Skip to content

Commit ca9be7a

Browse files
Rework config loader, update project
1 parent 7f86299 commit ca9be7a

20 files changed

Lines changed: 265 additions & 157 deletions

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ on:
1414

1515
jobs:
1616
call_ci:
17-
uses: EffectiveRange/ci-workflows/.github/workflows/python-ci.yaml@v5
17+
uses: EffectiveRange/ci-workflows/.github/workflows/python-ci.yaml@latest-python

.vscode/launch.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"version": "0.2.0",
3+
"configurations": [
4+
{
5+
"name": "Python Debugger: Current File",
6+
"type": "debugpy",
7+
"request": "launch",
8+
"program": "${file}",
9+
"args": [
10+
"--backend=scipy"
11+
],
12+
"console": "integratedTerminal"
13+
}
14+
]
15+
}

.vscode/settings.json

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,20 @@
11
{
2-
"editor.rulers": [
3-
120
4-
],
5-
"[python]": {
6-
"editor.defaultFormatter": "ms-python.black-formatter",
7-
"editor.formatOnSave": true
8-
},
9-
"black-formatter.args": [
10-
"--skip-string-normalization",
11-
"--line-length",
12-
"120"
13-
],
14-
"python.testing.unittestArgs": [
15-
"-v",
16-
"-s",
17-
"./tests",
18-
"-p",
19-
"*test.py"
20-
],
21-
"python.testing.pytestEnabled": false,
22-
"python.testing.unittestEnabled": true
2+
"python.venvPath": "${workspaceFolder}/.venv",
3+
"python.testing.unittestArgs": [
4+
"-v",
5+
"-s",
6+
"./tests",
7+
"-p",
8+
"*test.py"
9+
],
10+
"python.testing.pytestEnabled": true,
11+
"python.testing.unittestEnabled": false,
12+
"black-formatter.interpreter": [
13+
"${workspaceFolder}/.venv/bin/python3"
14+
],
15+
"black-formatter.args": [
16+
"--config=setup.cfg"
17+
],
18+
"python.analysis.typeCheckingMode": "standard",
19+
"python.testing.pytestArgs": []
2320
}

.vscode/tasks.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"version": "2.0.0",
3+
"tasks": [
4+
{
5+
"label": "Create Python venv",
6+
"type": "shell",
7+
"command": "if [ -d /var/chroot/buildroot ];then dpkgdeps -v --arch $(grep TARGET_ARCH /home/crossbuilder/target/target | cut -d'=' -f2 | tr -d \\') .;else dpkgdeps -v .;fi && rm -rf .venv && python3 -m venv --system-site-packages .venv && .venv/bin/pip install -e . && .venv/bin/python3 -m mypy --non-interactive --install-types && .venv/bin/pip install pytest-cov || true",
8+
"group": "build",
9+
"detail": "Creates a Python virtual environment in the .venv folder",
10+
"problemMatcher": [
11+
"$eslint-compact"
12+
]
13+
}
14+
]
15+
}

common_utility/configLoader.py

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
# SPDX-License-Identifier: MIT
44

55
import os
6-
import shutil
76
from configparser import ConfigParser
87
from pathlib import Path
98
from typing import Any
109

1110
from context_logger import get_logger
1211

12+
from common_utility import copy_file
13+
1314
log = get_logger('ConfigLoader')
1415

1516

@@ -21,29 +22,37 @@ def load(self, arguments: dict[str, Any]) -> dict[str, Any]:
2122

2223
class ConfigLoader(IConfigLoader):
2324

24-
def __init__(self, resource_root: str, default_config: str, config_file_argument: str = 'config_file') -> None:
25-
self._resource_root = resource_root
26-
self._default_config = f'{self._resource_root}/{default_config}'
25+
def __init__(self, default_config_file: Path, config_file_argument: str = 'config_file') -> None:
26+
self._default_config_file = default_config_file
2727
self._config_file_argument = config_file_argument
2828

2929
def load(self, arguments: dict[str, Any]) -> dict[str, Any]:
30-
config_file = Path(arguments[self._config_file_argument])
30+
parser = ConfigParser(interpolation=None)
3131

32-
if not os.path.exists(config_file):
33-
log.info('Loading default configuration file', config_file=self._default_config)
34-
config_file.parent.mkdir(parents=True, exist_ok=True)
35-
shutil.copyfile(self._default_config, config_file)
36-
else:
37-
log.info('Using configuration file', config_file=str(config_file))
32+
log.info('Loading default configuration', config_file=str(self._default_config_file))
33+
parser.read(self._default_config_file)
3834

