Bug Report
I tried to use the wrapt.function_wrapper on google.genai.models.Models.edit_image and saw a TypeError exception. Here's a minimal reproducer, since google-genai is a large package.
# /// script
# requires-python = ">=3.9"
# dependencies = [
# "wrapt>=2.1.2",
# ]
# ///
import wrapt
@wrapt.function_wrapper
def passthrough(wrapped, instance, args, kwargs):
return wrapped(*args, **kwargs)
def f(*, a: list[int]) -> list[int]:
return a
def list():
return
f = passthrough(f)
Here's the output from running the script. This only reproduces with the C extension disabled.
> uv run -p 3.14 repro.py
Installed 1 package in 1ms
Traceback (most recent call last):
File "/Users/jamesroberts/Projects/repro.py", line 23, in <module>
f = passthrough(f)
File "/Users/jamesroberts/.cache/uv/environments-v2/repro-737eeeff054c4226/lib/python3.14/site-packages/wrapt/wrappers.py", line 755, in __call__
return self._self_wrapper(self.__wrapped__, self._self_instance, args, kwargs)
~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/jamesroberts/.cache/uv/environments-v2/repro-737eeeff054c4226/lib/python3.14/site-packages/wrapt/patches.py", line 166, in _wrapper
return FunctionWrapper(target_wrapped, target_wrapper)
File "/Users/jamesroberts/.cache/uv/environments-v2/repro-737eeeff054c4226/lib/python3.14/site-packages/wrapt/wrappers.py", line 984, in __init__
super(FunctionWrapper, self).__init__(wrapped, None, wrapper, enabled, binding)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/jamesroberts/.cache/uv/environments-v2/repro-737eeeff054c4226/lib/python3.14/site-packages/wrapt/wrappers.py", line 629, in __init__
super(_FunctionWrapperBase, self).__init__(wrapped)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
File "/Users/jamesroberts/.cache/uv/environments-v2/repro-737eeeff054c4226/lib/python3.14/site-packages/wrapt/wrappers.py", line 124, in __init__
object.__setattr__(self, "__annotations__", wrapped.__annotations__)
^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/jamesroberts/Projects/repro.py", line 15, in __annotate__
def f(*, a: list[int]) -> list[int]:
~~~~^^^^^
TypeError: 'function' object is not subscriptable
The script exits successfully in Python 3.13 and earlier.
Investigation
A big change in Python 3.14 is deferred evaluation of annotations. I found a variety of resources explaining this change, including the release notes, a HOWTO article, a new annotationslib library for supporting annotations, and a third party RealPython article. From the RealPython article, the section on data descriptors was useful: https://realpython.com/python-annotations/#annotations-as-data-descriptors . In it, they explain the default behavior in Python 3.14 when accessing __annotations__ is to call the object's __annotate__ attribute with the VALUE format, which evaluates annotations to runtime values, similar to the behavior in earlier Python versions. In the reproducer script, list is defined after f, but before the function_wrapper is applied. When the function_wrapper is called on f, f.__annotations__ resolves list to the local function and raises an error when evaluating the subscript operation.
Possible fix
It doesn't seem safe for wrapt to access the __annotations__ attribute in 3.14+. In the CPython PR that added this change, functools.wraps is updated to copy the wrapped callable's __annotate__ attribute onto the wrapper instance. I think applying the same approach here for Python 3.14+ would be an improvement. There's at least one known gap with that solution though: python/cpython#124342, and I'm not sure whether that approach would cause issues with staticmethods, classmethods or other callables that wrapt supports.
Bug Report
I tried to use the
wrapt.function_wrapperongoogle.genai.models.Models.edit_imageand saw aTypeErrorexception. Here's a minimal reproducer, since google-genai is a large package.Here's the output from running the script. This only reproduces with the C extension disabled.
The script exits successfully in Python 3.13 and earlier.
Investigation
A big change in Python 3.14 is deferred evaluation of annotations. I found a variety of resources explaining this change, including the release notes, a HOWTO article, a new
annotationsliblibrary for supporting annotations, and a third party RealPython article. From the RealPython article, the section on data descriptors was useful: https://realpython.com/python-annotations/#annotations-as-data-descriptors . In it, they explain the default behavior in Python 3.14 when accessing__annotations__is to call the object's__annotate__attribute with theVALUEformat, which evaluates annotations to runtime values, similar to the behavior in earlier Python versions. In the reproducer script,listis defined afterf, but before the function_wrapper is applied. When the function_wrapper is called on f,f.__annotations__resolveslistto the local function and raises an error when evaluating the subscript operation.Possible fix
It doesn't seem safe for wrapt to access the
__annotations__attribute in 3.14+. In the CPython PR that added this change,functools.wrapsis updated to copy the wrapped callable's__annotate__attribute onto the wrapper instance. I think applying the same approach here for Python 3.14+ would be an improvement. There's at least one known gap with that solution though: python/cpython#124342, and I'm not sure whether that approach would cause issues with staticmethods, classmethods or other callables that wrapt supports.