Skip to content

Commit 8a96371

Browse files
committed
Fix typing of action runner. Add 'build artifact action'. Move 'FormatFilesSave' handler in builtin handlers. Add 'get_actions_by_source' and 'get_actions_for_language' methods in IActionRunner. Add 'current_result' in RunActionContext. Improve terms: declaration and definiton of action and handlers.
1 parent cfc79a6 commit 8a96371

49 files changed

Lines changed: 687 additions & 195 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.vscode/tasks.json

Lines changed: 0 additions & 18 deletions
This file was deleted.

extensions/fine_python_flake8/fine_python_flake8/action.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ async def run_on_single_file(
188188
async def run(
189189
self,
190190
payload: lint_files_action.LintFilesRunPayload,
191-
run_context: code_action.RunActionWithPartialResultsContext,
191+
run_context: lint_files_action.LintFilesRunContext,
192192
) -> None:
193193
if self.config.select is not None and len(self.config.select) == 0:
194194
# empty set of rules is selected, no need to run flake8

extensions/fine_python_mypy/fine_python_mypy/action.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ async def _run_dmypy_on_project(
195195
async def run(
196196
self,
197197
payload: lint_action.LintRunPayload,
198-
run_context: code_action.RunActionWithPartialResultsContext,
198+
run_context: lint_action.LintRunContext,
199199
) -> None:
200200
file_paths = [file_path async for file_path in payload]
201201

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import dataclasses
2+
3+
from finecode_extension_api import code_action
4+
from finecode_extension_api.actions import build_artifact_action
5+
from finecode_extension_api.interfaces import (
6+
icommandrunner,
7+
iextensionrunnerinfoprovider,
8+
ilogger,
9+
iprojectinfoprovider,
10+
)
11+
12+
13+
@dataclasses.dataclass
14+
class BuildArtifactPyHandlerConfig(code_action.ActionHandlerConfig): ...
15+
16+
17+
class BuildArtifactPyHandler(
18+
code_action.ActionHandler[
19+
build_artifact_action.BuildArtifactAction,
20+
BuildArtifactPyHandlerConfig,
21+
]
22+
):
23+
def __init__(
24+
self,
25+
config: BuildArtifactPyHandlerConfig,
26+
command_runner: icommandrunner.ICommandRunner,
27+
project_info_provider: iprojectinfoprovider.IProjectInfoProvider,
28+
extension_runner_info_provider: iextensionrunnerinfoprovider.IExtensionRunnerInfoProvider,
29+
logger: ilogger.ILogger,
30+
) -> None:
31+
self.config = config
32+
self.command_runner = command_runner
33+
self.project_info_provider = project_info_provider
34+
self.extension_runner_info_provider = extension_runner_info_provider
35+
self.logger = logger
36+
37+
async def run(
38+
self,
39+
payload: build_artifact_action.BuildArtifactRunPayload,
40+
run_context: build_artifact_action.BuildArtifactRunContext,
41+
) -> build_artifact_action.BuildArtifactRunResult:
42+
# Use current project if src_artifact_def_path is not provided
43+
src_artifact_def_path = payload.src_artifact_def_path
44+
if src_artifact_def_path is None:
45+
src_artifact_def_path = (
46+
self.project_info_provider.get_current_project_def_path()
47+
)
48+
49+
# Get the project directory (parent of pyproject.toml)
50+
project_dir = src_artifact_def_path.parent
51+
52+
self.logger.info(f"Building artifact in {project_dir}")
53+
54+
# Get the python interpreter from the current venv
55+
venv_dir = self.extension_runner_info_provider.get_current_venv_dir_path()
56+
python_path = self.extension_runner_info_provider.get_venv_python_interpreter(
57+
venv_dir
58+
)
59+
60+
# Run python -m build
61+
process = await self.command_runner.run(
62+
cmd=f"{python_path} -m build",
63+
cwd=project_dir,
64+
)
65+
await process.wait_for_end()
66+
67+
exit_code = process.get_exit_code()
68+
if exit_code != 0:
69+
error_output = process.get_error_output()
70+
raise code_action.ActionFailedException(
71+
f"Build failed with exit code {exit_code}: {error_output}"
72+
)
73+
74+
# Parse the build output to get the produced file names
75+
# Example line: "Successfully built pkg-1.0.tar.gz and pkg-1.0-py3-none-any.whl"
76+
dist_dir = project_dir / "dist"
77+
build_output_paths = []
78+
79+
output = process.get_output()
80+
for line in output.splitlines():
81+
if line.startswith("Successfully built "):
82+
files_part = line[len("Successfully built ") :]
83+
file_names = [f.strip() for f in files_part.split(" and ")]
84+
build_output_paths = [dist_dir / name for name in file_names]
85+
break
86+
87+
if not build_output_paths:
88+
# Fallback: return the dist directory if parsing failed
89+
build_output_paths = [dist_dir]
90+
91+
self.logger.info(f"Build completed. Output: {build_output_paths}")
92+
93+
return build_artifact_action.BuildArtifactRunResult(
94+
build_output_paths=build_output_paths
95+
)

extensions/fine_python_package_info/fine_python_package_info/is_artifact_published_to_registry_py_handler.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ async def run(
6565

6666
# Get registries using the action
6767
get_registries_action = self.action_runner.get_action_by_name(
68-
"get_src_artifact_registries"
68+
"get_src_artifact_registries", get_src_artifact_registries_action.GetSrcArtifactRegistriesAction
6969
)
7070
registries_payload = (
7171
get_src_artifact_registries_action.GetSrcArtifactRegistriesRunPayload(
@@ -127,7 +127,7 @@ async def run(
127127
except KeyError as exception:
128128
raise code_action.ActionFailedException("File object has no 'filename' key") from exception
129129

130-
is_published_by_dist_path = {dist_path: dist_path in published_file_names for dist_path in dist_artifact_paths}
130+
is_published_by_dist_path = {dist_path: dist_path.name in published_file_names for dist_path in dist_artifact_paths}
131131
else:
132132
is_published_by_dist_path = {dist_path: False for dist_path in dist_artifact_paths}
133133

extensions/fine_python_package_info/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ dependencies = [
99
"finecode_extension_api~=0.4.0a0",
1010
"tomlkit==0.11.*",
1111
"twine==6.2.*",
12+
"build==1.4.*",
1213
]
1314

1415
[dependency-groups]

extensions/fine_python_pyrefly/fine_python_pyrefly/lint_files_handler.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ async def run_on_single_file(
8787
async def run(
8888
self,
8989
payload: lint_files_action.LintFilesRunPayload,
90-
run_context: code_action.RunActionWithPartialResultsContext,
90+
run_context: lint_files_action.LintFilesRunContext,
9191
) -> None:
9292
file_paths = [file_path async for file_path in payload]
9393

extensions/fine_python_ruff/fine_python_ruff/lint_files_handler.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ async def run_on_single_file(
8080
async def run(
8181
self,
8282
payload: lint_files_action.LintFilesRunPayload,
83-
run_context: code_action.RunActionWithPartialResultsContext,
83+
run_context: lint_files_action.LintFilesRunContext,
8484
) -> None:
8585
file_paths = [file_path async for file_path in payload]
8686

finecode_builtin_handlers/src/finecode_builtin_handlers/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from .dump_config import DumpConfigHandler
55
from .dump_config_save import DumpConfigSaveHandler
66
from .format import FormatHandler
7+
from .format_files_save_handler import SaveFormatFilesHandler
78
from .lint import LintHandler
89
from .prepare_envs_install_deps import PrepareEnvsInstallDepsHandler
910
from .prepare_envs_read_configs import PrepareEnvsReadConfigsHandler
@@ -24,4 +25,5 @@
2425
"PrepareRunnersReadConfigsHandler",
2526
"DumpConfigSaveHandler",
2627
"PublishArtifactHandler",
28+
"SaveFormatFilesHandler"
2729
]

finecode_builtin_handlers/src/finecode_builtin_handlers/format.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ async def run(
7373
# or e.g. files changed according to git + dependencies.
7474
files_to_format: list[pathlib.Path] = self.file_editor.get_opened_files()
7575
group_project_files_action = self.action_runner.get_action_by_name(
76-
"group_src_artifact_files_by_lang"
76+
"group_src_artifact_files_by_lang", group_src_artifact_files_by_lang_action.GroupSrcArtifactFilesByLangAction
7777
)
7878
group_src_artifact_files_by_lang_payload = group_src_artifact_files_by_lang_action.GroupSrcArtifactFilesByLangRunPayload(
7979
file_paths=files_to_format, langs=langs_supported_by_format
@@ -90,7 +90,7 @@ async def run(
9090
# language, use `list_src_artifact_files_by_lang_action` action which returns
9191
# only files with supported languages
9292
list_src_artifact_file_by_lang_action_instance = (
93-
self.action_runner.get_action_by_name("list_src_artifact_files_by_lang")
93+
self.action_runner.get_action_by_name("list_src_artifact_files_by_lang", list_src_artifact_files_by_lang_action.ListSrcArtifactFilesByLangAction)
9494
)
9595
list_src_artifact_files_by_lang_payload = (
9696
list_src_artifact_files_by_lang_action.ListSrcArtifactFilesByLangRunPayload(
@@ -108,7 +108,7 @@ async def run(
108108
# format target are files, format them
109109
files_to_format = payload.file_paths
110110
group_src_artifact_files_by_lang_action_instance = (
111-
self.action_runner.get_action_by_name("group_src_artifact_files_by_lang")
111+
self.action_runner.get_action_by_name("group_src_artifact_files_by_lang", group_src_artifact_files_by_lang_action.GroupSrcArtifactFilesByLangAction)
112112
)
113113
group_src_artifact_files_by_lang_payload = (
114114
group_src_artifact_files_by_lang_action.GroupSrcArtifactFilesByLangRunPayload(
@@ -130,7 +130,7 @@ async def run(
130130
# TODO: handle errors
131131
# TODO: handle KeyError?
132132
action = self.action_runner.get_action_by_name(
133-
format_files_prefix + lang
133+
format_files_prefix + lang, format_files_action.FormatFilesAction
134134
)
135135
format_files_payload = format_files_action.FormatFilesRunPayload(
136136
file_paths=lang_files, save=payload.save

0 commit comments

Comments
 (0)