diff --git a/bob/devtools/build.py b/bob/devtools/build.py index 704fcf7ed30b94eaa23371748da76821252d1edf..f04561540637d9e251f3f97e3961ce00a6172fc1 100644 --- a/bob/devtools/build.py +++ b/bob/devtools/build.py @@ -711,22 +711,7 @@ def base_build( return conda_build.api.build(recipe_dir, config=conda_config) -def bob_devel( - bootstrap, - server, - intranet, - group, - conda_build_config, - condarc_options, - work_dir, -): - """ - Tests that all packages listed in bob/devtools/data/conda_build_config.yaml - can be installed in one environment. - """ - # Load the packages and their pins in bob/devtools/data/conda_build_config.yaml - # Create a temporary conda-build recipe to test if all packages can be installed - +def load_packages_from_conda_build_config(conda_build_config, condarc_options): with open(conda_build_config, "r") as f: content = f.read() @@ -746,6 +731,29 @@ def bob_devel( packages = [package_names_map.get(p, p) for p in package_pins.keys()] + return packages, package_names_map + + +def bob_devel( + bootstrap, + server, + intranet, + group, + conda_build_config, + condarc_options, + work_dir, +): + """ + Tests that all packages listed in bob/devtools/data/conda_build_config.yaml + can be installed in one environment. + """ + # Load the packages and their pins in bob/devtools/data/conda_build_config.yaml + # Create a temporary conda-build recipe to test if all packages can be installed + + packages, _ = load_packages_from_conda_build_config( + conda_build_config, condarc_options + ) + recipe_dir = os.path.join(work_dir, "deps", "bob-devel") template_yaml = os.path.join(recipe_dir, "meta.template.yaml") final_yaml = os.path.join(recipe_dir, "meta.yaml") diff --git a/bob/devtools/data/conda_build_config.yaml b/bob/devtools/data/conda_build_config.yaml index 98710068856dc0e1eddc04a9d19fbf62c7a49ec2..6cae8f4467afd351f62295d79797db593b0a7c4b 100644 --- a/bob/devtools/data/conda_build_config.yaml +++ b/bob/devtools/data/conda_build_config.yaml @@ -322,7 +322,7 @@ click_plugins: cmake: - 3.21.3 coverage: - - 5.5 + - 6.0 dask: - 2021.9.1 dask_jobqueue: @@ -338,7 +338,7 @@ docker_py: docopt: - 0.6.2 ffmpeg: - - 4.3 + - 4.3.2 flaky: - 3.7.0 font_ttf_dejavu_sans_mono: @@ -348,7 +348,7 @@ freetype: giflib: - 5.2.1 graphviz: - - 2.49.0 + - 2.49.1 h5py: - 3.1.0 hdf5: @@ -358,7 +358,7 @@ jinja2: jpeg: - 9d jsonschema: - - 3.2.0 + - 4.0.1 libblitz: - 1.0.2 libpng: @@ -377,9 +377,7 @@ nose: - 1.3.7 numba: - 0.54.0 -# we build against numpy 1.18 but test against newer versions. numpy: - # part of a zip_keys: python, python_impl, numpy - 1.19.5 opencv: - 4.5.1 @@ -387,6 +385,8 @@ pandas: - 1.3.3 pillow: - 8.3.2 +pip: + - 21.2.4 pkg_config: - 0.29.2 psutil: @@ -394,13 +394,13 @@ psutil: psycopg2: - 2.9.1 pybind11: - - 2.7.1 + - 2.8.0 pytables: - 3.6.1 pytest: - 6.2.5 pytest_cov: - - 2.12.1 + - 3.0.0 python_graphviz: - 0.17 pytorch: diff --git a/bob/devtools/scripts/update_pins.py b/bob/devtools/scripts/update_pins.py new file mode 100644 index 0000000000000000000000000000000000000000..7f73a764f9d91226399e2d702cd4d2fa56d32af7 --- /dev/null +++ b/bob/devtools/scripts/update_pins.py @@ -0,0 +1,99 @@ +"""Updates the pin versions inside bob/devtools/data/conda_build_config.yaml""" + +import click + + +@click.command( + epilog="""Example: + +python bob/devtools/scripts/update_pins.py --python 3.8 + +Force specific version of packages: + +python bob/devtools/scripts/update_pins.py --python 3.8 opencv=4.5.1 pytorch=1.9 +""" +) +@click.argument("manual_pins", nargs=-1) +@click.option("--python", required=True, help="Python version to pin, e.g. 3.8") +def update_pins(manual_pins, python): + import subprocess + + from bob.devtools.build import load_packages_from_conda_build_config + + conda_config_path = "bob/devtools/data/conda_build_config.yaml" + + packages, package_names_map = load_packages_from_conda_build_config( + conda_config_path, {"channels": []} + ) + reversed_package_names_map = {v: k for k, v in package_names_map.items()} + + # ask mamba to create an environment with the packages + try: + output = subprocess.run( + [ + "mamba", + "create", + "--dry-run", + "--override-channels", + "-c", + "conda-forge", + "-n", + "temp_env", + f"python={python}", + ] + + packages + + list(manual_pins), + capture_output=True, + check=True, + ) + except subprocess.CalledProcessError as e: + print(e.output.decode()) + raise e + + env_text = output.stdout.decode("utf-8") + print(env_text) + + resolved_packages = [] + for line in env_text.split("\n"): + line = line.strip() + if line.startswith("+ "): + line = line.split() + name, version = line[1], line[2] + resolved_packages.append((name, version)) + + # write the new pinning + with open(conda_config_path, "r") as f: + content = f.read() + + START = """ +# AUTOMATIC PARSING START +# DO NOT MODIFY THIS COMMENT + +# list all packages with dashes or dots in their names, here:""" + idx1 = content.find(START) + idx2 = content.find("# AUTOMATIC PARSING END") + pins = "\n".join( + f"{reversed_package_names_map.get(name, name)}:\n - {version}" + for name, version in resolved_packages + if name in packages + ) + package_names_map_str = "\n".join( + f" {k}: {v}" for k, v in package_names_map.items() + ) + + new_content = f"""{START} +package_names_map: +{package_names_map_str} + + +{pins} + +""" + + content = content[:idx1] + new_content + content[idx2:] + with open(conda_config_path, "w") as f: + f.write(content) + + +if __name__ == "__main__": + update_pins() diff --git a/bob/devtools/templates/conda/meta.yaml b/bob/devtools/templates/conda/meta.yaml index 3beccf72454e2acafda97f6a733ce9d2615ef5b9..b13c27a753b2280b3cdbbcae099a9b35ef78eb18 100644 --- a/bob/devtools/templates/conda/meta.yaml +++ b/bob/devtools/templates/conda/meta.yaml @@ -12,9 +12,9 @@ build: script: - cd {{ project_dir }} {% if environ.get('BUILD_EGG') %} - - python setup.py sdist --formats=zip + - "{{ PYTHON }} setup.py sdist --formats=zip" {% endif %} - - python setup.py install --single-version-externally-managed --record record.txt + - "{{ PYTHON }} -m pip install . -vv" # installs the documentation source, readme to share/doc so it is available # during test time - install -d "${PREFIX}/share/doc/{{ name }}" @@ -25,6 +25,7 @@ requirements: host: - python {{ python }} - setuptools {{ setuptools }} + - pip {{ pip }} - bob.extension # place your other host dependencies here (same as requirements.txt) # use the format: @@ -47,6 +48,7 @@ test: imports: - {{ name }} commands: + - pip check # runs tests for package only, report only what is in the package # creates html and xml reports and place them in specific directories - pytest --verbose --cov {{ name }} --cov-report term-missing --cov-report html:{{ project_dir }}/sphinx/coverage --cov-report xml:{{ project_dir }}/coverage.xml --pyargs {{ name }} @@ -55,6 +57,7 @@ test: - conda inspect linkages -p $PREFIX {{ name }} # [not win] - conda inspect objects -p $PREFIX {{ name }} # [osx] requires: + - pip {{ pip }} - pytest {{ pytest }} - pytest-cov {{ pytest_cov }} - coverage {{ coverage }} diff --git a/conda/meta.yaml b/conda/meta.yaml index fbfa05c8d674af9b796014f529679b1d97c91728..f97be00ad4bb80312945e4f60aa3162d915d727f 100644 --- a/conda/meta.yaml +++ b/conda/meta.yaml @@ -13,9 +13,9 @@ build: script: - cd {{ environ.get('RECIPE_DIR') + '/..' }} {% if environ.get('BUILD_EGG') and not os.path.exists('dist') %} - - python setup.py sdist --formats=zip + - "{{ PYTHON }} setup.py sdist --formats=zip" {% endif %} - - {{ PYTHON }} -m pip install --no-deps --ignore-installed . + - "{{ PYTHON }} -m pip install . -vv" # installs the documentation source, readme to share/doc so it is available # during test time - install -d "${PREFIX}/share/doc/{{ name }}" @@ -56,12 +56,14 @@ requirements: test: requires: + - pip - sphinx_rtd_theme - pytest - pytest-cov imports: - {{ name }} commands: + - pip check - bdt -h - bdt -? - bdt --help