Skip to content

Commit 2672733

Browse files
google-genai-botcopybara-github
authored andcommitted
ADK changes
PiperOrigin-RevId: 929392556
1 parent 30d1910 commit 2672733

3 files changed

Lines changed: 47 additions & 10 deletions

File tree

src/google/adk/environment/_base_environment.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,17 @@ class BaseEnvironment(ABC):
5858
4. Call ``close()`` when done.
5959
"""
6060

61+
_is_initialized: bool = False
62+
63+
@property
64+
def is_initialized(self) -> bool:
65+
"""Whether the environment has been initialized."""
66+
return self._is_initialized
67+
68+
@is_initialized.setter
69+
def is_initialized(self, value: bool) -> None:
70+
self._is_initialized = value
71+
6172
async def initialize(self) -> None:
6273
"""Initialize the environment (e.g. create working directory).
6374

src/google/adk/environment/_local_environment.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ def __init__(
5959
self._working_dir = working_dir
6060
self._env_vars = env_vars
6161
self._auto_created = False
62+
self._is_initialized = False
6263

6364
@property
6465
@override
@@ -75,13 +76,15 @@ async def initialize(self) -> None:
7576
logger.debug('Created temporary folder: %s', self._working_dir)
7677
else:
7778
os.makedirs(self._working_dir, exist_ok=True)
79+
self._is_initialized = True
7880

7981
@override
8082
async def close(self) -> None:
8183
if self._auto_created and self._working_dir:
8284
shutil.rmtree(self._working_dir, ignore_errors=True)
8385
logger.debug('Removed temporary workspace: %s', self._working_dir)
8486
self._working_dir = None
87+
self._is_initialized = False
8588

8689
@override
8790
async def execute(
@@ -138,21 +141,21 @@ async def write_file(self, path: str | Path, content: str | bytes) -> None:
138141
resolved = self._resolve_path(path)
139142
return await asyncio.to_thread(self._sync_write, resolved, content)
140143

141-
def _resolve_path(self, path: str | Path) -> str:
144+
def _resolve_path(self, path: str | Path) -> Path:
142145
"""Resolve a relative path against the working directory."""
143-
path = str(path)
144-
if os.path.isabs(path):
145-
return path
146-
return os.path.join(self._working_dir, path)
146+
path_obj = Path(path)
147+
if path_obj.is_absolute():
148+
return path_obj
149+
return self.working_dir / path_obj
147150

148151
@staticmethod
149-
def _sync_read(path: str) -> bytes:
152+
def _sync_read(path: Path) -> bytes:
150153
with open(path, 'rb') as f:
151154
return f.read()
152155

153156
@staticmethod
154-
def _sync_write(path: str, content: str | bytes) -> None:
155-
os.makedirs(os.path.dirname(path), exist_ok=True)
157+
def _sync_write(path: Path, content: str | bytes) -> None:
158+
os.makedirs(path.parent, exist_ok=True)
156159
mode = 'w' if isinstance(content, str) else 'wb'
157160
kwargs = {'encoding': 'utf-8'} if isinstance(content, str) else {}
158161
with open(path, mode, **kwargs) as f:

src/google/adk/utils/feature_decorator.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,35 @@
2020
from typing import Any
2121
from typing import cast
2222
from typing import Optional
23+
from typing import overload
24+
from typing import Protocol
2325
from typing import TypeVar
2426
import warnings
2527

2628
T = TypeVar("T")
2729

2830

31+
class _FeatureDecorator(Protocol):
32+
"""A feature decorator usable with or without a message argument.
33+
34+
Preserves the decorated object's type so that subclasses and type
35+
checkers continue to see the real class/function rather than ``Any``.
36+
"""
37+
38+
# @decorator (bare, on a class or function)
39+
@overload
40+
def __call__(self, message_or_obj: T) -> T:
41+
...
42+
43+
# @decorator() or @decorator("message")
44+
@overload
45+
def __call__(self, message_or_obj: Optional[str] = ...) -> Callable[[T], T]:
46+
...
47+
48+
def __call__(self, message_or_obj: Any = None) -> Any:
49+
...
50+
51+
2952
def _is_truthy_env(var_name: str) -> bool:
3053
value = os.environ.get(var_name)
3154
if value is None:
@@ -39,7 +62,7 @@ def _make_feature_decorator(
3962
default_message: str,
4063
block_usage: bool = False,
4164
bypass_env_var: Optional[str] = None,
42-
) -> Callable[..., Any]:
65+
) -> _FeatureDecorator:
4366
def decorator_factory(message_or_obj: Any = None) -> Any:
4467
# Case 1: Used as @decorator without parentheses
4568
# message_or_obj is the decorated class/function
@@ -57,7 +80,7 @@ def decorator_factory(message_or_obj: Any = None) -> Any:
5780
)
5881
return _create_decorator(message, label, block_usage, bypass_env_var)
5982

60-
return decorator_factory
83+
return cast(_FeatureDecorator, decorator_factory)
6184

6285

6386
def _create_decorator(

0 commit comments

Comments
 (0)