mamba-org / boa

The fast conda package builder, based on mamba
https://boa-build.readthedocs.io/en/latest/
BSD 3-Clause "New" or "Revised" License
255 stars 56 forks source link

ValidationError: Can't interpolate build number in `recipe.yaml` #329

Open dhirschfeld opened 1 year ago

dhirschfeld commented 1 year ago

Trying to interpolate the build number from the context as below:

build:
  number: "{{ build_number }}"

results in the validation error:

ValidationError: Invalid value 0 for build_number ``` ╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮ │ /opt/mambaforge/envs/quantdev/lib/python3.10/site-packages/boa/core/run_build.py:372 in │ │ build_recipe │ │ │ │ 369 │ │ │ │ f"\n[yellow]Starting build for [bold]{o.name}[/bold][/yellow]\n" │ │ 370 │ │ │ ) │ │ 371 │ │ │ │ │ ❱ 372 │ │ │ final_outputs = build( │ │ 373 │ │ │ │ meta, │ │ 374 │ │ │ │ None, │ │ 375 │ │ │ │ allow_interactive=interactive, │ │ │ │ /opt/mambaforge/envs/quantdev/lib/python3.10/site-packages/boa/core/build.py:668 in build │ │ │ │ 665 │ │ │ return │ │ 666 │ │ │ │ 667 │ │ if m.output.is_package: │ │ ❱ 668 │ │ │ final_outputs = bundle_conda( │ │ 669 │ │ │ │ m, files_before_script, env, m.output.sections["files"] │ │ 670 │ │ │ ) │ │ 671 │ │ else: │ │ │ │ /opt/mambaforge/envs/quantdev/lib/python3.10/site-packages/boa/core/build.py:353 in bundle_conda │ │ │ │ 350 │ │ │ ) │ │ 351 │ │ │ final_outputs.append(final_output) │ │ 352 │ │ │ ❱ 353 │ update_index( │ │ 354 │ │ os.path.dirname(output_folder), verbose=metadata.config.debug, threads=1 │ │ 355 │ ) │ │ 356 │ │ │ │ /opt/mambaforge/envs/quantdev/lib/python3.10/site-packages/conda_build/index.py:259 in │ │ update_index │ │ │ │ 256 │ │ │ │ │ │ │ threads=threads, verbose=verbose, progress=progress, │ │ 257 │ │ │ │ │ │ │ hotfix_source_repo=hotfix_source_repo, │ │ 258 │ │ │ │ │ │ │ current_index_versions=current_index_versions) │ │ ❱ 259 │ return ChannelIndex(dir_path, channel_name, subdirs=subdirs, threads=threads, │ │ 260 │ │ │ │ │ │ deep_integrity_check=check_md5, debug=debug).index( │ │ 261 │ │ │ │ │ │ │ patch_generator=patch_generator, verbose=verbose, │ │ 262 │ │ │ │ │ │ │ progress=progress, │ │ │ │ /opt/mambaforge/envs/quantdev/lib/python3.10/site-packages/conda_build/index.py:841 in index │ │ │ │ 838 │ │ │ │ │ │ │ self._write_repodata(subdir, patched_repodata, REPODATA_JSON │ │ 839 │ │ │ │ │ │ │ t2.set_description("Building current_repodata subset") │ │ 840 │ │ │ │ │ │ │ t2.update() │ │ ❱ 841 │ │ │ │ │ │ │ current_repodata = _build_current_repodata(subdir, patched_r │ │ 842 │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ pins=current_inde │ │ 843 │ │ │ │ │ │ │ t2.set_description("Writing current_repodata subset") │ │ 844 │ │ │ │ │ │ │ t2.update() │ │ │ │ /opt/mambaforge/envs/quantdev/lib/python3.10/site-packages/conda_build/index.py:748 in │ │ _build_current_repodata │ │ │ │ 745 │ │ 746 │ │ 747 def _build_current_repodata(subdir, repodata, pins): │ │ ❱ 748 │ r = _get_resolve_object(subdir, repodata=repodata) │ │ 749 │ keep_pkgs = _shard_newest_packages(subdir, r, pins) │ │ 750 │ new_repodata = {k: repodata[k] for k in set(repodata.keys()) - {'packages', 'package │ │ 751 │ packages = {} │ │ │ │ /opt/mambaforge/envs/quantdev/lib/python3.10/site-packages/conda_build/index.py:644 in │ │ _get_resolve_object │ │ │ │ 641 │ │ │ 642 │ channel = Channel('https://conda.anaconda.org/dummy-channel/%s' % subdir) │ │ 643 │ sd = SubdirData(channel) │ │ ❱ 644 │ sd._process_raw_repodata_str(json.dumps(repodata)) │ │ 645 │ sd._loaded = True │ │ 646 │ SubdirData._cache_[channel.url(with_credentials=True)] = sd │ │ 647 │ │ │ │ /opt/mambaforge/envs/quantdev/lib/python3.10/site-packages/conda/core/subdir_data.py:419 in │ │ _process_raw_repodata_str │ │ │ │ 416 │ │ │ 417 │ def _process_raw_repodata_str(self, raw_repodata_str): │ │ 418 │ │ json_obj = json.loads(raw_repodata_str or "{}") │ │ ❱ 419 │ │ return self._process_raw_repodata(json_obj) │ │ 420 │ │ │ 421 │ def _process_raw_repodata(self, repodata): │ │ 422 │ │ subdir = repodata.get("info", {}).get("subdir") or self.channel.subdir │ │ │ │ /opt/mambaforge/envs/quantdev/lib/python3.10/site-packages/conda/core/subdir_data.py:514 in │ │ _process_raw_repodata │ │ │ │ 511 │ │ │ │ │ ) │ │ 512 │ │ │ │ │ continue │ │ 513 │ │ │ │ │ │ ❱ 514 │ │ │ │ package_record = PackageRecord(**info) │ │ 515 │ │ │ │ │ │ 516 │ │ │ │ _package_records.append(package_record) │ │ 517 │ │ │ │ _names_index[package_record.name].append(package_record) │ │ │ │ /opt/mambaforge/envs/quantdev/lib/python3.10/site-packages/conda/auxlib/entity.py:750 in │ │ __call__ │ │ │ │ 747 │ │ │ cls.__register__() │ │ 748 │ │ │ 749 │ def __call__(cls, *args, **kwargs): │ │ ❱ 750 │ │ instance = super().__call__(*args, **kwargs) │ │ 751 │ │ setattr(instance, f"_{cls.__name__}__initd", True) │ │ 752 │ │ return instance │ │ 753 │ │ │ │ /opt/mambaforge/envs/quantdev/lib/python3.10/site-packages/conda/auxlib/entity.py:766 in │ │ __init__ │ │ │ │ 763 │ def __init__(self, **kwargs): │ │ 764 │ │ for key, field in self.__fields__.items(): │ │ 765 │ │ │ try: │ │ ❱ 766 │ │ │ │ setattr(self, key, kwargs[key]) │ │ 767 │ │ │ except KeyError: │ │ 768 │ │ │ │ alias = next((ls for ls in field._aliases if ls in kwargs), None) │ │ 769 │ │ │ │ if alias is not None: │ │ │ │ /opt/mambaforge/envs/quantdev/lib/python3.10/site-packages/conda/auxlib/entity.py:426 in __set__ │ │ │ │ 423 │ │ # validate will raise an exception if invalid │ │ 424 │ │ # validate will return False if the value should be removed │ │ 425 │ │ try: │ │ ❱ 426 │ │ │ instance.__dict__[self.name] = self.validate( │ │ 427 │ │ │ │ instance, │ │ 428 │ │ │ │ self.box(instance, instance.__class__, val), │ │ 429 │ │ │ ) │ │ │ │ /opt/mambaforge/envs/quantdev/lib/python3.10/site-packages/conda/auxlib/entity.py:478 in │ │ validate │ │ │ │ 475 │ │ elif val is None and self.nullable: │ │ 476 │ │ │ return val │ │ 477 │ │ else: │ │ ❱ 478 │ │ │ raise ValidationError(getattr(self, 'name', 'undefined name'), val) │ │ 479 │ │ │ 480 │ @property │ │ 481 │ def required(self): │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ ValidationError: Invalid value 0 for build_number ```

IIUC this is because validation expects an int but interpolation requires using quotes which means any value are interpreted as strings.

I thought I could cheat and force the value to be interpreted as an int:

build:
  number: !!int "{{ build_number }}"

...but that fails the type checking in the yaml parser:

Traceback (most recent call last):
  File "/opt/mambaforge/envs/quantdev/lib/python3.10/site-packages/ruamel/yaml/constructor.py", line 498, in construct_yaml_int
    return sign * int(value_s)
ValueError: invalid literal for int() with base 10: '{{ buildnumber }}'
dhirschfeld commented 1 year ago

Unless there's a smarter way to handle this, perhaps type validation needs to be switched off for interpolated values?