Skip to content

Commit 7a43116

Browse files
committed
apply ruff suggestions
1 parent aa0fd77 commit 7a43116

1 file changed

Lines changed: 68 additions & 102 deletions

File tree

.dev/install.py

Lines changed: 68 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import sys as _sys
1616
import tempfile as _tempfile
1717
import xml.dom.minidom as _xml_minidom
18-
import xml.etree.ElementTree as _xml_ET
18+
import xml.etree.ElementTree as _ET # noqa: N814, ICN001
1919
from pathlib import Path as _Path
2020
from typing import TYPE_CHECKING as _TYPE_CHECKING
2121

@@ -86,8 +86,9 @@
8686
"""
8787

8888

89-
def run(
89+
def run( # noqa: PLR0913
9090
packages: Sequence[str | dict],
91+
*,
9192
python_version: str | None = None,
9293
build_platform: PlatformName | None = None,
9394
target_platform: PlatformName | None = None,
@@ -111,11 +112,19 @@ def run(
111112
indent_xml: int | None = 4,
112113
indent_yaml: int | None = 2,
113114
filepath: str | _Path = ".github/.repodynamics/metadata.json",
114-
):
115+
) -> tuple[dict[SourceName, list[dict]], dict[SourceName, str], dict[SourceName, str]]:
115116
"""Generate and/or install package dependencies based on the given configurations."""
116-
dependencies, files = get_dependencies(
117+
filepath = _Path(filepath).resolve()
118+
if not filepath.is_file():
119+
error_msg = f"Metadata file not found at '{filepath}'"
120+
raise FileNotFoundError(error_msg)
121+
try:
122+
data = _json.loads(filepath.read_text())
123+
except _json.JSONDecodeError as e:
124+
error_msg = f"Failed to load dependencies from '{filepath}'"
125+
raise ValueError(error_msg) from e
126+
dependencies, files = DependencyInstaller(data).run(
117127
packages=packages,
118-
filepath=filepath,
119128
python_version=python_version,
120129
build_platform=build_platform,
121130
target_platform=target_platform,
@@ -148,44 +157,6 @@ def run(
148157
return dependencies, files, paths
149158

150159

151-
def get_dependencies(
152-
packages: Sequence[str | dict],
153-
python_version: str | None = None,
154-
build_platform: PlatformName | None = None,
155-
target_platform: PlatformName | None = None,
156-
sources: Sequence[SourceName] | None = None,
157-
exclude_sources: Sequence[SourceName] | None = None,
158-
exclude_installed: bool = True,
159-
pip_in_conda: bool = True,
160-
conda_env_name: str | None = None,
161-
indent_json: int | None = 4,
162-
indent_xml: int | None = 4,
163-
indent_yaml: int | None = 2,
164-
filepath: str | _Path = ".github/.repodynamics/metadata.json",
165-
) -> tuple[dict[SourceName, list[dict]], dict[SourceName, str]]:
166-
filepath = _Path(filepath).resolve()
167-
if not filepath.is_file():
168-
raise FileNotFoundError(f"Metadata file not found at '{filepath}'")
169-
try:
170-
data = _json.loads(filepath.read_text())
171-
except _json.JSONDecodeError as e:
172-
raise ValueError(f"Failed to load dependencies from '{filepath}'") from e
173-
return DependencyInstaller(data).run(
174-
packages=packages,
175-
python_version=python_version,
176-
build_platform=build_platform,
177-
target_platform=target_platform,
178-
sources=sources,
179-
exclude_sources=exclude_sources,
180-
exclude_installed=exclude_installed,
181-
pip_in_conda=pip_in_conda,
182-
conda_env_name=conda_env_name,
183-
indent_json=indent_json,
184-
indent_xml=indent_xml,
185-
indent_yaml=indent_yaml,
186-
)
187-
188-
189160
def install_files(
190161
files: dict[SourceName, str],
191162
cmd_bash: Sequence[str] = ("bash", "{filepath}"),
@@ -214,29 +185,30 @@ def install_files(
214185
inputs = locals()
215186

216187
def _install(content: str, cmd: Sequence[str]):
217-
file = _tempfile.NamedTemporaryFile(mode="w", delete=False)
218-
file.write(content)
219-
filepath = file.name
220-
cmd_filled = [cmd_part.format(filepath=filepath) for cmd_part in cmd]
221-
try:
222-
_subprocess.run(cmd_filled, check=True)
223-
finally:
224-
_Path(filepath).unlink()
188+
with _tempfile.NamedTemporaryFile(mode="w", delete=False) as file:
189+
file.write(content)
190+
filepath = file.name
191+
cmd_filled = [cmd_part.format(filepath=filepath) for cmd_part in cmd]
192+
try:
193+
_subprocess.run(cmd_filled, check=True) # noqa: S603
194+
finally:
195+
_Path(filepath).unlink()
225196
return
226197

227198
for source in ("bash", "pwsh", "apt", "brew", "choco", "winget", "conda", "pip"):
228199
if source not in files:
229200
continue
230201
if source == "apt":
231-
_subprocess.run(list(cmd_apt) + files[source].splitlines(), check=True)
202+
_subprocess.run(list(cmd_apt) + files[source].splitlines(), check=True) # noqa: S603
232203
else:
233204
_install(files[source], inputs[f"cmd_{source}"])
234205
return
235206

236207

237-
def write_files(
208+
def write_files( # noqa: PLR0913
238209
files: dict[SourceName, str],
239210
output_dir: str | _Path,
211+
*,
240212
overwrite: bool = False,
241213
filename_conda: str = "environment.yml",
242214
filename_pip: str = "requirements.txt",
@@ -256,7 +228,8 @@ def _write_file(filename: str, dep_content: str):
256228
if not filepath.exists() or overwrite:
257229
filepath.write_text(dep_content)
258230
else:
259-
raise FileExistsError(f"File already exists: '{filepath}'")
231+
error_msg = f"File already exists: '{filepath}'"
232+
raise FileExistsError(error_msg)
260233
return
261234

262235
inputs = locals()
@@ -274,9 +247,10 @@ def __init__(self, package_data: dict):
274247
self._data = package_data
275248
return
276249

277-
def run(
250+
def run( # noqa: PLR0913
278251
self,
279252
packages: Sequence[str | dict],
253+
*,
280254
build_platform: PlatformName | None = None,
281255
target_platform: PlatformName | None = None,
282256
python_version: str | None = None,
@@ -376,14 +350,16 @@ def _resolve_python_version(packages: list[dict], python_version: str | None = N
376350
python_version = ".".join(_sys.version_info[:2])
377351
if python_version not in ("latest", "earliest"):
378352
if python_version not in common_python_versions:
379-
raise ValueError(f"Python version '{python_version}' is not supported.")
353+
error_msg = f"Python version '{python_version}' is not supported."
354+
raise ValueError(error_msg)
380355
return python_version
381356
python_versions = sorted(common_python_versions, key=lambda x: tuple(map(int, x.split("."))))
382357
return python_versions[-1] if python_version == "latest" else python_versions[0]
383358

384359

385-
def _resolve_dependencies(
360+
def _resolve_dependencies( # noqa: PLR0912
386361
pkg: dict,
362+
*,
387363
python_version: str,
388364
extras: Sequence[str] | Literal["all"] | None = "all",
389365
build_platform: PlatformName | None = None,
@@ -425,10 +401,6 @@ def _resolve_dependencies(
425401
Whether to exclude dependencies that are already installed.
426402
This is determined by running the validator script
427403
provided in the dependency data.
428-
429-
Returns
430-
-------
431-
432404
"""
433405
if not build_platform:
434406
build_platform = _get_native_platform()
@@ -463,8 +435,10 @@ def _resolve_dependencies(
463435
if selector and not _evaluate_selector(selector, selector_vars):
464436
continue
465437
if exclude_installed and dependency.get("validator"):
466-
validator_result = _subprocess.run(
467-
["python", "-c", dependency["validator"]], capture_output=True, check=False
438+
validator_result = _subprocess.run( # noqa: S603
439+
["python", "-c", dependency["validator"]], # noqa: S607
440+
capture_output=True,
441+
check=False,
468442
)
469443
if validator_result.returncode == 0:
470444
continue
@@ -473,10 +447,11 @@ def _resolve_dependencies(
473447
out.setdefault(source, []).append(dependency)
474448
break
475449
else:
476-
raise ValueError(
450+
error_msg = (
477451
f"Dependency '{dependency['name']}' not installable from any source. "
478452
f"Available sources are: {list(dependency['install'].keys())}"
479453
)
454+
raise ValueError(error_msg)
480455
return out
481456

482457

@@ -501,14 +476,15 @@ def _collect_dependencies(
501476
if extras != "all":
502477
for extra in extras:
503478
if extra not in optional_group_keys:
504-
raise ValueError(f"Invalid optional dependency group: {extra}")
505-
for group_key, group in data.get("optional", {}).items():
479+
error_msg = f"Invalid optional dependency group: {extra}"
480+
raise ValueError(error_msg)
481+
for group in data.get("optional", {}).values():
506482
if extras == "all" or group["name"] in extras:
507483
deps.extend(list(group["package"].values()))
508484
return _copy.deepcopy(deps)
509485

510486

511-
def _resolve_variants(
487+
def _resolve_variants( # noqa: PLR0912, C901
512488
pkg: dict, pyver: str, input_variants: dict[str, str | int | bool] | None = None
513489
) -> dict:
514490
"""Get a full set of variant values based on input variants and project variant data."""
@@ -519,9 +495,11 @@ def _resolve_variants(
519495
# Validate input variants
520496
for variant_key, variant_value in input_variants.items():
521497
if variant_key not in pkg_vars:
522-
raise ValueError(f"Invalid variant key '{variant_key}'")
498+
error_msg = f"Invalid variant key '{variant_key}'"
499+
raise ValueError(error_msg)
523500
if variant_value not in pkg_vars[variant_key]:
524-
raise ValueError(f"Invalid variant value '{variant_value}' for key '{variant_key}'")
501+
error_msg = f"Invalid variant value '{variant_value}' for key '{variant_key}'"
502+
raise ValueError(error_msg)
525503
for zip_keys in pkg_zip_keys:
526504
input_keys = []
527505
input_indices = []
@@ -530,9 +508,8 @@ def _resolve_variants(
530508
input_keys.append(zip_key)
531509
input_indices.append(pkg_vars[zip_key].index(input_variants[zip_key]))
532510
if len(input_indices) > 1 and len(set(input_indices)) != 1:
533-
raise ValueError(
534-
f"Variant keys '{input_keys}' must be zipped, but values correspond to indices {input_indices}"
535-
)
511+
error_msg = f"Variant keys '{input_keys}' must be zipped, but values correspond to indices {input_indices}"
512+
raise ValueError(error_msg)
536513
output = {}
537514
# Set the variant values
538515
for pkg_var_key, pkg_var_items in pkg_vars.items():
@@ -580,7 +557,7 @@ def _evaluate_selector(selector: str, selector_vars: dict[str, str | int | bool]
580557
result
581558
Result of the selector evaluation.
582559
"""
583-
return eval(selector, selector_vars)
560+
return eval(selector, selector_vars) # noqa: S307
584561

585562

586563
def _get_native_platform() -> PlatformName:
@@ -620,7 +597,8 @@ def _get_native_platform() -> PlatformName:
620597
machine = _platform.machine()
621598
platform = _platform_map.get(_sys.platform)
622599
if not platform:
623-
raise RuntimeError(f"Unknown current platform: {_sys.platform}")
600+
error_msg = f"Unknown current platform: {_sys.platform}"
601+
raise RuntimeError(error_msg)
624602
if machine in non_x86_machines:
625603
return f"{platform}-{machine}"
626604
if platform == "zos":
@@ -635,9 +613,7 @@ def _create_env_file_conda(
635613
env_name: str | None = None,
636614
indent: int | None = 2,
637615
) -> str:
638-
"""Create a Conda
639-
[environment.yml](https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html#creating-an-environment-file-manually)
640-
file.
616+
"""Create a Conda [environment.yml](https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html#creating-an-environment-file-manually) file.
641617
642618
Parameters
643619
----------
@@ -660,18 +636,15 @@ def _create_env_file_conda(
660636
if env_name:
661637
lines.append(f"name: {env_name}")
662638
lines.append("dependencies:")
663-
for match_spec in sorted(match_specs):
664-
lines.append(f"{' ' * indent}- {match_spec}")
639+
lines.extend([f"{' ' * indent}- {match_spec}" for match_spec in sorted(match_specs)])
665640
if pip_packages:
666641
lines.append(f"{' ' * indent}- pip:")
667-
for pkg in pip_packages:
668-
lines.append(f"{' ' * (indent * 2)}- {pkg['spec']}")
642+
lines.extend([f"{' ' * (indent * 2)}- {pkg['spec']}" for pkg in pip_packages])
669643
return f"{'\n'.join(lines)}\n"
670644

671645

672646
def _create_env_file_pip(packages: list[dict]) -> str:
673-
"""Create a pip
674-
[requirements.txt](https://pip.pypa.io/en/stable/user_guide/#requirements-files) file.
647+
"""Create a pip [requirements.txt](https://pip.pypa.io/en/stable/user_guide/#requirements-files) file.
675648
676649
Parameters
677650
----------
@@ -713,16 +686,16 @@ def _create_env_file_brew(packages: list[dict]) -> str:
713686
if "tap" in pkg:
714687
out.setdefault("tap", []).append(pkg["tap"])
715688
out.setdefault(pkg["type"], []).append(pkg["spec"])
716-
sections = []
717-
for section in ("tap", "brew", "cask", "mas", "whalebrew", "vscode"):
718-
if section in out:
719-
sections.append("\n".join([f"{section}: {spec}" for spec in sorted(out[section])]))
689+
sections = [
690+
"\n".join([f"{section}: {spec}" for spec in sorted(out[section])])
691+
for section in ("tap", "brew", "cask", "mas", "whalebrew", "vscode")
692+
if section in out
693+
]
720694
return f"{'\n\n'.join(sections)}\n"
721695

722696

723697
def _create_env_file_choco(packages: list[dict], indent: int | None = 4) -> str:
724-
"""Create a Chocolatey
725-
[packages.config](https://docs.chocolatey.org/en-us/choco/commands/install/#packagesconfig) file.
698+
"""Create a Chocolatey [packages.config](https://docs.chocolatey.org/en-us/choco/commands/install/#packagesconfig) file.
726699
727700
Parameters
728701
----------
@@ -734,15 +707,15 @@ def _create_env_file_choco(packages: list[dict], indent: int | None = 4) -> str:
734707
Number of spaces to use for indentation.
735708
If `None`, a compact format is used with no indentation or newlines.
736709
"""
737-
root = _xml_ET.Element("packages")
710+
root = _ET.Element("packages")
738711
for pkg in packages:
739-
package_element = _xml_ET.SubElement(root, "package")
712+
package_element = _ET.SubElement(root, "package")
740713
for key, value in pkg.items():
741714
if value is not None and value not in ("homepage",):
742715
package_element.set(_snake_case_to_camel_case(key), str(value))
743-
xml_str = _xml_ET.tostring(root, encoding="utf-8")
716+
xml_str = _ET.tostring(root, encoding="utf-8")
744717
# Format the XML string to add indentation
745-
parsed_xml = _xml_minidom.parseString(xml_str)
718+
parsed_xml = _xml_minidom.parseString(xml_str) # noqa: S318
746719
if indent is None:
747720
# Produce a single-line XML with no newlines or indentation
748721
formatted_xml = parsed_xml.toxml(encoding="utf-8")
@@ -753,9 +726,7 @@ def _create_env_file_choco(packages: list[dict], indent: int | None = 4) -> str:
753726

754727

755728
def _create_env_file_winget(packages: list[dict], indent: int | None = 4) -> str:
756-
"""Create a winget
757-
[packages.json](https://github.com/microsoft/winget-cli/blob/master/schemas/JSON/packages/packages.schema.2.0.json)
758-
file.
729+
"""Create a winget [packages.json](https://github.com/microsoft/winget-cli/blob/master/schemas/JSON/packages/packages.schema.2.0.json) file.
759730
760731
Parameters
761732
----------
@@ -791,12 +762,7 @@ def _snake_case_to_camel_case(string: str) -> str:
791762
return "".join([components[0]] + [x.title() for x in components[1:]])
792763

793764

794-
def _parse_args():
795-
def parse_extras(value):
796-
if value.lower() == "all":
797-
return "all"
798-
return value.split(",") if "," in value else [value]
799-
765+
def _parse_args() -> _argparse.Namespace:
800766
parser = _argparse.ArgumentParser(description="Install package and/or test-suite dependencies.")
801767
parser.add_argument("--filepath", type=str, default=".github/.repodynamics/metadata.json")
802768
parser.add_argument(

0 commit comments

Comments
 (0)