Fix: Skip ipython directive execution inside excluded only blocks#15249
Open
w1ndcn wants to merge 2 commits into
Open
Fix: Skip ipython directive execution inside excluded only blocks#15249w1ndcn wants to merge 2 commits into
w1ndcn wants to merge 2 commits into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #9339
Problem
The
ipythonSphinx directive executes code at the parse stage. When wrapped in a conditional directive likeonlywith a false condition for the current builder, the code still runs:Building with
htmlbuilder — theonly:: latexcondition is false, yetdangerous_operation()still executes. This is because Sphinx'sonlydirective evaluates conditions at the post-transform stage, after all child directiverun()methods have already been called.Fix
Add
_is_inside_excluded_only()toIPythonDirective. It walks up the parent node chain viaself.state.parent, and if any ancestor is anonlynode whose expression evaluates to false for the current builder's tags, returnsTrue. When true,run()returns[]early without executing code or calling setup/teardown.Key insight: during
nested_parseinsideOnly.run(), theonlynode is set as the parent in the docutils state machine, soself.state.parentis directly theonlynode — no fragile heuristics needed.Changes
IPython/sphinxext/ipython_directive.pyIPythonDirective._is_inside_excluded_only(): walks parent chain, evaluatesonlynode expressions againstenv.app.tagsIPythonDirective.run(): early return when inside an excludedonlyblocktests/test_ipython_directive.py(new)test_only_excluded_skips_execution:only:: latexunder html builder → code not executedtest_only_included_executes_normally:only:: htmlunder html builder → code executedtest_nested_only_skips_execution: nestedonly:: html>only:: latex→ inner block skipped