Skip to content

Commit 7a23ce6

Browse files
committed
Find python files in project using new list_project_files_by_lang action instead of rglobbing. Fix repeating lint messages in IDE (cached result of first handler was modified without copying). Restructure WM services to avoid cycle imports.
1 parent 82a666e commit 7a23ce6

Some content is hidden

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

53 files changed

+1208
-918
lines changed

extensions/fine_python_package_info/README.md

Whitespace-only changes.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from .list_project_files_by_lang_python import ListProjectFilesByLangPythonHandler
2+
from .py_package_layout_info_provider import PyPackageLayoutInfoProvider
3+
4+
__all__ = [
5+
"ListProjectFilesByLangPythonHandler",
6+
"PyPackageLayoutInfoProvider"
7+
]
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
from finecode_extension_api.interfaces import iprojectinfoprovider, ipypackagelayoutinfoprovider
2+
import dataclasses
3+
import pathlib
4+
5+
from finecode_extension_api import code_action
6+
from finecode_extension_api.actions import list_project_files_by_lang as list_project_files_by_lang_action
7+
8+
9+
@dataclasses.dataclass
10+
class ListProjectFilesByLangPythonHandlerConfig(code_action.ActionHandlerConfig): ...
11+
# TODO: parameter for additional dirs
12+
13+
14+
class ListProjectFilesByLangPythonHandler(
15+
code_action.ActionHandler[
16+
list_project_files_by_lang_action.ListProjectFilesByLangAction, ListProjectFilesByLangPythonHandlerConfig
17+
]
18+
):
19+
def __init__(self, project_info_provider: iprojectinfoprovider.IProjectInfoProvider, py_package_layout_info_provider: ipypackagelayoutinfoprovider.IPyPackageLayoutInfoProvider) -> None:
20+
self.project_info_provider = project_info_provider
21+
self.py_package_layout_info_provider = py_package_layout_info_provider
22+
23+
self.current_project_dir_path = self.project_info_provider.get_current_project_dir_path()
24+
self.tests_dir_path = self.current_project_dir_path / 'tests'
25+
self.scripts_dir_path = self.current_project_dir_path / 'scripts'
26+
self.setup_py_path = self.current_project_dir_path / 'setup.py'
27+
28+
async def run(
29+
self,
30+
payload: list_project_files_by_lang_action.ListProjectFilesByLangRunPayload,
31+
run_context: list_project_files_by_lang_action.ListProjectFilesByLangRunContext,
32+
) -> list_project_files_by_lang_action.ListProjectFilesByLangRunResult:
33+
py_files: list[pathlib.Path] = []
34+
project_package_src_root_dir_path = await self.py_package_layout_info_provider.get_package_src_root_dir_path(package_dir_path=self.current_project_dir_path)
35+
py_files += list(project_package_src_root_dir_path.rglob('*.py'))
36+
37+
if self.scripts_dir_path.exists():
38+
py_files += list(self.scripts_dir_path.rglob('*.py'))
39+
40+
if self.tests_dir_path.exists():
41+
py_files += list(self.tests_dir_path.rglob('*.py'))
42+
43+
if self.setup_py_path.exists():
44+
py_files.append(self.setup_py_path)
45+
46+
return list_project_files_by_lang_action.ListProjectFilesByLangRunResult(
47+
files_by_lang={"python": py_files}
48+
)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import enum
2+
import pathlib
3+
4+
import tomlkit
5+
6+
from finecode_extension_api.interfaces import ifilemanager, ipypackagelayoutinfoprovider
7+
from finecode_extension_api import service
8+
9+
10+
class PyPackageLayoutInfoProvider(ipypackagelayoutinfoprovider.IPyPackageLayoutInfoProvider, service.Service):
11+
def __init__(self, file_manager: ifilemanager.IFileManager) -> None:
12+
self.file_manager = file_manager
13+
# TODO: cache package name by file version?
14+
15+
async def _get_package_name(self, package_dir_path: pathlib.Path) -> str:
16+
package_def_file = package_dir_path / 'pyproject.toml'
17+
if not package_def_file.exists():
18+
raise NotImplementedError("Only python packages with pyproject.toml config file are supported")
19+
20+
package_def_file_content = await self.file_manager.get_content(file_path=package_def_file)
21+
# TODO: handle errors
22+
package_def_dict = tomlkit.loads(package_def_file_content)
23+
package_raw_name = package_def_dict.get('project', {}).get('name', None)
24+
if package_raw_name is None:
25+
raise ValueError(f"package.name not found in {package_def_file}")
26+
27+
return package_raw_name.replace('-', '_')
28+
29+
async def get_package_layout(self, package_dir_path: pathlib.Path) -> ipypackagelayoutinfoprovider.PyPackageLayout:
30+
if (package_dir_path / 'src').exists():
31+
return ipypackagelayoutinfoprovider.PyPackageLayout.SRC
32+
else:
33+
package_name = await self._get_package_name(package_dir_path=package_dir_path)
34+
if (package_dir_path / package_name).exists():
35+
return ipypackagelayoutinfoprovider.PyPackageLayout.FLAT
36+
else:
37+
return ipypackagelayoutinfoprovider.PyPackageLayout.CUSTOM
38+
39+
async def get_package_src_root_dir_path(self, package_dir_path: str) -> pathlib.Path:
40+
package_layout = await self.get_package_layout(package_dir_path=package_dir_path)
41+
package_name = await self._get_package_name(package_dir_path=package_dir_path)
42+
if package_layout == ipypackagelayoutinfoprovider.PyPackageLayout.SRC:
43+
return package_dir_path / 'src' / package_name
44+
elif package_layout == ipypackagelayoutinfoprovider.PyPackageLayout.FLAT:
45+
return package_dir_path / package_name
46+
else:
47+
raise NotImplementedError(f"Custom python package layout in {package_dir_path} is not supported")
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[project]
2+
name = "fine_python_package_info"
3+
version = "0.1.0"
4+
description = ""
5+
authors = [{ name = "Vladyslav Hnatiuk", email = "[email protected]" }]
6+
readme = "README.md"
7+
requires-python = ">=3.11, < 3.14"
8+
dependencies = ["finecode_extension_api==0.3.*", "tomlkit==0.11.*"]
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import atexit
2+
import shutil
3+
import sys
4+
import tempfile
5+
6+
from setuptools import setup
7+
from setuptools.command.build import build
8+
from setuptools.command.build_ext import build_ext
9+
from setuptools.command.build_py import build_py
10+
from setuptools.command.egg_info import egg_info
11+
12+
# Create a single temp directory for all build operations
13+
_TEMP_BUILD_DIR = None
14+
15+
16+
def get_temp_build_dir(pkg_name):
17+
global _TEMP_BUILD_DIR
18+
if _TEMP_BUILD_DIR is None:
19+
_TEMP_BUILD_DIR = tempfile.mkdtemp(prefix=f"{pkg_name}_build_")
20+
atexit.register(lambda: shutil.rmtree(_TEMP_BUILD_DIR, ignore_errors=True))
21+
return _TEMP_BUILD_DIR
22+
23+
24+
class TempDirBuildMixin:
25+
def initialize_options(self):
26+
super().initialize_options()
27+
temp_dir = get_temp_build_dir(self.distribution.get_name())
28+
self.build_base = temp_dir
29+
30+
31+
class TempDirEggInfoMixin:
32+
def initialize_options(self):
33+
super().initialize_options()
34+
temp_dir = get_temp_build_dir(self.distribution.get_name())
35+
self.egg_base = temp_dir
36+
37+
38+
class CustomBuild(TempDirBuildMixin, build):
39+
pass
40+
41+
42+
class CustomBuildPy(TempDirBuildMixin, build_py):
43+
pass
44+
45+
46+
class CustomBuildExt(TempDirBuildMixin, build_ext):
47+
pass
48+
49+
50+
class CustomEggInfo(TempDirEggInfoMixin, egg_info):
51+
def initialize_options(self):
52+
# Don't use temp dir for editable installs
53+
if "--editable" in sys.argv or "-e" in sys.argv:
54+
egg_info.initialize_options(self)
55+
else:
56+
super().initialize_options()
57+
58+
59+
setup(
60+
name="fine_python_package_info",
61+
cmdclass={
62+
"build": CustomBuild,
63+
"build_py": CustomBuildPy,
64+
"build_ext": CustomBuildExt,
65+
"egg_info": CustomEggInfo,
66+
},
67+
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Tests for fine_python_package_info extension

extensions/fine_python_pip/setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from setuptools.command.build_py import build_py
1010
from setuptools.command.egg_info import egg_info
1111

12+
1213
# Create a single temp directory for all build operations
1314
_TEMP_BUILD_DIR = None
1415

extensions/fine_python_ruff/fine_python_ruff/format_handler.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ def __init__(
3737
command_runner: icommandrunner.ICommandRunner,
3838
) -> None:
3939
self.config = config
40-
self.context = context
4140
self.logger = logger
4241
self.cache = cache
4342
self.command_runner = command_runner

finecode_builtin_handlers/src/finecode_builtin_handlers/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@
1616
"PrepareRunnersInstallRunnerAndPresetsHandler",
1717
"PrepareRunnersReadConfigsHandler",
1818
"DumpConfigSaveHandler",
19-
]
19+
]

0 commit comments

Comments
 (0)