Skip to content

Refactored the CLI entry point into modular helper functions for better maintainability#26

Open
wenh06 wants to merge 2 commits intomasterfrom
feature/enhance-cli
Open

Refactored the CLI entry point into modular helper functions for better maintainability#26
wenh06 wants to merge 2 commits intomasterfrom
feature/enhance-cli

Conversation

@wenh06
Copy link
Contributor

@wenh06 wenh06 commented Feb 28, 2026

Changes made:

  1. Refactoring: Split the monolithic main function into modular helper functions:
    - _handle_config: Handles configuration commands (show, reset, set).
    - _handle_gather: Handles the --gather command logic.
    - _handle_simplify_bib: Handles the --simplify-bib command logic.
    - main: Now serves as a clean entry point that orchestrates argument parsing and dispatches to handlers.
  2. Robustness & Testing:
    - Added validation for configuration file extensions (only .json, .yaml, .yml supported).
    - Added validation for the input file in --gather command (must be a valid .tex file).
    - Added new test cases in test/test_cli.py to cover these error conditions.
    - Achieved 98% test coverage for bib_lookup/cli.py.

Copilot AI review requested due to automatic review settings February 28, 2026 03:02
@wenh06 wenh06 self-assigned this Feb 28, 2026
@codecov
Copy link

codecov bot commented Feb 28, 2026

Codecov Report

❌ Patch coverage is 96.59091% with 3 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (master@34dad0a). Learn more about missing BASE report.
⚠️ Report is 2 commits behind head on master.

Files with missing lines Patch % Lines
bib_lookup/cli.py 96.59% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff            @@
##             master      #26   +/-   ##
=========================================
  Coverage          ?   97.95%           
=========================================
  Files             ?        8           
  Lines             ?     1318           
  Branches          ?        0           
=========================================
  Hits              ?     1291           
  Misses            ?       27           
  Partials          ?        0           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5986361b4a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 224 to +225
"--ignore-errors",
type=str2bool,
default=True,
action="store_true",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep --ignore-errors accepting explicit boolean values

Changing --ignore-errors to action="store_true" breaks existing CLI invocations that pass a value (for example --ignore-errors true/false): with identifiers defined as positional nargs=*, the trailing token is now consumed as an identifier instead of the option value, causing an unintended extra lookup and making it impossible to explicitly set ignore_errors to false on the command line.

Useful? React with 👍 / 👎.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the CLI entry point in bib_lookup/cli.py by extracting the monolithic main() function into three helper functions (_handle_config, _handle_gather, _handle_simplify_bib) for better maintainability. It also adds validation for file extensions in the --config and --gather commands, and updates the corresponding test suite.

Changes:

  • Split main() into _handle_config, _handle_gather, and _handle_simplify_bib helper functions
  • Changed --ignore-errors argument from type=str2bool, default=True to action="store_true", and improved the --timeout help text
  • Added new test cases for invalid config/gather file extensions, plus a no-assertion network lookup test block

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
bib_lookup/cli.py Extracts helper functions, adds a try/except guard around yaml import, changes --ignore-errors to action="store_true", and reformats init_args construction
test/test_cli.py Adds test cases for invalid .txt config and gather file paths, and adds a no-assertion network lookup block
CHANGELOG.rst Documents the CLI refactoring

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

"--ignore-errors",
type=str2bool,
default=True,
action="store_true",
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing --ignore-errors from type=str2bool, default=True to action="store_true" is a breaking change. The existing tests at lines 96 and 103 in test/test_cli.py call --ignore-errors true, where true will now be parsed as a positional identifier (something to look up) rather than the boolean value for the flag. With action="store_true", the flag takes no argument — providing true after it causes it to be consumed as an extra positional identifiers argument, resulting in the CLI attempting to look up "true" as a DOI/arXiv ID. You should update the existing test invocations to simply use --ignore-errors (without true) to match the new store_true semantics.

Suggested change
action="store_true",
type=str2bool,
nargs="?",
const=True,
default=True,

