feat: with bigfoot: context manager shorthand (v0.4.1)#3
Conversation
Add module-level context manager support so `with bigfoot:` and `async with bigfoot:` serve as shorthand for the sandbox() call. Both forms return the active StrictVerifier from __enter__, enabling `with bigfoot as v:` for direct verifier access when needed. Update all documentation, guides, and README to use the new syntax. Bump version to 0.4.1.
Summary of ChangesHello, 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 significantly enhances the usability of the Highlights
🧠 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. Changelog
Activity
Using Gemini Code AssistThe 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
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 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
|
There was a problem hiding this comment.
Code Review
This pull request introduces a convenient shorthand, with bigfoot:, for the sandbox context manager, which is a great enhancement for the library's usability. The implementation is clever, using sys.modules[__name__].__class__ to make the module itself a context manager. The changes are thoroughly documented and well-tested. My feedback includes a minor refactoring suggestion for the core implementation in _BigfootModule to improve code clarity and reduce duplication.
| class _BigfootModule(types.ModuleType): | ||
| """ModuleType subclass that makes ``bigfoot`` usable as a context manager. | ||
|
|
||
| ``with bigfoot:`` is equivalent to ``with bigfoot.sandbox():``. | ||
| ``async with bigfoot:`` is equivalent to ``async with bigfoot.sandbox():``. | ||
| Both forms return the active :class:`StrictVerifier` from ``__enter__``. | ||
| """ | ||
|
|
||
| def __enter__(self) -> StrictVerifier: | ||
| cm = sandbox() | ||
| stack = _sandbox_stack.__dict__.setdefault("stack", []) | ||
| stack.append(cm) | ||
| return cm.__enter__() | ||
|
|
||
| def __exit__( | ||
| self, | ||
| exc_type: type[BaseException] | None, | ||
| exc_val: BaseException | None, | ||
| exc_tb: object, | ||
| ) -> None: | ||
| _sandbox_stack.stack.pop().__exit__(exc_type, exc_val, exc_tb) | ||
|
|
||
| async def __aenter__(self) -> StrictVerifier: | ||
| cm = sandbox() | ||
| stack = _sandbox_stack.__dict__.setdefault("stack", []) | ||
| stack.append(cm) | ||
| return await cm.__aenter__() | ||
|
|
||
| async def __aexit__( | ||
| self, | ||
| exc_type: type[BaseException] | None, | ||
| exc_val: BaseException | None, | ||
| exc_tb: object, | ||
| ) -> None: | ||
| await _sandbox_stack.stack.pop().__aexit__(exc_type, exc_val, exc_tb) | ||
|
|
There was a problem hiding this comment.
The __enter__ and __aenter__ methods contain duplicated logic for creating and pushing the sandbox context manager onto the stack. This can be refactored into a helper method to improve maintainability and reduce code duplication. Additionally, using hasattr to check for the stack's existence is more idiomatic and readable than accessing __dict__ directly.
class _BigfootModule(types.ModuleType):
"""ModuleType subclass that makes ``bigfoot`` usable as a context manager.
``with bigfoot:`` is equivalent to ``with bigfoot.sandbox():``.
``async with bigfoot:`` is equivalent to ``async with bigfoot.sandbox():``.
Both forms return the active :class:`StrictVerifier` from ``__enter__``.
"""
def _push_cm(self) -> SandboxContext:
"""Create a new sandbox context, push it to the thread-local stack, and return it."""
cm = sandbox()
if not hasattr(_sandbox_stack, "stack"):
_sandbox_stack.stack = []
_sandbox_stack.stack.append(cm)
return cm
def __enter__(self) -> StrictVerifier:
return self._push_cm().__enter__()
def __exit__(
self,
exc_type: type[BaseException] | None,
exc_val: BaseException | None,
exc_tb: object,
) -> None:
_sandbox_stack.stack.pop().__exit__(exc_type, exc_val, exc_tb)
async def __aenter__(self) -> StrictVerifier:
return await self._push_cm().__aenter__()
async def __aexit__(
self,
exc_type: type[BaseException] | None,
exc_val: BaseException | None,
exc_tb: object,
) -> None:
await _sandbox_stack.stack.pop().__aexit__(exc_type, exc_val, exc_tb)
Summary
_BigfootModule(types.ModuleType)subclass with__enter__/__exit__/__aenter__/__aexit__and applies it viasys.modules[__name__].__class__ = _BigfootModulewith bigfoot:andasync with bigfoot:are now shorthand forwith bigfoot.sandbox():/async with bigfoot.sandbox():StrictVerifierfrom__enter__, sowith bigfoot as v:gives direct verifier access (e.g. for registering custom plugins manually)threading.localLIFO stack for correct nested sandbox trackingwith bigfoot:syntax throughoutTest plan
test_bigfoot_module_is_context_manager— syncwith bigfoot as v:returnsStrictVerifier, mock/assert works insidetest_bigfoot_module_is_async_context_manager— async form works identicallytest_bigfoot_nested_sandboxes_via_with_bigfoot— nestedwith bigfoot:blocks share the same verifier without interference