Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions conda_recipe_manager/parser/recipe_parser_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,17 @@ def _upgrade_ambiguous_deps(self) -> None:
)
self._msg_tbl.add_message(MessageCategory.WARNING, f"Version on dependency changed to: {spec_str}")

def _is_noarch_python(self, base_path: str = "/") -> bool:
"""
Checks if the recipe (or a specific output) has `noarch: python` set.

:param base_path: Base path to check (defaults to root for single-output recipes)
:returns: True if the recipe has `noarch: python` set, False otherwise.
"""
noarch_path = RecipeParser.append_to_path(base_path, "/build/noarch")
noarch_value = self._v1_recipe.get_value(noarch_path, default=None)
return noarch_value == "python"

def _upgrade_selectors_to_conditionals(self) -> None:
"""
Upgrades the proprietary comment-based selector syntax to equivalent conditional logic statements.
Expand All @@ -317,6 +328,12 @@ def _upgrade_selectors_to_conditionals(self) -> None:
conda docs for common selectors:
https://docs.conda.io/projects/conda-build/en/latest/resources/define-metadata.html#preprocessing-selectors
"""
# Per CFEP-25, noarch Python recipes should use `python_min` instead of `python` in match expressions,
# as only `python_min` is defined in the variant configuration for noarch packages.
# See: https://github.com/conda/conda-recipe-manager/issues/479
is_noarch_python: Final[bool] = self._is_noarch_python()
python_match_var: Final[str] = "python_min" if is_noarch_python else "python"

selector_path_map: dict[str, str] = {}
for selector, instances in self._v1_recipe._selector_tbl.items(): # pylint: disable=protected-access
for info in instances:
Expand All @@ -333,21 +350,21 @@ def _upgrade_selectors_to_conditionals(self) -> None:
# Some commonly used selectors (like `py<36`) need to be upgraded. Otherwise, these expressions will be
# interpreted as strings. See this CEP PR for more details: https://github.com/conda/ceps/pull/71
bool_expression = Regex.SELECTOR_PYTHON_VERSION_REPLACEMENT.sub(
r'match(python, "\1\2.\3")', bool_expression
rf'match({python_match_var}, "\1\2.\3")', bool_expression
)
# Upgrades for less common `py36` and `not py27` selectors
bool_expression = Regex.SELECTOR_PYTHON_VERSION_EQ_REPLACEMENT.sub(
r'match(python, "==\1.\2")', bool_expression
rf'match({python_match_var}, "==\1.\2")', bool_expression
)
bool_expression = Regex.SELECTOR_PYTHON_VERSION_NE_REPLACEMENT.sub(
r'match(python, "!=\1.\2")', bool_expression
rf'match({python_match_var}, "!=\1.\2")', bool_expression
)
# Upgrades for less common `py2k` and `py3k` selectors
bool_expression = Regex.SELECTOR_PYTHON_VERSION_PY2K_REPLACEMENT.sub(
r'match(python, ">=2,<3")', bool_expression
rf'match({python_match_var}, ">=2,<3")', bool_expression
)
bool_expression = Regex.SELECTOR_PYTHON_VERSION_PY3K_REPLACEMENT.sub(
r'match(python, ">=3,<4")', bool_expression
rf'match({python_match_var}, ">=3,<4")', bool_expression
)

# TODO other common selectors to support:
Expand Down
6 changes: 6 additions & 0 deletions tests/parser/test_recipe_parser_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,12 @@ def test_pre_process_recipe_text(input_file: str, expected_file: str) -> None:
[],
[],
),
# Issue #479: noarch python recipes should use `python_min` instead of `python` in skip conditions
(
"noarch-python-skip.yaml",
[],
[],
),
],
)
def test_render_to_v1_recipe_format(file: str, errors: list[str], warnings: list[str]) -> None:
Expand Down
37 changes: 37 additions & 0 deletions tests/test_aux_files/noarch-python-skip.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{% set name = "noarch-python-skip" %}
{% set version = "1.0.0" %}

package:
name: {{ name|lower }}
version: {{ version }}

source:
url: https://pypi.io/packages/source/{{ name[0] }}/{{ name }}/{{ name }}-{{ version }}.tar.gz
sha256: 6d3ac79e36c9ee593c5d4fb33a50cca0e3adceb6ef5cff8b8e5aef67b4c4aaf2

build:
number: 0
noarch: python
skip: true # [py<310]
script: {{ PYTHON }} -m pip install . -vv --no-deps --no-build-isolation

requirements:
host:
- python >=3.10
- pip
run:
- python >=3.10

test:
imports:
- noarch_python_skip
commands:
- pip check
requires:
- pip

about:
home: https://github.com/example/noarch-python-skip
summary: Test package for noarch python skip condition conversion
license: MIT
license_file: LICENSE
38 changes: 38 additions & 0 deletions tests/test_aux_files/v1_format/v1_noarch-python-skip.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
schema_version: 1

context:
name: noarch-python-skip
version: 1.0.0

package:
name: ${{ name|lower }}
version: ${{ version }}

source:
url: https://pypi.io/packages/source/${{ name[0] }}/${{ name }}/${{ name }}-${{ version }}.tar.gz
sha256: 6d3ac79e36c9ee593c5d4fb33a50cca0e3adceb6ef5cff8b8e5aef67b4c4aaf2

build:
number: 0
skip: match(python_min, "<3.10")
noarch: python
script: ${{ PYTHON }} -m pip install . -vv --no-deps --no-build-isolation

requirements:
host:
- python >=3.10
- pip
run:
- python >=3.10

tests:
- python:
imports:
- noarch_python_skip
pip_check: true

about:
summary: Test package for noarch python skip condition conversion
license: MIT
license_file: LICENSE
homepage: https://github.com/example/noarch-python-skip
Loading