Skip to content

fix(utils): Preserve decorated type for @experimental and @working_in_progress#6030

Closed
Jacksunwei wants to merge 1 commit into
mainfrom
fix/experimental-typing
Closed

fix(utils): Preserve decorated type for @experimental and @working_in_progress#6030
Jacksunwei wants to merge 1 commit into
mainfrom
fix/experimental-typing

Conversation

@Jacksunwei

Copy link
Copy Markdown
Collaborator

Summary

The feature decorators (@experimental, @working_in_progress) were typed as returning Any, so any class or function they decorated (e.g. BaseEnvironment) was seen as Any by type checkers. This erased the base class, producing spurious "no base method present" errors on every @override in subclasses (LocalEnvironment, and any future subclass).

This adds a _FeatureDecorator Protocol with @overload signatures so the decorators preserve the decorated object's type across all three call forms — @experimental, @experimental(), @experimental("msg") — for both classes and functions.

Impact

  • BaseEnvironment now resolves as type[BaseEnvironment] instead of Any.
  • LocalEnvironment's 6 spurious @override errors drop to 0 (verified with pyright).
  • Runtime behavior is unchanged: warnings still fire, class names and callability are preserved.

Test plan

  • pytest tests/unittests/utils/test_feature_decorator.py (17 passed)
  • pytest tests/unittests/features/test_feature_decorator.py (11 passed)
  • pyright src/google/adk/utils/feature_decorator.py — 0 errors
  • Verified LocalEnvironment override errors went 6 → 0

…_progress

The feature decorators were typed as returning Any, so any class or
function decorated with @experimental (e.g. BaseEnvironment) was seen as
Any by type checkers. This erased the base class, causing spurious
'no base method present' errors on every @OverRide in subclasses.

Add @overload signatures so the decorators preserve the decorated
object's type across all three call forms (@experimental,
@experimental(), @experimental('msg')) for both classes and functions.
@adk-bot

adk-bot commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

🔍 ADK Pull Request Analysis: PR #6030

Title: fix(utils): Preserve decorated type for @experimental and @working_in_progress
Author: @Jacksunwei
Status: open
Impact: 25 additions, 2 deletions across 1 files

Executive Summary

  1. Core Objective: Correctly preserve decorated class and function types for @experimental and @working_in_progress decorators instead of erasing them to Any during static analysis.
  2. Justification & Value: [Justified Fix] - This is a critical typing fix that restores full static analysis checks, autocompletion support, and IDE discoverability across the entire codebase, eliminating spurious typing warnings on subclass method overrides.
  3. Alignment with Principles: [Pass with Nits] - Employs a private typing Protocol with @overload signatures to elegantly preserve types across multiple call forms, conforming fully to ADK's strict type-safety standards, with a minor style nit on using modern union syntax.
  4. Recommendation: Approve with Nits (minor typing style adjustments).
Detailed Findings & Analysis

1. Objectives & Impact ("What does it do?")

  • Context & Background: In ADK development, features under active enhancement or validation are wrapped with @experimental or @working_in_progress. However, because these decorators were return-typed as Callable[..., Any], they stripped all static typing from their annotated targets, leading to false downstream diagnostics (such as Pyright reporting "no base method present" on methods annotated with @override in subclasses).
  • Implementation Mechanism: The PR introduces _FeatureDecorator as a private Protocol in feature_decorator.py with structured @overload signatures targeting bare decorator vs argument-taking invocations. _make_feature_decorator is then adjusted to return _FeatureDecorator, maintaining full static integrity.
  • Affected Surface: No runtime execution path is altered. Static analysis metadata is successfully improved for dozens of classes/functions decorated across the core google.adk codebase, particularly classes inheriting from decorated parents.

2. Justification & Value ("Is it a valid and useful change?")

  • Workspace Verification:
    • Investigated feature_decorator.py and saw that _make_feature_decorator originally returned Callable[..., Any], causing decorated objects (classes and functions) to resolve to Any.
    • Investigated _base_environment.py and confirmed that BaseEnvironment is decorated with @experimental. Because of this decorator, BaseEnvironment's baseline type became Any according to static analysis tools like Pyright and Mypy. Thus, any subclasses, such as those in _local_environment.py, using @override would trigger false-positive warnings because the static type analyzer couldn't find base functions to match against.
  • Value Assessment: Highly valuable. Spurious type warnings create developer friction, obstruct authentic compiler errors, and decrease IDE productivity.
  • Alternative Approaches: Defining structural Protocol overloads is the most robust, standard PEP-484 pattern to support both types of decorator syntax signatures without runtime wrappers.
  • Scope & Depth: [Systematic Fix] & [Root Cause] - This elegantly corrects the issue for any and all uses of the framework's decorators instead of putting point-fixes or ignores in subclass methods.

3. Principle & Style Alignment Checklist ("Does it follow rules?")

  • Public API & Visibility Boundaries:
    • Status: Pass
    • Analysis: No breaking changes to the public API are made. The _FeatureDecorator protocol class remains fully private (prefixed with _). No internal constructs leak.
  • Code Quality, Typing & Conventions:
    • Status: Nits
    • Analysis: Excellent use of typing primitives and generics (T) to ensure exact static resolution.
    • Nit: In the added overload signature:
      def __call__(self, message_or_obj: Optional[str] = ...) -> Callable[[T], T]:
      Modern Python union type str | None is strongly preferred over legacy Optional[str] per ADK styling rules.
  • Robustness & Edge Cases:
    • Status: Pass
    • Analysis: Accurately models bare decorators, empty parenthesis calls, and fully-custom messaging options across classes and callables.
  • Test Integrity & Quality:
    • Status: Pass
    • Analysis: Existing unit tests in test_feature_decorator.py provide extensive branch and error-handling coverage, while remote integration checks confirm that

