|
3 | 3 |
|
4 | 4 | import tomlkit |
5 | 5 |
|
6 | | -from finecode_extension_api.interfaces import ifilemanager, ipypackagelayoutinfoprovider |
| 6 | +from finecode_extension_api.interfaces import ifilemanager, ipypackagelayoutinfoprovider, icache |
7 | 7 | from finecode_extension_api import service |
8 | 8 |
|
9 | 9 |
|
| 10 | +class ConfigParseError(Exception): |
| 11 | + def __init__(self, message: str) -> None: |
| 12 | + self.message = message |
| 13 | + |
| 14 | + |
10 | 15 | class PyPackageLayoutInfoProvider(ipypackagelayoutinfoprovider.IPyPackageLayoutInfoProvider, service.Service): |
11 | | - def __init__(self, file_manager: ifilemanager.IFileManager) -> None: |
| 16 | + PACKAGE_NAME_CACHE_KEY = 'PyPackageLayoutInfoProviderPackageName' |
| 17 | + |
| 18 | + def __init__(self, file_manager: ifilemanager.IFileManager, cache: icache.ICache) -> None: |
12 | 19 | self.file_manager = file_manager |
13 | | - # TODO: cache package name by file version? |
| 20 | + self.cache = cache |
14 | 21 |
|
15 | 22 | async def _get_package_name(self, package_dir_path: pathlib.Path) -> str: |
| 23 | + # raises ConfigParseError |
16 | 24 | package_def_file = package_dir_path / 'pyproject.toml' |
17 | 25 | if not package_def_file.exists(): |
18 | 26 | raise NotImplementedError("Only python packages with pyproject.toml config file are supported") |
19 | 27 |
|
| 28 | + try: |
| 29 | + cached_package_name = await self.cache.get_file_cache(file_path=package_def_file, key=self.PACKAGE_NAME_CACHE_KEY) |
| 30 | + return cached_package_name |
| 31 | + except icache.CacheMissException: |
| 32 | + ... |
| 33 | + |
20 | 34 | 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) |
| 35 | + package_def_file_version = await self.file_manager.get_file_version(file_path=package_def_file) |
| 36 | + try: |
| 37 | + package_def_dict = tomlkit.loads(package_def_file_content) |
| 38 | + except tomlkit.exceptions.ParseError as exception: |
| 39 | + raise ConfigParseError(f"Failed to parse package config {package_def_file}: {exception.message} at {exception.line}:{exception.col}") |
| 40 | + |
23 | 41 | package_raw_name = package_def_dict.get('project', {}).get('name', None) |
24 | 42 | if package_raw_name is None: |
25 | 43 | raise ValueError(f"package.name not found in {package_def_file}") |
26 | 44 |
|
27 | | - return package_raw_name.replace('-', '_') |
| 45 | + package_name = package_raw_name.replace('-', '_') |
| 46 | + await self.cache.save_file_cache(file_path=package_def_file, file_version=package_def_file_version, key=self.PACKAGE_NAME_CACHE_KEY, value=package_name) |
| 47 | + return package_name |
28 | 48 |
|
29 | 49 | async def get_package_layout(self, package_dir_path: pathlib.Path) -> ipypackagelayoutinfoprovider.PyPackageLayout: |
30 | 50 | if (package_dir_path / 'src').exists(): |
31 | 51 | return ipypackagelayoutinfoprovider.PyPackageLayout.SRC |
32 | 52 | else: |
33 | | - package_name = await self._get_package_name(package_dir_path=package_dir_path) |
| 53 | + try: |
| 54 | + package_name = await self._get_package_name(package_dir_path=package_dir_path) |
| 55 | + except ConfigParseError as exception: |
| 56 | + raise ipypackagelayoutinfoprovider.FailedToGetPackageLayout(exception.message) |
| 57 | + |
34 | 58 | if (package_dir_path / package_name).exists(): |
35 | 59 | return ipypackagelayoutinfoprovider.PyPackageLayout.FLAT |
36 | 60 | else: |
37 | 61 | return ipypackagelayoutinfoprovider.PyPackageLayout.CUSTOM |
38 | 62 |
|
39 | 63 | 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) |
| 64 | + try: |
| 65 | + package_layout = await self.get_package_layout(package_dir_path=package_dir_path) |
| 66 | + except ipypackagelayoutinfoprovider.FailedToGetPackageLayout as exception: |
| 67 | + raise ipypackagelayoutinfoprovider.FailedToGetPackageSrcRootDirPath(exception.message) |
| 68 | + |
| 69 | + try: |
| 70 | + package_name = await self._get_package_name(package_dir_path=package_dir_path) |
| 71 | + except ConfigParseError as exception: |
| 72 | + raise ipypackagelayoutinfoprovider.FailedToGetPackageSrcRootDirPath(exception.message) |
| 73 | + |
42 | 74 | if package_layout == ipypackagelayoutinfoprovider.PyPackageLayout.SRC: |
43 | 75 | return package_dir_path / 'src' / package_name |
44 | 76 | elif package_layout == ipypackagelayoutinfoprovider.PyPackageLayout.FLAT: |
|
0 commit comments