39-
parser = ConfigParser(interpolation=None)
40-
parser.read(config_file)
35+
if config_file := arguments.get(self._config_file_argument):
36+
custom_config_file = Path(config_file)
37+
38+
if os.path.exists(custom_config_file):
39+
log.info('Loading custom configuration', config_file=str(custom_config_file))
40+
parser.read(custom_config_file)
41+
else:
42+
try:
43+
log.info('Creating custom configuration using default', config_file=str(custom_config_file))
44+
copy_file(self._default_config_file, custom_config_file)
45+
except Exception as exception:
46+
log.warn('Failed to create custom configuration file', error=str(exception))
4147

4248
configuration = {}
4349

4450
for section in parser.sections():
4551
configuration.update(dict(parser[section]))
4652

53+
log.info('Loading command line arguments', arguments=arguments)
4754
configuration.update(arguments)
4855

56+
log.info('Configuration loaded', configuration=configuration)
57+
4958
return configuration

common_utility/fileDownloader.py

Lines changed: 24 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
# SPDX-License-Identifier: MIT
44

55
import os
6-
from typing import Optional
6+
from pathlib import Path
7+
from typing import Optional, Union
78
from urllib.parse import urlparse
89

910
from context_logger import get_logger
@@ -16,44 +17,26 @@
1617

1718
class IFileDownloader(object):
1819

19-
def download(
20-
self,
21-
file_url: str,
22-
file_name: Optional[str] = None,
23-
sub_dir: Optional[str] = None,
24-
headers: Optional[dict[str, str]] = None,
25-
skip_if_exists: bool = True,
26-
chunk_size: int = 1000 * 1000,
27-
) -> str:
20+
def download(self, file_url: str, file_name: Optional[str] = None, sub_dir: Optional[Union[str, Path]] = None,
21+
headers: Optional[dict[str, str]] = None, skip_if_exists: bool = True, chunk_size: int = 1000 * 1000
22+
) -> Path:
2823
raise NotImplementedError()
2924

30-
def download_and_copy(
31-
self,
32-
file_url: str,
33-
sub_dirs: list[str],
34-
file_name: Optional[str] = None,
35-
headers: Optional[dict[str, str]] = None,
36-
skip_if_exists: bool = True,
37-
chunk_size: int = 1000 * 1000,
38-
) -> list[str]:
25+
def download_and_copy(self, file_url: str, sub_dirs: list[Union[str, Path]], file_name: Optional[str] = None,
26+
headers: Optional[dict[str, str]] = None, skip_if_exists: bool = True,
27+
chunk_size: int = 1000 * 1000) -> list[Path]:
3928
raise NotImplementedError()
4029

4130

4231
class FileDownloader(IFileDownloader):
4332

44-
def __init__(self, session_provider: ISessionProvider, download_location: str) -> None:
33+
def __init__(self, session_provider: ISessionProvider, download_location: Path) -> None:
4534
self._session_provider = session_provider
4635
self._download_location = download_location
4736

48-
def download(
49-
self,
50-
file_url: str,
51-
file_name: Optional[str] = None,
52-
sub_dir: Optional[str] = None,
53-
headers: Optional[dict[str, str]] = None,
54-
skip_if_exists: bool = True,
55-
chunk_size: int = 1000 * 1000,
56-
) -> str:
37+
def download(self, file_url: str, file_name: Optional[str] = None, sub_dir: Optional[Union[str, Path]] = None,
38+
headers: Optional[dict[str, str]] = None, skip_if_exists: bool = True, chunk_size: int = 1000 * 1000
39+
) -> Path:
5740
if not urlparse(file_url).scheme:
5841
return self._check_local_file(file_url)
5942

