diff --git a/python/CHANGELOG.md b/python/CHANGELOG.md index 78f6720aa..19a5c783f 100644 --- a/python/CHANGELOG.md +++ b/python/CHANGELOG.md @@ -9,6 +9,10 @@ Note that for version number starting with a `0`, i.e., `0.x.y`, a bump of `x` should be considered as a major (and thus potentially breaking) change. See semver guidelines for more details about this. +## [Unreleased] +- Python fallback client: removed `--compatibility-mode` / `-c` flag. Its original purpose (output mimicking Unix `file`) was lost when the `magic` field was removed in v0.6.1; it had since been a no-op alias for `--no-colors`. +- Python fallback client: colors are now auto-disabled when stdout is not a TTY, matching Rust client behavior. Use `--colors` to force them on, `--no-colors` to force them off. + ## [1.0.2] - 2026-02-25 - Mark python 3.14 as supported. - Remove direct dependency on numpy. diff --git a/python/src/magika/cli/magika_client.py b/python/src/magika/cli/magika_client.py index 86a6ed00d..4a01c65c5 100755 --- a/python/src/magika/cli/magika_client.py +++ b/python/src/magika/cli/magika_client.py @@ -83,13 +83,6 @@ is_flag=True, help="Output a simple label instead of a verbose content type description. Use --list-output-content-types for the list of supported output.", ) -@click.option( - "-c", - "--compatibility-mode", - "magic_compatibility_mode", - is_flag=True, - help="Compatibility mode: output is as close as possible to `file` and colors are disabled.", -) @click.option( "-s", "--output-score", @@ -112,11 +105,18 @@ help="This option causes symlinks not to be followed. By default, symlinks are dereferenced.", ) @click.option( - "--colors/--no-colors", - "with_colors", + "--colors", + "force_colors", + is_flag=True, + default=False, + help="Force color output regardless of terminal support.", +) +@click.option( + "--no-colors", + "no_colors", is_flag=True, - default=True, - help="Enable/disable use of colors.", + default=False, + help="Disable color output regardless of terminal support.", ) @click.option("-v", "--verbose", is_flag=True, help="Enable more verbose output.") @click.option("-vv", "--debug", is_flag=True, help="Enable debug logging.") @@ -137,12 +137,12 @@ def main( jsonl_output: bool, mime_output: bool, label_output: bool, - magic_compatibility_mode: bool, output_score: bool, prediction_mode_str: str, batch_size: int, no_dereference: bool, - with_colors: bool, + force_colors: bool, + no_colors: bool, verbose: bool, debug: bool, output_version: bool, @@ -154,9 +154,16 @@ def main( # the argument "file" (which is ugly) and we re-assign it as soon as we can. files_paths = file - if magic_compatibility_mode: - # In compatibility mode we disable colors. + if force_colors and no_colors: + click.echo("Error: --colors and --no-colors are mutually exclusive.", err=True) + sys.exit(1) + + if force_colors: + with_colors = True + elif no_colors: with_colors = False + else: + with_colors = sys.stdout.isatty() _l = get_logger(use_colors=with_colors) @@ -198,8 +205,8 @@ def main( _l.error("You should use either --json or --jsonl, not both.") sys.exit(1) - if int(mime_output) + int(label_output) + int(magic_compatibility_mode) > 1: - _l.error("You should use only one of --mime, --label, --compatibility-mode.") + if int(mime_output) + int(label_output) > 1: + _l.error("You should use only one of --mime-type, --label.") sys.exit(1) if recursive: @@ -283,8 +290,6 @@ def main( for file_path, result in zip(batch_files_paths, batch_predictions): if result.ok: if mime_output: - # If the user requested the MIME type, we use the mime type - # regardless of the compatibility mode. output = result.prediction.output.mime_type elif label_output: output = str(result.prediction.output.label) diff --git a/python/tests/test_python_magika_client.py b/python/tests/test_python_magika_client.py index 4baa1c3cc..1192df357 100644 --- a/python/tests/test_python_magika_client.py +++ b/python/tests/test_python_magika_client.py @@ -13,19 +13,39 @@ # limitations under the License. import subprocess +import sys from pathlib import Path +CLIENT = ( + Path(__file__).parent.parent / "src" / "magika" / "cli" / "magika_client.py" +).resolve() + + +def _run(*args: str) -> subprocess.CompletedProcess: + return subprocess.run( + [sys.executable, str(CLIENT), *args], capture_output=True, text=True + ) -def test_python_magika_client() -> None: - python_root_dir = Path(__file__).parent.parent - python_magika_client_path = ( - python_root_dir / "src" / "magika" / "cli" / "magika_client.py" - ).resolve() +def test_python_magika_client() -> None: # quick test to check there are no obvious problems - cmd = [str(python_magika_client_path), "--help"] - subprocess.run(cmd, capture_output=True, check=True) + subprocess.run([sys.executable, str(CLIENT), "--help"], capture_output=True, check=True) # quick test to check there are no crashes - cmd = [str(python_magika_client_path), str(python_magika_client_path)] - subprocess.run(cmd, capture_output=True, check=True) + subprocess.run([sys.executable, str(CLIENT), str(CLIENT)], capture_output=True, check=True) + + +def test_compatibility_mode_removed() -> None: + result = _run("--compatibility-mode", str(CLIENT)) + assert result.returncode != 0, "--compatibility-mode should no longer be accepted" + + +def test_no_colors_flag() -> None: + result = _run("--no-colors", str(CLIENT)) + assert result.returncode == 0 + assert "\x1b[" not in result.stdout, "--no-colors should produce no ANSI escape codes" + + +def test_colors_flag() -> None: + result = _run("--colors", str(CLIENT)) + assert result.returncode == 0