Skip to content

fix(python): support withitem __enter__ call#47

Open
CrackTC wants to merge 1 commit intoantgroup:mainfrom
CrackTC:fix/python-withitem
Open

fix(python): support withitem __enter__ call#47
CrackTC wants to merge 1 commit intoantgroup:mainfrom
CrackTC:fix/python-withitem

Conversation

@CrackTC
Copy link
Contributor

@CrackTC CrackTC commented Jan 20, 2026

Note

Adds proper handling for Python with items.

  • Implements visit_withitem to call __enter__() on context_expr and initialize optional_vars via a VariableDeclaration
  • Replaces direct use of context_expr with a CallExpression to __enter__(); returns Noop when no optional_vars

Written by Cursor Bugbot for commit 1f5ca17. This will update automatically on new commits. Configure here.

@gemini-code-assist
Copy link

Summary of Changes

Hello @CrackTC, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a parsing inaccuracy in the Python UAST visitor concerning with statements. It ensures that when a withitem has optional variables, the __enter__ method of the context manager is explicitly invoked and represented in the generated UAST, aligning the UAST more closely with Python's runtime behavior for context managers.

Highlights

  • Correct withitem UAST generation: The visit_withitem method in the Python UAST visitor has been updated to correctly generate the Universal Abstract Syntax Tree (UAST) for with statements. Previously, it directly used the context expression; now, it explicitly creates a MemberAccess for the __enter__ method and wraps it in a CallExpression to ensure the context manager's entry point is properly represented in the UAST when optional variables are present.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request correctly adds support for the __enter__ call in with statements that use an as clause. However, it misses the case where a with statement is used without an as clause, where the __enter__ method should still be called for its side effects. I've provided a suggestion that handles both cases correctly and also improves the readability of the code.

Comment on lines +912 to 926
def visit_withitem(self, node):
if node.optional_vars is not None:
enter = UNode.MemberAccess(UNode.SourceLocation(), UNode.Meta(),
self.packPos(node.context_expr, self.visit(node.context_expr)),
UNode.Identifier(UNode.SourceLocation(), UNode.Meta(), "__enter__"))

call = UNode.CallExpression(UNode.SourceLocation(), UNode.Meta(),
self.packPos(node.context_expr, enter), [])

return UNode.VariableDeclaration(UNode.SourceLocation(), UNode.Meta(),
self.packPos(node.optional_vars, self.visit(node.optional_vars)),
self.packPos(node.context_expr, self.visit(node.context_expr)), False,
self.packPos(node.context_expr, call), False,
UNode.DynamicType(UNode.SourceLocation(), UNode.Meta()))
else:
return UNode.Noop(UNode.SourceLocation(), UNode.Meta())

Choose a reason for hiding this comment

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

high

The current implementation correctly handles with <expr> as <var>: by generating a call to __enter__. However, it doesn't handle with <expr>: (without an as clause). In this case, __enter__ should still be called, but its return value is discarded. The current code returns a Noop, which is incorrect.

I've provided a suggestion that fixes this by moving the __enter__ call logic outside the if condition. The else branch now wraps this call in an ExpressionStatement to indicate it's called for its side effects. This change also improves readability by breaking down the complex node creation and location packing.

Suggested change
def visit_withitem(self, node):
if node.optional_vars is not None:
enter = UNode.MemberAccess(UNode.SourceLocation(), UNode.Meta(),
self.packPos(node.context_expr, self.visit(node.context_expr)),
UNode.Identifier(UNode.SourceLocation(), UNode.Meta(), "__enter__"))
call = UNode.CallExpression(UNode.SourceLocation(), UNode.Meta(),
self.packPos(node.context_expr, enter), [])
return UNode.VariableDeclaration(UNode.SourceLocation(), UNode.Meta(),
self.packPos(node.optional_vars, self.visit(node.optional_vars)),
self.packPos(node.context_expr, self.visit(node.context_expr)), False,
self.packPos(node.context_expr, call), False,
UNode.DynamicType(UNode.SourceLocation(), UNode.Meta()))
else:
return UNode.Noop(UNode.SourceLocation(), UNode.Meta())
def visit_withitem(self, node):
context_uast = self.packPos(node.context_expr, self.visit(node.context_expr))
enter_access = UNode.MemberAccess(UNode.SourceLocation(), UNode.Meta(),
context_uast,
UNode.Identifier(UNode.SourceLocation(), UNode.Meta(), "__enter__"))
self.packPos(node.context_expr, enter_access)
enter_call = UNode.CallExpression(UNode.SourceLocation(), UNode.Meta(), enter_access, [])
self.packPos(node.context_expr, enter_call)
if node.optional_vars is not None:
return UNode.VariableDeclaration(UNode.SourceLocation(), UNode.Meta(),
self.packPos(node.optional_vars, self.visit(node.optional_vars)),
enter_call, False,
UNode.DynamicType(UNode.SourceLocation(), UNode.Meta()))
else:
return self.packPos(node, UNode.ExpressionStatement(UNode.SourceLocation(), UNode.Meta(), enter_call))

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.

1 participant