Repository navigation
Conversation
`save('name')` was meant to add a query to the queries written by the CLI
(`queries_to_save`), like writing the query name on its own line. It never
worked: `visit_Call` tested `isinstance(node.args, ast.Constant)` on the
argument list, and `visit_Expr` rejected bare calls before `visit_Call`
was reached.
Handle `save('name')` as a statement in `visit_Expr`, next to the bare
name case it mirrors. Unlike a bare name it also accepts dotted names such
as `save('cst.left')`, for queries defined with `|=`. An unknown name
raises the same error as an unknown bare name, and `x = save(...)` is still
rejected.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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.
What was wrong
EvaluateQueries.visit_Callhas asave('name')branch. It has been there since 5cd2746 (2012, "Added outlier rejection and the interactive shell"), but it has never worked:isinstance(node.args, ast.Constant), andnode.argsis a list, so the branch is never taken;visit_Exprrejects bare calls beforevisit_Callis reached.On master,
a |= 1/save('a')fails withInvalid expression at line: 2.What
savewas meant to doThe CLI writes one output file per name in
EvaluateQueries.queries_to_save, whicheval_queriesreturns. A name gets intoqueries_to_savein two ways:name = <query>evaluates the query and adds it;nameadds an already evaluated query.name |= <query>evaluates the query without adding it, for intermediate results.The dead branch only did
self.queries_to_save.add(<string>). Sosave('name')was meant to be a third way to request an evaluated query for output. Unlike a bare name, it also works for dotted names:visit_Expronly acceptsast.Name, socst.leftalone on a line is rejected. Withsave, a query defined ascst.side |= ...can be written withsave('cst.left').Change (option A: fix, this PR)
visit_Call.visit_Expr, acceptsave('<name>')(exactly one string argument) next to the bare-name case. It uses the same lookup and the sameQuery X not known line: Nerror for unknown names.saveis only valid as a statement:x = save('a')is still rejected withInvalid query in line N. Names are matched after preprocessing, so they are case-insensitive like everything else in WMQL. Glob patterns are not expanded.Behaviour change:
save('name')lines that used to fail now work. Nothing else changes.Not changed: in the interactive shell (
--interactive),save('a')is now accepted but does not write a file. The shell writes queries through its ownSaveQueriesvisitor and itssave <name>command, not throughqueries_to_save. Writing files from the shell would need about 3 more lines inSaveQueries.visit_Expr.Option B: remove instead
If you would rather not have a second way to do what a bare name does, the alternative is to delete the six dead lines in
visit_Call(theelif ... 'save'branch) and keepsave(...)an error. I chose the fix because the semantics are unambiguous from the code (add the name toqueries_to_save), it is small, and it fills a real gap: saving dotted|=queries.saveis not documented and no packaged.qryfile uses it, so either choice is safe.Testing
test_save_queryintract_querier/tests/test_query_eval.py. It checks thatA |= 0; B.left |= 1; C |= 0; A; save('B.left')returns exactly{a, b.left}, and thatsave('B')(unknown query) andX = save('A')raiseTractQuerierSyntaxError. It fails on master withInvalid expression at line: 5.python -m pytest -q -p no:cacheprovider tract_querier: 43 passed, 1 skipped.Merge order: touches
visit_Call/visit_Exprinquery_processor.py, as do #133 (#103:visit_Attribute,visit_For, relative terms) and #139 (#115: thestarargslines invisit_Call). Expect textual conflicts at most.Closes #104
🤖 Generated with Claude Code