Skip to content

♻️ refactor(logic): improve error handling and reduce duplication#286

Merged
gaborbernat merged 2 commits intotox-dev:mainfrom
gaborbernat:main
Mar 2, 2026
Merged

♻️ refactor(logic): improve error handling and reduce duplication#286
gaborbernat merged 2 commits intotox-dev:mainfrom
gaborbernat:main

Conversation

@gaborbernat
Copy link
Member

When users misconfigure the :module: or :func: directive options, the extension produced raw Python tracebacks (ImportError, AttributeError) that gave no indication of what went wrong or how to fix it. 🔐 This is especially confusing for new users who may not realize the error originates from their RST configuration rather than a bug in the extension.

The dynamic import is now wrapped with explicit error handling that surfaces clear messages through Sphinx's warning system, e.g. Failed to import module 'foo' or Module 'foo' has no attribute 'bar'. A subtle sys.modules leak on the AttributeError path was also fixed — when the module imported successfully but the function wasn't found, the stale module entry remained cached, which could cause the wrong parser to load in subsequent directive invocations within the same process.

♻️ The duplicated prefix resolution logic between _build_opt_grp_title and _build_sub_cmd_title has been consolidated into a shared _resolve_prefix method. Both methods had near-identical branching for combining title_prefix, sub_title_prefix, and program name, but diverged in small ways that made independent maintenance error-prone. A redundant _strip_ansi_colors call was also eliminated — _mk_sub_command already strips ANSI from parser.prog before passing it to _build_sub_cmd_title, which was stripping it again.

The coverage threshold has been raised from 76% to 100% to match actual coverage and prevent silent regressions. Additional test fixtures exercise previously untested argparse features (nargs variants, choices, action="count", action="append", required=True) and both error paths for bad module/function references.

The dynamic import of user-specified modules produced raw Python tracebacks
(ImportError, AttributeError) when users misconfigured :module: or :func:
directive options. Wrapping these with explicit error messages surfaces the
problem clearly in Sphinx's warning output. The module cleanup on the
AttributeError path also prevents stale sys.modules entries from causing
cross-test contamination when the same generic module name is reused.

The duplicated prefix resolution logic between _build_opt_grp_title and
_build_sub_cmd_title was fragile to maintain independently. Extracting
_resolve_prefix consolidates the branching into one place.

Coverage threshold was at 76% while actual coverage sat at ~99.7%, allowing
significant regressions to pass unnoticed. Raised to 100% and added tests
for previously uncovered argparse features (nargs, choices, count/append
actions) and error paths.
@gaborbernat gaborbernat added the enhancement New feature or request label Mar 2, 2026
After consolidating the ANSI stripping into _mk_sub_command's
version guard, the stripped parameter in _build_sub_cmd_title
became dead code — its only caller always passed stripped=True.
This left _strip_ansi_colors unreachable on Python <3.14, failing
coverage on those versions.
@gaborbernat gaborbernat merged commit 0790dd2 into tox-dev:main Mar 2, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant