Skip to content

Commit

Permalink
Warn about upcoming default change in conda_pkg_format (#5534)
Browse files Browse the repository at this point in the history
Co-authored-by: jezdez <jezdez@users.noreply.github.com>
Co-authored-by: Jannis Leidel <jannis@leidel.info>
Co-authored-by: Bianca Henderson <bhenderson@anaconda.com>
  • Loading branch information
4 people authored Nov 13, 2024
1 parent 98ece01 commit 0ae2f01
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 24 deletions.
33 changes: 30 additions & 3 deletions conda_build/cli/main_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
get_or_merge_config,
zstd_compression_level_default,
)
from ..deprecations import deprecated
from ..utils import LoggingContext
from .actions import KeyValueAction, PackageTypeNormalize
from .main_render import get_render_parser
Expand Down Expand Up @@ -487,14 +488,19 @@ def parse_args(args: Sequence[str] | None) -> tuple[ArgumentParser, Namespace]:
"Do not display value of environment variables specified in build.script_env."
),
)
# TODO: Remove in 25.1
default_pkg_format = context.conda_build.get("pkg_format")
if default_pkg_format is None:
warn_about_default_pkg_format = True
default_pkg_format = conda_pkg_format_default
else:
warn_about_default_pkg_format = False
parser.add_argument(
"--package-format",
dest="conda_pkg_format",
choices=CondaPkgFormat.acceptable(),
action=PackageTypeNormalize,
default=CondaPkgFormat.normalize(
context.conda_build.get("pkg_format", conda_pkg_format_default)
),
default=CondaPkgFormat.normalize(default_pkg_format),
help=(
"Choose which package type(s) are outputted. (Accepted inputs .tar.bz2 or 1, .conda or 2)"
),
Expand All @@ -503,6 +509,27 @@ def parse_args(args: Sequence[str] | None) -> tuple[ArgumentParser, Namespace]:

parsed = parser.parse_args(args)
check_recipe(parsed.recipe)

# TODO: Remove in 25.1
if (
all(not arg.startswith("--package-format") for arg in args)
and warn_about_default_pkg_format
and "purge" not in parsed.recipe
and "purge-all" not in parsed.recipe
):
deprecated.topic(
"24.11",
"25.1",
topic="The default `pkg_format` of '.tar.bz2'",
addendum=(
"\n\n"
"The new default `pkg_format` value will be '.conda'. "
"If you want to keep using `.tar.bz2`, consider:\n"
"- Setting `conda_build.pkg_format: 'tar.bz2' in your condarc file.\n"
"- Using `--pkg-format=tar.bz2` in the CLI.\n"
),
deprecation_type=FutureWarning,
)
return parser, parsed


Expand Down
22 changes: 19 additions & 3 deletions news/4890-package-format-cli-options
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
### Enhancements

* `--package-format` introduced as command line argument. (#4890 via #5209)
* This takes precedence over default value and .condarc
* Normalization occurs so 1,tar.bz2,.tar.bz2,2,conda,.conda are all recognized and mapped appropriately
* Other options are rejected
* This takes precedence over default value and `condarc`.
* Normalization occurs so `1`, `"1"`, `tar.bz2`,`.tar.bz2`, `2`, `"2"`, `conda`, `.conda` are all recognized and mapped appropriately.
* Other options are rejected.

### Bug fixes

* <news item>

### Deprecations

* <news item>

### Docs

* <news item>

### Other

* <news item>
19 changes: 19 additions & 0 deletions news/5534-warn-default-conda-pkg-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
### Enhancements

* <news item>

### Bug fixes

* <news item>

### Deprecations

* The default value for `--package-format` and `conda_pkg_format` will become `.conda` in 25.1. (#5534)

### Docs

* <news item>

### Other

* <news item>
67 changes: 50 additions & 17 deletions tests/cli/test_main_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@

from conda_build.metadata import MetaData

# FUTURE: Remove after 25.1
DEFAULT_PACKAGE_FORMAT_FLAG = "--package-format=1"


@pytest.mark.sanity
def test_build_empty_sections(conda_build_test_recipe_envvar: str):
Expand All @@ -37,6 +40,7 @@ def test_build_empty_sections(conda_build_test_recipe_envvar: str):
os.path.join(metadata_dir, "empty_sections"),
"--no-activate",
"--no-anaconda-upload",
DEFAULT_PACKAGE_FORMAT_FLAG,
]
main_build.execute(args)

Expand All @@ -52,6 +56,7 @@ def test_build_add_channel():
"conda_build_test",
"--no-activate",
"--no-anaconda-upload",
DEFAULT_PACKAGE_FORMAT_FLAG,
os.path.join(metadata_dir, "_recipe_requiring_external_channel"),
]
main_build.execute(args)
Expand All @@ -64,6 +69,7 @@ def test_build_without_channel_fails(testing_workdir):
"--no-anaconda-upload",
"--no-activate",
os.path.join(metadata_dir, "_recipe_requiring_external_channel"),
DEFAULT_PACKAGE_FORMAT_FLAG,
]
with pytest.raises(DependencyNeedsBuildingError):
main_build.execute(args)
Expand All @@ -81,6 +87,7 @@ def test_no_filename_hash(testing_workdir, testing_metadata, capfd):
"--no-activate",
testing_workdir,
"--old-build-string",
DEFAULT_PACKAGE_FORMAT_FLAG,
]
main_build.execute(args)
output, error = capfd.readouterr()
Expand All @@ -100,7 +107,7 @@ def test_build_output_build_path(
api.output_yaml(testing_metadata, "meta.yaml")
testing_config.verbose = False
testing_config.debug = False
args = ["--output", testing_workdir]
args = ["--output", testing_workdir, DEFAULT_PACKAGE_FORMAT_FLAG]
main_build.execute(args)
test_path = os.path.join(
testing_config.croot,
Expand All @@ -118,7 +125,7 @@ def test_build_output_build_path_multiple_recipes(
api.output_yaml(testing_metadata, "meta.yaml")
testing_config.verbose = False
skip_recipe = os.path.join(metadata_dir, "build_skip")
args = ["--output", testing_workdir, skip_recipe]
args = ["--output", testing_workdir, skip_recipe, DEFAULT_PACKAGE_FORMAT_FLAG]

main_build.execute(args)

Expand All @@ -142,6 +149,7 @@ def test_slash_in_recipe_arg_keeps_build_id(
"--croot",
testing_config.croot,
"--no-anaconda-upload",
DEFAULT_PACKAGE_FORMAT_FLAG,
]
main_build.execute(args)

Expand All @@ -161,7 +169,7 @@ def test_slash_in_recipe_arg_keeps_build_id(
@pytest.mark.skipif(on_win, reason="prefix is always short on win.")
def test_build_long_test_prefix_default_enabled(mocker, testing_workdir):
recipe_path = os.path.join(metadata_dir, "_test_long_test_prefix")
args = [recipe_path, "--no-anaconda-upload"]
args = [recipe_path, "--no-anaconda-upload", DEFAULT_PACKAGE_FORMAT_FLAG]
main_build.execute(args)

args.append("--no-long-test-prefix")
Expand All @@ -177,6 +185,7 @@ def test_build_no_build_id(testing_workdir: str, testing_config: Config):
testing_config.croot,
"--no-activate",
"--no-anaconda-upload",
DEFAULT_PACKAGE_FORMAT_FLAG,
]
main_build.execute(args)

Expand Down Expand Up @@ -205,7 +214,7 @@ def test_build_multiple_recipes(testing_metadata, testing_workdir, testing_confi
api.output_yaml(testing_metadata, "recipe2/meta.yaml")
with open("recipe2/run_test.py", "w") as f:
f.write("import os; assert 'package2' in os.getenv('PREFIX')")
args = ["--no-anaconda-upload", "recipe1", "recipe2"]
args = ["--no-anaconda-upload", "recipe1", "recipe2", DEFAULT_PACKAGE_FORMAT_FLAG]
main_build.execute(args)


Expand All @@ -224,6 +233,7 @@ def test_build_output_folder(testing_workdir: str, testing_metadata: MetaData):
"--no-anaconda-upload",
"--output-folder",
str(out),
DEFAULT_PACKAGE_FORMAT_FLAG,
]
main_build.execute(args)

Expand All @@ -241,6 +251,7 @@ def test_build_source(testing_workdir: str):
testing_workdir,
"--no-activate",
"--no-anaconda-upload",
DEFAULT_PACKAGE_FORMAT_FLAG,
]
main_build.execute(args)
assert Path(testing_workdir, "work", "setup.py").is_file()
Expand Down Expand Up @@ -309,12 +320,14 @@ def test_no_force_upload(
)

# check for normal upload
main_build.execute(["--no-force-upload", testing_workdir])
main_build.execute(
["--no-force-upload", testing_workdir, DEFAULT_PACKAGE_FORMAT_FLAG]
)
call.assert_called_once_with([anaconda, "upload", *pkg])
call.reset_mock()

# check for force upload
main_build.execute([testing_workdir])
main_build.execute([testing_workdir, DEFAULT_PACKAGE_FORMAT_FLAG])
call.assert_called_once_with([anaconda, "upload", "--force", *pkg])


Expand All @@ -335,7 +348,7 @@ def test_build_skip_existing(
):
# build the recipe first
empty_sections = os.path.join(metadata_dir, "empty_sections")
args = ["--no-anaconda-upload", empty_sections]
args = ["--no-anaconda-upload", empty_sections, DEFAULT_PACKAGE_FORMAT_FLAG]
main_build.execute(args)
args.insert(0, "--skip-existing")
import conda_build.source
Expand All @@ -354,7 +367,13 @@ def test_build_skip_existing_croot(
):
# build the recipe first
empty_sections = os.path.join(metadata_dir, "empty_sections")
args = ["--no-anaconda-upload", "--croot", testing_workdir, empty_sections]
args = [
"--no-anaconda-upload",
"--croot",
testing_workdir,
empty_sections,
DEFAULT_PACKAGE_FORMAT_FLAG,
]
main_build.execute(args)
args.insert(0, "--skip-existing")
main_build.execute(args)
Expand All @@ -367,13 +386,19 @@ def test_package_test(testing_workdir, testing_metadata):
"""Test calling conda build -t <package file> - rather than <recipe dir>"""
api.output_yaml(testing_metadata, "recipe/meta.yaml")
output = api.build(testing_workdir, config=testing_metadata.config, notest=True)[0]
args = ["-t", output]
args = ["-t", output, DEFAULT_PACKAGE_FORMAT_FLAG]
main_build.execute(args)


def test_activate_scripts_not_included(testing_workdir):
recipe = os.path.join(metadata_dir, "_activate_scripts_not_included")
args = ["--no-anaconda-upload", "--croot", testing_workdir, recipe]
args = [
"--no-anaconda-upload",
"--croot",
testing_workdir,
recipe,
DEFAULT_PACKAGE_FORMAT_FLAG,
]
main_build.execute(args)
out = api.get_output_file_paths(recipe, croot=testing_workdir)[0]
for f in (
Expand Down Expand Up @@ -401,7 +426,12 @@ def test_relative_path_croot(
empty_sections = Path(metadata_dir, "empty_with_build_script")
croot = Path(".", "relative", "path")

args = ["--no-anaconda-upload", f"--croot={croot}", str(empty_sections)]
args = [
"--no-anaconda-upload",
f"--croot={croot}",
str(empty_sections),
DEFAULT_PACKAGE_FORMAT_FLAG,
]
main_build.execute(args)

assert len(list(croot.glob("**/*.tar.bz2"))) == 1
Expand All @@ -425,6 +455,7 @@ def test_relative_path_test_artifact(
"--no-test",
f"--croot={croot_abs}",
str(empty_sections),
DEFAULT_PACKAGE_FORMAT_FLAG,
]
main_build.execute(args)

Expand All @@ -439,6 +470,7 @@ def test_relative_path_test_artifact(
testing_config.subdir,
"empty_with_build_script-0.0-0.tar.bz2",
),
DEFAULT_PACKAGE_FORMAT_FLAG,
]
main_build.execute(args)

Expand All @@ -449,13 +481,13 @@ def test_test_extra_dep(testing_metadata):
output = api.build(testing_metadata, notest=True, anaconda_upload=False)[0]

# tests version constraints. CLI would quote this - "click <6.7"
args = [output, "-t", "--extra-deps", "imagesize <1.0"]
args = [output, "-t", "--extra-deps", "imagesize <1.0", DEFAULT_PACKAGE_FORMAT_FLAG]
# extra_deps will add it in
main_build.execute(args)

# missing click dep will fail tests
with pytest.raises(CondaBuildUserError):
args = [output, "-t"]
args = [output, "-t", DEFAULT_PACKAGE_FORMAT_FLAG]
# extra_deps will add it in
main_build.execute(args)

Expand All @@ -465,7 +497,7 @@ def test_test_extra_dep(testing_metadata):
[([], True), (["--long-test-prefix"], True), (["--no-long-test-prefix"], False)],
)
def test_long_test_prefix(additional_args, is_long_test_prefix):
args = ["non_existing_recipe"] + additional_args
args = ["non_existing_recipe", DEFAULT_PACKAGE_FORMAT_FLAG] + additional_args
parser, args = main_build.parse_args(args)
config = Config(**args.__dict__)
assert config.long_test_prefix is is_long_test_prefix
Expand Down Expand Up @@ -494,7 +526,7 @@ def test_zstd_compression_level(
)
request.addfinalizer(_reset_config)
_reset_config([os.path.join(testing_workdir, ".condarc")])
args = ["non_existing_recipe"]
args = ["non_existing_recipe", DEFAULT_PACKAGE_FORMAT_FLAG]
if zstd_level_cli:
args.append(f"--zstd-compression-level={zstd_level_cli}")
parser, args = main_build.parse_args(args)
Expand All @@ -512,14 +544,14 @@ def test_user_warning(tmpdir, recwarn):
recipe = dir_recipe_path.join("meta.yaml")
recipe.write("")

main_build.parse_args([str(recipe)])
main_build.parse_args([str(recipe), DEFAULT_PACKAGE_FORMAT_FLAG])
assert (
f"RECIPE_PATH received is a file ({recipe}).\n"
"It should be a path to a folder.\n"
"Forcing conda-build to use the recipe file."
) == str(recwarn.pop(UserWarning).message)

main_build.parse_args([str(dir_recipe_path)])
main_build.parse_args([str(dir_recipe_path), DEFAULT_PACKAGE_FORMAT_FLAG])
assert not recwarn.list


Expand All @@ -530,5 +562,6 @@ def test_build_with_empty_channel_fails(empty_channel: Path) -> None:
"--override-channels",
f"--channel={empty_channel}",
os.path.join(metadata_dir, "_recipe_requiring_external_channel"),
DEFAULT_PACKAGE_FORMAT_FLAG,
]
)
5 changes: 4 additions & 1 deletion tests/cli/test_main_skeleton.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
from conda_build import api
from conda_build.cli import main_build, main_skeleton

# FUTURE: Remove after 25.1
DEFAULT_PACKAGE_FORMAT_FLAG = "--package-format=1"


@pytest.mark.sanity
def test_skeleton_pypi(testing_workdir, testing_config):
Expand All @@ -15,7 +18,7 @@ def test_skeleton_pypi(testing_workdir, testing_config):
assert os.path.isdir("peppercorn")

# ensure that recipe generated is buildable
main_build.execute(("peppercorn",))
main_build.execute(("peppercorn", DEFAULT_PACKAGE_FORMAT_FLAG))


@pytest.mark.sanity
Expand Down

0 comments on commit 0ae2f01

Please sign in to comment.