Repository: instructlab/instructlab

Issue:
ilab diff on a single file fails unless you specify --quiet
When running diff on an individual file:

```
ilab diff --taxonomy-path=xx.yaml
```

it errors out:

> Reading taxonomy failed with the following error: /Users/hargrave/git/instruct-lab/cli/xx.yaml

If you also specify `--quiet`, then it works.

This is because the non-quiet code path assumes the specified taxonomy path is a folder(git repo):

https://github.com/instruct-lab/cli/blob/eb953979454c546c3206da34316cfe068ad84f0c/cli/lab.py#L241

and does not detect that it is a file like is done in:

https://github.com/instruct-lab/cli/blob/eb953979454c546c3206da34316cfe068ad84f0c/cli/generator/generate_data.py#L632-L633



Discussion:

Patch:
diff --git a/src/instructlab/lab.py b/src/instructlab/lab.py
index 9570c6ff17..9e584fbaca 100644
--- a/src/instructlab/lab.py
+++ b/src/instructlab/lab.py
@@ -249,34 +249,36 @@ def diff(ctx, taxonomy_path, taxonomy_base, yaml_rules, quiet):
         logger = logging.getLogger(__name__)
     else:
         logger = ctx.obj.logger
-    if quiet:
-        try:
-            read_taxonomy(logger, taxonomy_path, taxonomy_base, yaml_rules)
-        except (SystemExit, yaml.YAMLError) as exc:
-            raise SystemExit(1) from exc
-        return
-    try:
-        updated_taxonomy_files = get_taxonomy_diff(taxonomy_path, taxonomy_base)
-    except (SystemExit, GitError) as exc:
-        click.secho(
-            f"Reading taxonomy failed with the following error: {exc}",
-            fg="red",
-        )
-        raise SystemExit(1) from exc
-    for f in updated_taxonomy_files:
-        click.echo(f)
+
+    if not quiet:
+        is_file = os.path.isfile(taxonomy_path)
+        if is_file:  # taxonomy_path is file
+            click.echo(taxonomy_path)
+        else:  # taxonomy_path is dir
+            try:
+                updated_taxonomy_files = get_taxonomy_diff(taxonomy_path, taxonomy_base)
+            except (SystemExit, GitError) as exc:
+                click.secho(
+                    f"Reading taxonomy failed with the following error: {exc}",
+                    fg="red",
+                )
+                raise SystemExit(1) from exc
+            for f in updated_taxonomy_files:
+                click.echo(f)
     try:
         read_taxonomy(logger, taxonomy_path, taxonomy_base, yaml_rules)
     except (SystemExit, yaml.YAMLError) as exc:
+        if not quiet:
+            click.secho(
+                f"Reading taxonomy failed with the following error: {exc}",
+                fg="red",
+            )
+        raise SystemExit(1) from exc
+    if not quiet:
         click.secho(
-            f"Reading taxonomy failed with the following error: {exc}",
-            fg="red",
+            f"Taxonomy in /{taxonomy_path}/ is valid :)",
+            fg="green",
         )
-        raise SystemExit(1) from exc
-    click.secho(
-        f"Taxonomy in /{taxonomy_path}/ is valid :)",
-        fg="green",
-    )
 
 
 # ilab list => ilab diff


Test patch:
diff --git a/tests/taxonomy.py b/tests/taxonomy.py
index e0a05d280d..cb00af714a 100644
--- a/tests/taxonomy.py
+++ b/tests/taxonomy.py
@@ -46,12 +46,14 @@ def untracked_files(self) -> List[str]:
         """List untracked files in the repository"""
         return self._repo.untracked_files
 
-    def create_untracked(self, rel_path: str, contents: Optional[bytes] = None) -> None:
+    def create_untracked(self, rel_path: str, contents: Optional[bytes] = None) -> Path:
         """Create a new untracked file in the repository.
 
         Args:
             rel_path (str): Relative path (from repository root) to the file.
             contents (bytes): (optional) Byte string to be written to the file.
+        Returns:
+            file_path: The path to the created file.
         """
         taxonomy_path = Path(rel_path)
         assert not taxonomy_path.is_absolute()
@@ -62,16 +64,20 @@ def create_untracked(self, rel_path: str, contents: Optional[bytes] = None) -> N
             file_path.write_text(TEST_VALID_COMPOSITIONAL_SKILL_YAML, encoding="utf-8")
         else:
             file_path.write_bytes(contents)
+        return file_path
 
-    def add_tracked(self, rel_path: str) -> None:
+    def add_tracked(self, rel_path: str) -> Path:
         """Add a new tracked file to the repository (and commits it).
 
         Args:
             rel_path (str): Relative path (from repository root) to the file.
+        Returns:
+            file_path: The path to the added file.
         """
-        self.create_untracked(rel_path)
+        file_path = self.create_untracked(rel_path)
         self._repo.index.add([rel_path])
         self._repo.index.commit("new commit")
+        return file_path
 
     def remove_file(self, rel_path: str) -> None:
         """Remove a file in the repository (tracked or not)
diff --git a/tests/test_lab_diff.py b/tests/test_lab_diff.py
index 93f9a40595..3ee1919176 100644
--- a/tests/test_lab_diff.py
+++ b/tests/test_lab_diff.py
@@ -149,6 +149,25 @@ def test_diff_valid_yaml(self):
             assert f"Taxonomy in /{self.taxonomy.root}/ is valid :)" in result.output
             assert result.exit_code == 0
 
+    def test_diff_valid_yaml_file(self):
+        with open("tests/testdata/skill_valid_answer.yaml", "rb") as qnafile:
+            valid_yaml_file = "compositional_skills/qna_valid.yaml"
+            file_path = self.taxonomy.create_untracked(valid_yaml_file, qnafile.read())
+            runner = CliRunner()
+            result = runner.invoke(
+                lab.cli,
+                [
+                    "--config=DEFAULT",
+                    "diff",
+                    "--taxonomy-base",
+                    TAXONOMY_BASE,
+                    "--taxonomy-path",
+                    file_path,
+                ],
+            )
+            assert f"Taxonomy in /{file_path}/ is valid :)" in result.output
+            assert result.exit_code == 0
+
     def test_diff_valid_yaml_quiet(self):
         with open("tests/testdata/skill_valid_answer.yaml", "rb") as qnafile:
             valid_yaml_file = "compositional_skills/qna_valid.yaml"
@@ -169,6 +188,26 @@ def test_diff_valid_yaml_quiet(self):
             assert result.output == ""
             assert result.exit_code == 0
 
+    def test_diff_valid_yaml_quiet_file(self):
+        with open("tests/testdata/skill_valid_answer.yaml", "rb") as qnafile:
+            valid_yaml_file = "compositional_skills/qna_valid.yaml"
+            file_path = self.taxonomy.create_untracked(valid_yaml_file, qnafile.read())
+            runner = CliRunner()
+            result = runner.invoke(
+                lab.cli,
+                [
+                    "--config=DEFAULT",
+                    "diff",
+                    "--taxonomy-base",
+                    TAXONOMY_BASE,
+                    "--taxonomy-path",
+                    file_path,
+                    "--quiet",
+                ],
+            )
+            assert result.output == ""
+            assert result.exit_code == 0
+
     def test_diff_invalid_yaml(self):
         with open("tests/testdata/invalid_yaml.yaml", "rb") as qnafile:
             self.taxonomy.create_untracked(