fix(client): prevent ClientFactory.create() from mutating shared config extensions#859
fix(client): prevent ClientFactory.create() from mutating shared config extensions#859matanweks wants to merge 1 commit intoa2aproject:mainfrom
ClientFactory.create() from mutating shared config extensions#859Conversation
…ig extensions When `create()` was called with per-client extensions, the merged list was written back to `self._config.extensions`, permanently mutating the shared config. Extensions would silently accumulate across calls. Use `dataclasses.replace()` to create a per-call config copy instead of mutating the original, matching the immutability pattern from a2aproject#744. Fixes a2aproject#858
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 addresses a critical bug where the Highlights
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 effectively resolves a critical bug where ClientFactory.create() mutated the shared configuration's extensions, leading to unintended accumulation across multiple calls. The solution, which involves using dataclasses.replace() to create an immutable, per-call configuration copy, is robust and aligns with best practices for immutability. The addition of a regression test is excellent, as it verifies the fix and prevents future regressions. The changes are correct and well-implemented. I have one minor suggestion to improve the conciseness of the code by using a ternary operator.
| @@ -239,15 +240,20 @@ def create( | |||
| all_extensions = self._config.extensions.copy() | |||
There was a problem hiding this comment.
While the current implementation correctly fixes the mutation bug, the logic for creating the per-call configuration can be simplified for better readability and conciseness. For consistency, prefer using a conditional expression (ternary operator) for this assignment over an if/else block, as per repository guidelines.
config = dataclasses.replace(self._config, extensions=self._config.extensions + extensions) if extensions else self._configReferences
- For consistency, prefer using conditional expressions (ternary operators) for simple assignments over if/else blocks.
🧪 Code Coverage (vs
|
| Base | PR | Delta | |
|---|---|---|---|
| src/a2a/client/client_factory.py | 89.09% | 91.82% | 🟢 +2.73% |
| Total | 91.73% | 91.79% | 🟢 +0.06% |
Generated by coverage-comment.yml
ClientFactory.create() from mutating shared config extensions
Summary
ClientFactory.create()was mutatingself._config.extensionswhen called with per-client extensions, causing extensions to silently accumulate across calls.dataclasses.replace()to create a per-call config copy instead of mutating the sharedClientConfig. This matches the immutability pattern from fix: use default_factory for mutable field defaults in ServerCallContext #744.config.extensionsremains unchanged after multiplecreate()calls with different extensions.Fixes #858
Test plan
test_client_factory_create_does_not_mutate_config_extensionsverifies no mutationtest_client_factory.pytests passruff checkandruff formatpassmypypasses with no issues