diff --git a/grayskull/config.py b/grayskull/config.py index a4bc9a562..0961c75dc 100644 --- a/grayskull/config.py +++ b/grayskull/config.py @@ -74,6 +74,8 @@ def get_py_version_available( else: py_ver_enabled = {py_ver: True for py_ver in sup_python_ver} for op, major, minor in req_python: + if op == "=": + op = "==" if not minor: minor = 0 for sup_py, is_enabled in py_ver_enabled.items(): diff --git a/grayskull/strategy/py_base.py b/grayskull/strategy/py_base.py index 6926af94e..ed069c267 100644 --- a/grayskull/strategy/py_base.py +++ b/grayskull/strategy/py_base.py @@ -293,8 +293,8 @@ def get_setup_cfg(source_path: str) -> dict: setup_cfg = read_configuration(str(path_setup_cfg)) setup_cfg = dict(setup_cfg) if setup_cfg.get("options", {}).get("python_requires"): - setup_cfg["options"]["python_requires"] = str( - setup_cfg["options"]["python_requires"] + setup_cfg["options"]["python_requires"] = ensure_pep440( + str(setup_cfg["options"]["python_requires"]) ) result = {} result.update(setup_cfg.get("options", {})) @@ -677,3 +677,30 @@ def get_sdist_metadata( metadata["source"] = {"url": sdist_url, "sha256": sha256_checksum(path_pkg)} return metadata + + +def ensure_pep440_in_req_list(list_req: List[str]) -> List[str]: + return [ensure_pep440(pkg) for pkg in list_req] + + +def ensure_pep440(pkg: str) -> str: + if not pkg: + return pkg + if pkg.strip().startswith("<{") or pkg.strip().startswith("{{"): + return pkg + split_pkg = pkg.strip().split(" ") + if len(split_pkg) <= 1: + return pkg + constrain_pkg = "".join(split_pkg[1:]) + list_constrains = constrain_pkg.split(",") + full_constrain = [] + for constrain in list_constrains: + if "~=" in constrain: + version = constrain.strip().replace("~=", "").strip() + version_reduced = ".".join(version.split(".")[:-1]) + version_reduced += ".*" + full_constrain.append(f">={version},=={version_reduced}") + else: + full_constrain.append(constrain.strip()) + all_constrains = ",".join(full_constrain) + return f"{split_pkg[0]} {all_constrains}" diff --git a/grayskull/strategy/pypi.py b/grayskull/strategy/pypi.py index 2e374f31e..2a8027656 100644 --- a/grayskull/strategy/pypi.py +++ b/grayskull/strategy/pypi.py @@ -21,6 +21,8 @@ RE_DEPS_NAME, clean_deps_for_conda_forge, discover_license, + ensure_pep440, + ensure_pep440_in_req_list, get_compilers, get_entry_points_from_sdist, get_extra_from_requires_dist, @@ -85,8 +87,10 @@ def get_val(key): "entry_points": get_entry_points_from_sdist(sdist_metadata), "scripts": get_val("scripts"), "summary": get_val("summary"), - "requires_python": pypi_metadata.get("requires_python") - or sdist_metadata.get("python_requires"), + "requires_python": ensure_pep440( + pypi_metadata.get("requires_python") + or sdist_metadata.get("python_requires") + ), "doc_url": get_val("doc_url"), "dev_url": get_val("dev_url"), "license": get_val("license"), @@ -341,14 +345,17 @@ def get_metadata(recipe, config) -> dict: print_msg(f"License file: {Fore.LIGHTMAGENTA_EX}{license_file}") all_requirements = extract_requirements(metadata, config, recipe) + if all_requirements.get("host"): all_requirements["host"] = solve_list_pkg_name( all_requirements["host"], PYPI_CONFIG ) + all_requirements["host"] = ensure_pep440_in_req_list(all_requirements["host"]) if all_requirements.get("run"): all_requirements["run"] = solve_list_pkg_name( all_requirements["run"], PYPI_CONFIG ) + all_requirements["run"] = ensure_pep440_in_req_list(all_requirements["run"]) if config.is_strict_cf: all_requirements["host"] = clean_deps_for_conda_forge( all_requirements["host"], config.py_cf_supported[0] diff --git a/tests/test_pypi.py b/tests/test_pypi.py index 48839cab8..d7004f3c6 100644 --- a/tests/test_pypi.py +++ b/tests/test_pypi.py @@ -15,6 +15,7 @@ from grayskull.config import Configuration from grayskull.strategy.py_base import ( clean_deps_for_conda_forge, + ensure_pep440, generic_py_ver_to, get_compilers, get_entry_points_from_sdist, @@ -839,3 +840,17 @@ def test_get_test_imports_clean_modules(): ) == ["_pytest", "_pytest._code"] ) + + +def test_ensure_pep440(): + assert ensure_pep440("pytest ~=5.3.2") == "pytest >=5.3.2,==5.3.*" + + +def test_pep440_recipe(): + recipe = create_python_recipe("codalab=0.5.26", is_strict_cf=False)[0] + assert recipe["requirements"]["host"] == ["pip", "python >=3.6,<3.7"] + + +def test_pep440_in_recipe_pypi(): + recipe = create_python_recipe("kedro=0.17.6", is_strict_cf=False)[0] + assert sorted(recipe["requirements"]["run"])[0] == "anyconfig >=0.10.0,==0.10.*"