From 6750e91cc16ba7536d99f614ff8ae5744f9da11c Mon Sep 17 00:00:00 2001 From: kompre Date: Mon, 1 Dec 2025 10:32:18 +0100 Subject: [PATCH 1/3] chore: add proposal for graceful no-files-exit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add task proposal to handle "no files found" scenarios gracefully. Currently CLI exits with error code 1 when no files are found. Proposal suggests exiting with code 0 since no work to do is not an error. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- _todo/proposal/graceful-no-files-exit.md | 82 ++++++++++++++++++++++++ _todo/todo.md | 1 + 2 files changed, 83 insertions(+) create mode 100644 _todo/proposal/graceful-no-files-exit.md diff --git a/_todo/proposal/graceful-no-files-exit.md b/_todo/proposal/graceful-no-files-exit.md new file mode 100644 index 0000000..0897818 --- /dev/null +++ b/_todo/proposal/graceful-no-files-exit.md @@ -0,0 +1,82 @@ +# Task Proposal: Graceful Exit When No Files Found + +## Original Objective +When no .ipynb files (or .qmd files) are found to process, the CLI currently terminates with error code 1. This should be handled gracefully - just exit with code 0 since there's no work to do. + +## Current Behavior +The CLI exits with error code 1 in two scenarios: +1. **No files found initially** (quarto_batch_convert.py:301-303): When input paths contain no files with the target extension +2. **No files after regex filtering** (quarto_batch_convert.py:321-326): When regex pattern matches no files + +Both cases print error messages and call `ctx.exit(1)`. + +## Proposed Changes + +### 1. Exit with Code 0 for "No Work to Do" Scenarios +**File**: `src/quarto_batch_convert/quarto_batch_convert.py` + +**Change 1** (lines 301-303): +```python +# Before: +if not files: + click.echo("Error: No files found to process") + ctx.exit(1) + +# After: +if not files: + click.echo("No files found to process") + return # Exit gracefully with code 0 +``` + +**Change 2** (lines 321-326): +```python +# Before: +if not files: + if match_regex: + click.echo(f"No files found matching the regex pattern: {match_regex}") + else: + click.echo("No files found to process") + ctx.exit(1) + +# After: +if not files: + if match_regex: + click.echo(f"No files found matching the regex pattern: {match_regex}") + else: + click.echo("No files found to process") + return # Exit gracefully with code 0 +``` + +### 2. Update Tests (if needed) +**File**: `tests/test_quarto_batch_convert.py` + +Check if any tests expect exit code 1 for "no files found" scenarios. Update them to expect code 0 instead. + +## Implementation Steps + +1. Read `src/quarto_batch_convert/quarto_batch_convert.py` +2. Update lines 301-303: Remove "Error:" prefix, change `ctx.exit(1)` to `return` +3. Update lines 321-326: Change `ctx.exit(1)` to `return` +4. Read `tests/test_quarto_batch_convert.py` to check for affected tests +5. Update any tests that assert exit code 1 for "no files found" +6. Run test suite: `uv run pytest tests -v` +7. Verify locally with test case: run CLI on empty directory + +## Rationale + +- **Exit code 0**: No files to process is not an error condition - it's a valid state where the tool has nothing to do +- **Remove "Error:" prefix**: Since this isn't an error, the message shouldn't be labeled as such +- **Graceful termination**: Tools that find no work shouldn't fail CI/CD pipelines or automated scripts +- **Consistency**: Many Unix tools (grep, find, etc.) exit with 0 when finding no matches + +## Testing Scenarios + +1. Empty directory with `-r` flag +2. Directory with files but wrong extension +3. Regex pattern that matches no files +4. Non-existent glob pattern + +All should exit with code 0 and informative (non-error) message. + +## Status +**Awaiting User Review** diff --git a/_todo/todo.md b/_todo/todo.md index 37dd5ae..728c0f8 100644 --- a/_todo/todo.md +++ b/_todo/todo.md @@ -7,6 +7,7 @@ ## Proposed Tasks (Awaiting Review) 1. **new-release-workflow** - Proposal in `proposal/new-release-workflow.md` +2. **graceful-no-files-exit** - Proposal in `proposal/graceful-no-files-exit.md` ## Completed Tasks From 8f0231c3c1e188022a1d3705e02762fc3ab218df Mon Sep 17 00:00:00 2001 From: kompre Date: Mon, 1 Dec 2025 10:34:15 +0100 Subject: [PATCH 2/3] fix: exit gracefully when no files found MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changed CLI behavior to exit with code 0 instead of 1 when no files are found to process. This treats "no work to do" as a valid state rather than an error condition. Changes: - Remove "Error:" prefix from "no files found" messages - Replace ctx.exit(1) with return for graceful exit - Update test_no_match_found to expect exit code 0 - Update test docstring to reflect graceful exit behavior Rationale: - No files to process is not an error - it's a valid state - Prevents failure of CI/CD pipelines and automated scripts - Consistent with Unix tools (grep, find) that exit 0 on no matches All 17 tests pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../graceful-no-files-exit.md | 33 +++++++++++++++++-- _todo/todo.md | 3 +- .../quarto_batch_convert.py | 6 ++-- tests/test_quarto_batch_convert.py | 12 +++---- 4 files changed, 41 insertions(+), 13 deletions(-) rename _todo/{proposal => pending}/graceful-no-files-exit.md (73%) diff --git a/_todo/proposal/graceful-no-files-exit.md b/_todo/pending/graceful-no-files-exit.md similarity index 73% rename from _todo/proposal/graceful-no-files-exit.md rename to _todo/pending/graceful-no-files-exit.md index 0897818..dd90087 100644 --- a/_todo/proposal/graceful-no-files-exit.md +++ b/_todo/pending/graceful-no-files-exit.md @@ -78,5 +78,34 @@ Check if any tests expect exit code 1 for "no files found" scenarios. Update the All should exit with code 0 and informative (non-error) message. -## Status -**Awaiting User Review** +## Implementation Summary + +**Status**: ✅ Completed + +### Changes Made + +1. **quarto_batch_convert.py:301-303** - Updated first exit point + - Removed "Error:" prefix from message + - Changed `ctx.exit(1)` to `return` for graceful exit + +2. **quarto_batch_convert.py:321-326** - Updated second exit point + - Changed `ctx.exit(1)` to `return` for graceful exit + - Kept informative message about regex pattern + +3. **test_quarto_batch_convert.py:128-145** - Updated test + - Changed `test_no_match_found()` to expect exit code 0 + - Updated docstring to reflect graceful exit behavior + +### Test Results +All 17 tests passed successfully: +- ✅ test_no_match_found now validates exit code 0 +- ✅ All other tests remain passing +- ✅ Test suite completed in 7.79s + +### Verification +The CLI now exits gracefully (code 0) when: +- No files with target extension are found in input paths +- Regex pattern matches no files +- Directory is empty + +Non-error scenarios no longer fail CI/CD pipelines or automated scripts. diff --git a/_todo/todo.md b/_todo/todo.md index 728c0f8..78dff41 100644 --- a/_todo/todo.md +++ b/_todo/todo.md @@ -2,12 +2,11 @@ ## Active Tasks - +1. **graceful-no-files-exit** - In progress in `pending/graceful-no-files-exit.md` ## Proposed Tasks (Awaiting Review) 1. **new-release-workflow** - Proposal in `proposal/new-release-workflow.md` -2. **graceful-no-files-exit** - Proposal in `proposal/graceful-no-files-exit.md` ## Completed Tasks diff --git a/src/quarto_batch_convert/quarto_batch_convert.py b/src/quarto_batch_convert/quarto_batch_convert.py index 7a6119f..0816b4e 100644 --- a/src/quarto_batch_convert/quarto_batch_convert.py +++ b/src/quarto_batch_convert/quarto_batch_convert.py @@ -299,8 +299,8 @@ def convert_files( # Check if any files were found if not files: - click.echo("Error: No files found to process") - ctx.exit(1) + click.echo("No files found to process") + return if output_path is None: output_path = base_input_path @@ -323,7 +323,7 @@ def convert_files( click.echo(f"No files found matching the regex pattern: {match_regex}") else: click.echo("No files found to process") - ctx.exit(1) + return print(f"Found {len(files)} file(s) to be converted:\n") print(f"\n\t{files}\n") diff --git a/tests/test_quarto_batch_convert.py b/tests/test_quarto_batch_convert.py index 58c351d..7fe917e 100644 --- a/tests/test_quarto_batch_convert.py +++ b/tests/test_quarto_batch_convert.py @@ -128,20 +128,20 @@ def test_invalid_regex_pattern() -> None: def test_no_match_found(setup_teardown_test_env: str) -> None: """Test that a non-matching pattern results in no files being processed. - Verifies that when a regex pattern matches no files, the CLI exits with - an error code and displays an appropriate message. + Verifies that when a regex pattern matches no files, the CLI exits gracefully + with exit code 0 and displays an appropriate message. Args: setup_teardown_test_env: Path to the temporary test directory. """ runner = CliRunner() test_dir = setup_teardown_test_env - + input_files = glob.glob(test_dir + "/**/*", recursive=True) - + result = runner.invoke(quarto_batch_convert, [*input_files, "-m", "non_existent_pattern"]) - - assert result.exit_code != 0 + + assert result.exit_code == 0 assert "No files found matching the regex pattern" in result.output def test_prefix_option(setup_teardown_test_env: str) -> None: From 788bee247cb43a82bd92eb3ea3fac8ed242ba538 Mon Sep 17 00:00:00 2001 From: kompre Date: Mon, 1 Dec 2025 10:39:58 +0100 Subject: [PATCH 3/3] version bump --- pyproject.toml | 2 +- uv.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 78154d2..ce33f6a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "quarto-batch-convert" -version = "2025.9.1" +version = "2025.9.2" description = "Converts multiple Jupyter notebooks to Quarto documents at once" readme = "README.md" license = "MIT" diff --git a/uv.lock b/uv.lock index da994a5..38df720 100644 --- a/uv.lock +++ b/uv.lock @@ -81,7 +81,7 @@ wheels = [ [[package]] name = "quarto-batch-convert" -version = "2025.9.1" +version = "2025.9.2" source = { editable = "." } dependencies = [ { name = "click" },