@@ -75,15 +58,9 @@ def download(
7558

7659
return file_path
7760

78-
def download_and_copy(
79-
self,
80-
file_url: str,
81-
sub_dirs: list[str],
82-
file_name: Optional[str] = None,
83-
headers: Optional[dict[str, str]] = None,
84-
skip_if_exists: bool = True,
85-
chunk_size: int = 1000 * 1000,
86-
) -> list[str]:
61+
def download_and_copy(self, file_url: str, sub_dirs: list[Union[str, Path]], file_name: Optional[str] = None,
62+
headers: Optional[dict[str, str]] = None, skip_if_exists: bool = True,
63+
chunk_size: int = 1000 * 1000) -> list[Path]:
8764
if not sub_dirs:
8865
raise ValueError('At least one sub directory must be provided')
8966

@@ -102,11 +79,11 @@ def download_and_copy(
10279

10380
return downloaded_files
10481

105-
def _check_local_file(self, file_url: str) -> str:
82+
def _check_local_file(self, file_url: str) -> Path:
10683
file_path = os.path.abspath(file_url)
10784
if os.path.isfile(file_path):
10885
log.info('Local file path provided, skipping download', file=file_path)
109-
return file_path
86+
return Path(file_path)
11087
else:
11188
log.error('Local file does not exist', file=file_path)
11289
raise ValueError('Local file does not exist')
@@ -121,21 +98,21 @@ def _send_request(self, file_url: str, headers: dict[str, str]) -> Response:
12198

12299
return response
123100

124-
def _get_target_path(self, file_url: str, file_name: Optional[str], sub_dir: Optional[str] = None) -> str:
125-
if not file_name and '/' in file_url:
101+
def _get_target_path(self, file_url: str, file_name: Optional[str],
102+
sub_dir: Optional[Union[str, Path]] = None) -> Path:
103+
if not file_name:
126104
file_name = file_url.split('/')[-1]
127105

128106
download_dir = self._download_location
129107

130108
if sub_dir:
131-
download_dir += f'/{sub_dir}'
109+
download_dir = download_dir / sub_dir
132110
create_directory(download_dir)
133111

134-
return f'{download_dir}/{file_name}'
112+
return download_dir / file_name
135113

136-
def _download_file(self, response: Response, file_path: str, chunk_size: int) -> None:
137-
if not os.path.exists(self._download_location):
138-
os.makedirs(self._download_location)
114+
def _download_file(self, response: Response, file_path: Path, chunk_size: int) -> None:
115+
create_directory(self._download_location)
139116

140117
with open(file_path, 'wb') as asset_file:
141118
for chunk in response.iter_content(chunk_size):

common_utility/fileUtility.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,54 +6,55 @@
66
import re
77
import shutil
88
from os.path import exists
9-
from typing import Any
9+
from pathlib import Path
10+
from typing import Any, Union
1011

1112
from jinja2 import Environment, FileSystemLoader
1213

1314

14-
def create_directory(directory: str) -> None:
15+
def create_directory(directory: Union[str, Path]) -> None:
1516
if not os.path.isdir(directory):
1617
os.makedirs(directory, exist_ok=True)
1718

1819

19-
def delete_directory(directory: str) -> None:
20+
def delete_directory(directory: Union[str, Path]) -> None:
2021
if os.path.isdir(directory):
2122
shutil.rmtree(directory)
2223

2324

24-
def create_file(file_path: str, content: str = '\n') -> None:
25+
def create_file(file_path: Union[str, Path], content: str = '\n') -> None:
2526
create_directory(os.path.dirname(file_path))
2627
with open(file_path, 'w') as f:
2728
f.write(content)
2829

2930

30-
def copy_file(source: str, destination: str) -> None:
31+
def copy_file(source: Union[str, Path], destination: Union[str, Path]) -> None:
3132
create_directory(os.path.dirname(destination))
3233
shutil.copy(source, destination)
3334

3435

35-
def append_file(file_path: str, line: str) -> None:
36+
def append_file(file_path: Union[str, Path], line: str) -> None:
3637
with open(file_path, 'a+') as file:
3738
file.writelines([f'{line}\n'])
3839

3940

40-
def delete_file(file_path: str) -> None:
41+
def delete_file(file_path: Union[str, Path]) -> None:
4142
if exists(file_path):
4243
if os.path.islink(file_path):
4344
os.unlink(file_path)
4445
else:
4546
os.remove(file_path)
4647

4748

48-
def is_file_matches_pattern(file_path: str, pattern: str) -> bool:
49+
def is_file_matches_pattern(file_path: Union[str, Path], pattern: str) -> bool:
4950
if not exists(file_path):
5051
return False
5152

5253
with open(file_path) as file:
5354
return re.search(pattern, file.read(), re.MULTILINE) is not None
5455

5556

56-
def is_file_contains_lines(file: str, expected_lines: list[str]) -> bool:
57+
def is_file_contains_lines(file: Union[str, Path], expected_lines: list[str]) -> bool:
5758
if not exists(file):
5859
return False
5960

@@ -65,14 +66,13 @@ def is_file_contains_lines(file: str, expected_lines: list[str]) -> bool:
6566
return file_lines_set == expected_lines_set
6667

6768

68-
def render_template_file(resource_root: str, template_file: str, context: dict[str, Any]) -> str:
69-
template_path = f'{resource_root}/{template_file}'
70-
environment = Environment(loader=FileSystemLoader(os.path.dirname(template_path)))
71-
template = environment.get_template(os.path.basename(template_path))
69+
def render_template_file(template_file: Union[str, Path], context: dict[str, Any]) -> str:
70+
environment = Environment(loader=FileSystemLoader(os.path.dirname(template_file)))
71+
template = environment.get_template(os.path.basename(template_file))
7272
return f'{template.render(context)}\n'
7373

7474

75-
def replace_in_file(file_path: str, pattern: str, replacement: str) -> None:
75+
def replace_in_file(file_path: Union[str, Path], pattern: str, replacement: str) -> None:
7676
if not exists(file_path):
7777
return
7878

0 commit comments

Comments
 (0)