Copilot uses AI. Check for mistakes.
"ignore_errors",
"verbose",
]
init_args = {k: args[k] for k in init_keys if args[k] is not None}
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because --ignore-errors uses action="store_true", its default value is False (not None). The init_args dictionary is built with {k: args[k] for k in init_keys if args[k] is not None}, so ignore_errors=False will always be included — even when the user never specified the flag. This silently overrides any user config that has ignore_errors: true, making it impossible to enable ignore_errors via the config file when using the CLI. To fix this, use default=None with explicit action handling, or use a separate sentinel to distinguish "not provided" from False.

Suggested change
init_args = {k: args[k] for k in init_keys if args[k] is not None}
# Build init_args while ensuring that the default value of --ignore-errors
# (False from argparse's store_true) does not override configuration unless
# the flag was explicitly provided.
init_args = {
k: args[k]
for k in init_keys
if k != "ignore_errors" and args[k] is not None
}
if "ignore_errors" in args and args["ignore_errors"]:
init_args["ignore_errors"] = True

Copilot uses AI. Check for mistakes.
Comment on lines +216 to +225
# lookup with print
# use a fake DOI that is mocked or use a known one if network is allowed (it seems network is used in tests)
# But network calls are flaky.
# The existing test uses 10.1109/CVPR.2016.90.
# Let's check if output is produced.
cmd = "bib-lookup 10.1109/CVPR.2016.90 --timeout 10"
exitcode, output_msg = execute_cmd(cmd)
# output_msg should contain something if successful.
# If network fails, it might be empty.

Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new test block at lines 216-224 runs a network lookup command but has no assertions (no assert statement). The comment says "output_msg should contain something if successful" but there is no check. This means the test block provides no coverage guarantees — it will pass even if the command silently produces no output. Either add a meaningful assertion or remove this block if it duplicates coverage already provided by the earlier 10.1109/CVPR.2016.90 test at lines 94-99.

Suggested change
# lookup with print
# use a fake DOI that is mocked or use a known one if network is allowed (it seems network is used in tests)
# But network calls are flaky.
# The existing test uses 10.1109/CVPR.2016.90.
# Let's check if output is produced.
cmd = "bib-lookup 10.1109/CVPR.2016.90 --timeout 10"
exitcode, output_msg = execute_cmd(cmd)
# output_msg should contain something if successful.
# If network fails, it might be empty.

Copilot uses AI. Check for mistakes.
Comment on lines +13 to +16
try:
import yaml
except ImportError:
yaml = None # type: ignore
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PyYAML is listed as a required dependency in requirements.txt, so the try/except ImportError guard around import yaml and the subsequent yaml is None check (line 61) are dead code — yaml will always be importable in any supported environment. This adds unnecessary complexity and could mislead readers into thinking YAML support is optional.

Copilot uses AI. Check for mistakes.
Comment on lines +56 to +69
assert config_path.is_file(), f"Configuration file ``{config_arg}`` does not exist. Please check and try again."

if config_path.suffix == ".json":
config = json.loads(config_path.read_text())
elif config_path.suffix in [".yaml", ".yml"]:
if yaml is None:
raise ImportError(
"PyYAML is required to parse yaml config files. Please install it via `pip install PyYAML`."
)
config = yaml.safe_load(config_path.read_text())
else:
raise ValueError(
f"Unknown configuration file type ``{config_path.suffix}``. " "Only json and yaml files are supported."
)
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When an unsupported config file extension is provided, _handle_config raises a ValueError (or AssertionError for non-existent files) that propagates uncaught from main(). While this does result in exit code 1 (satisfying the test assertion), it prints a full Python traceback to the user rather than a clean error message. The _handle_gather function uses sys.exit(1) with friendly print(f"Error: ...") messages for analogous error conditions. For consistency, _handle_config should handle the invalid-extension and file-not-found cases with print() + sys.exit(1) instead of bare raise/assert.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants