googleapis / googleapis/python-genai

TypeError in convert_if_exist_pydantic_model with parameterized generic types

Open
#2,013 4 comments 0 reactions 1 assignee Claimed by @Venkaiahbabuneelam View on GitHub
type: bug type: feature request
Dominant language
Python
Stars
4k
Forks
1k
Avg merge
2d 11h
Merged PRs (30d)
40

Description

## Description

When automatic function calling processes a function with a parameterized generic type annotation (e.g., `set[str]`), the SDK raises `TypeError: isinstance() argument 2 cannot be a parameterized generic`.

### Note

Apologies, my agent posted before I got to review this, but it seems mostly fine.

## Minimal Reproduction

```python
from google.genai._extra_utils import convert_if_exist_pydantic_model

# Simulating what happens when Gemini returns a value for a set[str] parameter
result = convert_if_exist_pydantic_model(
value=['a', 'b'], # Gemini returns list (JSON array)
annotation=set[str], # But annotation is set[str]
param_name='items',
func_name='my_func'
)
# TypeError: isinstance() argument 2 cannot be a parameterized generic
```

## Cause

In `_extra_utils.py`, the function `convert_if_exist_pydantic_model()` has two locations where `isinstance()` is called with an annotation that could be a `GenericAlias`:

**Line 257** (inside Union handling):
```python
or isinstance(value, arg)
```

**Line 279** (final fallback):
```python
if not isinstance(value, annotation):
```

In Python, `isinstance(x, set[str])` raises `TypeError` because `set[str]` is a `GenericAlias`, not a type. The SDK correctly handles `list[T]` and `dict[K,V]` with special cases using `get_origin()`, but other parameterized generics fall through to the raw `isinstance()` call.

## Affected Versions

- google-genai 1.60.0
- google-genai 1.61.0

## Environment

- Python 3.12
- Linux

## Proposed Fix

Add a helper function that safely handles parameterized generics:

```python
def _safe_isinstance(value: Any, annotation: Any) -> bool:
"""Check isinstance, handling GenericAlias types like set[str]."""
origin = get_origin(annotation)
if origin is not None:
return isinstance(value, origin)
try:
return isinstance(value, annotation)
except TypeError:
return False
```

Then replace:
- Line 257: `isinstance(value, arg)` → `_safe_isinstance(value, arg)`
- Line 279: `isinstance(value, annotation)` → `_safe_isinstance(value, annotation)`

This follows the same pattern already used for `list[T]` and `dict[K,V]` at lines 239 and 245.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.