Skip to content

Commit b6bf503

Browse files
authored
Canonicalize config yaml names (#631)
* doc: add comment about PyPI name normalization in config.yaml * Canonicalize the PyPI names in config.yaml Verified via ```python after == {canonicalize_name(k): v for k,v in before.items()} ``` * Enforce canonical names with pytest * Update test cases to use canonicalized names * Test non-canonical name resolution * Canonicalize PyPI names from input requirements * Improve variable names in track_packages
1 parent d47007c commit b6bf503

File tree

6 files changed

+156
-96
lines changed

6 files changed

+156
-96
lines changed

grayskull/base/track_packages.py

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from functools import lru_cache
55
from pathlib import Path
66

7+
from packaging.utils import canonicalize_name
78
from packaging.version import Version # noqa
89
from ruamel.yaml import YAML
910

@@ -12,7 +13,9 @@
1213

1314
@dataclass
1415
class ConfigPkg:
15-
name: str
16+
"""Configuration for mapping a PyPI package to its conda-forge equivalent."""
17+
18+
pypi_name: str
1619
import_name: str = ""
1720
conda_forge: str = ""
1821
delimiter_min: str = ""
@@ -21,30 +24,35 @@ class ConfigPkg:
2124

2225
def __post_init__(self):
2326
if not self.import_name:
24-
self.import_name = self.name
27+
self.import_name = self.pypi_name
2528
if not self.conda_forge:
26-
self.conda_forge = self.name
29+
self.conda_forge = self.pypi_name
2730

2831

29-
def track_package(pkg_name: str, config_file: Path | str) -> ConfigPkg:
30-
all_pkg = _get_track_info_from_file(config_file)
31-
return ConfigPkg(pkg_name, **(all_pkg.get(pkg_name, {})))
32+
def track_package(raw_pypi_name: str, config_file: Path | str) -> ConfigPkg:
33+
"""Look up a PyPI package name in the config and return its mapping info."""
34+
pypi_to_conda_map = _get_track_info_from_file(config_file)
35+
normalized_pypi_name = canonicalize_name(raw_pypi_name)
36+
return ConfigPkg(raw_pypi_name, **(pypi_to_conda_map.get(normalized_pypi_name, {})))
3237

3338

34-
def solve_list_pkg_name(list_pkg: list[str], config_file: Path | str) -> list[str]:
39+
def solve_list_pkg_name(pypi_reqs: list[str], config_file: Path | str) -> list[str]:
40+
"""Convert a list of PyPI requirements to conda-forge package names."""
3541
re_norm = re.compile(r",\s+")
36-
return [re_norm.sub(",", solve_pkg_name(pkg, config_file)) for pkg in list_pkg]
37-
38-
39-
def solve_pkg_name(pkg: str, config_file: Path | str) -> str:
40-
pkg_name_sep = pkg.strip().split()
41-
config_pkg = track_package(pkg_name_sep[0], config_file)
42-
all_delimiter = " ".join(pkg_name_sep[1:])
43-
return (
44-
" ".join(
45-
[config_pkg.conda_forge, solve_version_delimiter(all_delimiter, config_pkg)]
46-
)
47-
).strip()
42+
return [
43+
re_norm.sub(",", solve_pkg_name(pypi_req, config_file))
44+
for pypi_req in pypi_reqs
45+
]
46+
47+
48+
def solve_pkg_name(pypi_req: str, config_file: Path | str) -> str:
49+
"""Convert a single PyPI requirement (name + version spec) to conda-forge format."""
50+
parts = pypi_req.strip().split()
51+
raw_pypi_name = parts[0]
52+
version_spec = " ".join(parts[1:])
53+
pkg_config = track_package(raw_pypi_name, config_file)
54+
resolved_version_spec = solve_version_delimiter(version_spec, pkg_config)
55+
return " ".join([pkg_config.conda_forge, resolved_version_spec]).strip()
4856

4957

5058
@lru_cache(maxsize=5)

0 commit comments

Comments
 (0)