Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Warn about upcoming default change in conda_pkg_format #5534

Merged
merged 12 commits into from
Nov 13, 2024
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
Loading