-
Notifications
You must be signed in to change notification settings - Fork 169
feat: add context manager to mrd #1724
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Summary of ChangesHello @chandra-siri, 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 introduces an asynchronous context manager for the Highlights
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.
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 introduces a convenient async context manager for AsyncMultiRangeDownloader, which is a great improvement for ensuring resources are properly managed. The implementation is correct and is accompanied by a new unit test and an update to a system test.
One suggestion for further improvement is to refactor the other system tests in tests/system/test_zonal.py that use AsyncMultiRangeDownloader to also adopt the new async with syntax. This would improve consistency and readability across the test suite.
I've also added a comment with suggestions to enhance the unit tests for the new context manager by covering some important edge cases.
| async def test_async_context_manager_calls_open_and_close( | ||
| self, mock_grpc_client, mock_close, mock_open | ||
| ): | ||
| # Arrange | ||
| mrd = AsyncMultiRangeDownloader( | ||
| mock_grpc_client, _TEST_BUCKET_NAME, _TEST_OBJECT_NAME | ||
| ) | ||
|
|
||
| # To simulate the behavior of open and close changing the stream state | ||
| async def open_side_effect(): | ||
| mrd._is_stream_open = True | ||
|
|
||
| async def close_side_effect(): | ||
| mrd._is_stream_open = False | ||
|
|
||
| mock_open.side_effect = open_side_effect | ||
| mock_close.side_effect = close_side_effect | ||
| mrd._is_stream_open = False | ||
|
|
||
| # Act | ||
| async with mrd as downloader: | ||
| # Assert | ||
| mock_open.assert_called_once() | ||
| assert downloader == mrd | ||
| assert mrd.is_stream_open | ||
|
|
||
| mock_close.assert_called_once() | ||
| assert not mrd.is_stream_open |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good test for the happy path of the async context manager. To make it more robust, it would be beneficial to also test the behavior in edge cases.
Specifically, consider adding tests for:
- When
open()fails (e.g., raises an exception). In this scenario,close()should not be called. - When an exception is raised from within the
async withblock. In this case,close()should still be called to ensure cleanup.
Here are some examples of how you could structure these tests:
Test for open() failure:
@mock.patch("...")
@pytest.mark.asyncio
async def test_context_manager_no_close_on_open_failure(self, mock_grpc_client, mock_close, mock_open):
mock_open.side_effect = ValueError("Failed to open")
mrd = AsyncMultiRangeDownloader(
mock_grpc_client, _TEST_BUCKET_NAME, _TEST_OBJECT_NAME
)
with pytest.raises(ValueError, match="Failed to open"):
async with mrd:
pytest.fail("This block should not be executed.")
mock_open.assert_called_once()
mock_close.assert_not_called()Test for exception within the block:
@mock.patch("...")
@pytest.mark.asyncio
async def test_context_manager_closes_on_exception(self, mock_grpc_client, mock_close, mock_open):
mrd = AsyncMultiRangeDownloader(
mock_grpc_client, _TEST_BUCKET_NAME, _TEST_OBJECT_NAME
)
# set up side effects for open/close as in the existing test
async def open_side_effect():
mrd._is_stream_open = True
mock_open.side_effect = open_side_effect
with pytest.raises(RuntimeError, match="Oops"):
async with mrd:
raise RuntimeError("Oops")
mock_open.assert_called_once()
mock_close.assert_called_once()
feat: add context manager to mrd