copybara-service Bot pushed a commit that referenced this pull request Jun 9, 2026
…_progress

Merge #6030

## Summary

The feature decorators (`@experimental`, `@working_in_progress`) were typed as returning `Any`, so any class or function they decorated (e.g. `BaseEnvironment`) was seen as `Any` by type checkers. This erased the base class, producing spurious `"no base method present"` errors on every `@override` in subclasses (`LocalEnvironment`, and any future subclass).

This adds a `_FeatureDecorator` `Protocol` with `@overload` signatures so the decorators preserve the decorated object's type across all three call forms — `@experimental`, `@experimental()`, `@experimental("msg")` — for both classes and functions.

## Impact

- `BaseEnvironment` now resolves as `type[BaseEnvironment]` instead of `Any`.
- `LocalEnvironment`'s 6 spurious `@override` errors drop to 0 (verified with pyright).
- Runtime behavior is unchanged: warnings still fire, class names and callability are preserved.

## Test plan

- [x] `pytest tests/unittests/utils/test_feature_decorator.py` (17 passed)
- [x] `pytest tests/unittests/features/test_feature_decorator.py` (11 passed)
- [x] `pyright src/google/adk/utils/feature_decorator.py` — 0 errors
- [x] Verified `LocalEnvironment` override errors went 6 → 0

Co-authored-by: Wei Sun (Jack) <weisun@google.com>
COPYBARA_INTEGRATE_REVIEW=#6030 from google:fix/experimental-typing 5bdb8a4
PiperOrigin-RevId: 929281312
@adk-bot

adk-bot commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Thank you @Jacksunwei for your contribution! 🎉

Your changes have been successfully imported and merged via Copybara in commit 1ff0158.

Closing this PR as the changes are now in the main branch.

@adk-bot adk-bot added the merged [Status] This PR is merged label Jun 9, 2026
@adk-bot adk-bot closed this Jun 9, 2026
copybara-service Bot pushed a commit that referenced this pull request Jun 9, 2026
…_progress

Merge #6030

## Summary

The feature decorators (`@experimental`, `@working_in_progress`) were typed as returning `Any`, so any class or function they decorated (e.g. `BaseEnvironment`) was seen as `Any` by type checkers. This erased the base class, producing spurious `"no base method present"` errors on every `@override` in subclasses (`LocalEnvironment`, and any future subclass).

This adds a `_FeatureDecorator` `Protocol` with `@overload` signatures so the decorators preserve the decorated object's type across all three call forms — `@experimental`, `@experimental()`, `@experimental("msg")` — for both classes and functions.

## Impact

- `BaseEnvironment` now resolves as `type[BaseEnvironment]` instead of `Any`.
- `LocalEnvironment`'s 6 spurious `@override` errors drop to 0 (verified with pyright).
- Runtime behavior is unchanged: warnings still fire, class names and callability are preserved.

## Test plan

- [x] `pytest tests/unittests/utils/test_feature_decorator.py` (17 passed)
- [x] `pytest tests/unittests/features/test_feature_decorator.py` (11 passed)
- [x] `pyright src/google/adk/utils/feature_decorator.py` — 0 errors
- [x] Verified `LocalEnvironment` override errors went 6 → 0

PiperOrigin-RevId: 929389871
copybara-service Bot pushed a commit that referenced this pull request Jun 9, 2026
Merge #6031

> **Stacked on #6030** (`fix/experimental-typing`). This PR targets that branch; please review/merge #6030 first, after which this will be retargeted to `main`.

## Summary

Adds `E2BEnvironment`, a `BaseEnvironment` backed by an [E2B](https://e2b.dev) sandbox. It gives agents a persistent remote workspace for shell execution, file CRUD, and on-demand installs (`pip`/`apt`) without touching the host machine.

- The sandbox TTL is bounded to cap credit usage and is extended on each operation; an expired idle sandbox is transparently recreated.
- Lazy-imports the SDK behind a new `e2b` extra, so the base package stays lean.
- Includes a data-analysis sample that downloads a public (GCS-hosted) dataset and analyzes it inside the sandbox.

## Usage

```python
from google.adk.integrations.e2b import E2BEnvironment
from google.adk.tools.environment import EnvironmentToolset

toolset = EnvironmentToolset(environment=E2BEnvironment())
```

## Test plan

- [x] `pytest tests/unittests/integrations/e2b/` (14 passed)
- [x] `pyright src/google/adk/integrations/e2b/_e2b_environment.py` — 0 errors
- [x] Sample agent loads (`contributing/samples/environment_and_skills/e2b_environment`)
- [ ] Manual run against a live E2B sandbox (requires `E2B_API_KEY`)

Co-authored-by: Wei Sun (Jack) <weisun@google.com>
COPYBARA_INTEGRATE_REVIEW=#6031 from google:feat/e2b f2b5584
PiperOrigin-RevId: 929443164
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merged [Status] This PR is merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants