Skip to content

unittest.mock requests VALUE annotation format when calling inspect.signature #145755

@mschoettle

Description

@mschoettle

Bug report

Bug description:

unittest.mock calls inspect.signature which uses the default anntation_format argument value of annotationlib.Format.VALUE. This causes an exception at runtime when the signature contains type hints and a type is imported inside a TYPE_CHECKING block.

MRE:

from typing import TYPE_CHECKING
from unittest import mock

if TYPE_CHECKING:
    from typing import Tuple  # noqa: UP035

def foo(x: Tuple[int, ...]):
    pass

mock.create_autospec(foo)

Traceback:

Traceback (most recent call last):
  File "/Users/mschoettle/Documents/Development/mock_mre.py", line 10, in <module>
    mock.create_autospec(foo)
    ~~~~~~~~~~~~~~~~~~~~^^^^^
  File "/opt/homebrew/Cellar/python@3.14/3.14.3_1/Frameworks/Python.framework/Versions/3.14/lib/python3.14/unittest/mock.py", line 2818, in create_autospec
    mock = Klass(parent=_parent, _new_parent=_parent, _new_name=_new_name,
                 name=_name, **_kwargs)
  File "/opt/homebrew/Cellar/python@3.14/3.14.3_1/Frameworks/Python.framework/Versions/3.14/lib/python3.14/unittest/mock.py", line 2176, in __init__
    _safe_super(MagicMixin, self).__init__(*args, **kw)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/python@3.14/3.14.3_1/Frameworks/Python.framework/Versions/3.14/lib/python3.14/unittest/mock.py", line 1157, in __init__
    _safe_super(CallableMixin, self).__init__(
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
        spec, wraps, name, spec_set, parent,
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        _spec_state, _new_name, _new_parent, **kwargs
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/opt/homebrew/Cellar/python@3.14/3.14.3_1/Frameworks/Python.framework/Versions/3.14/lib/python3.14/unittest/mock.py", line 485, in __init__
    self._mock_add_spec(spec, spec_set, _spec_as_instance, _eat_self)
    ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/python@3.14/3.14.3_1/Frameworks/Python.framework/Versions/3.14/lib/python3.14/unittest/mock.py", line 547, in _mock_add_spec
    res = _get_signature_object(spec,
                                _spec_as_instance, _eat_self)
  File "/opt/homebrew/Cellar/python@3.14/3.14.3_1/Frameworks/Python.framework/Versions/3.14/lib/python3.14/unittest/mock.py", line 122, in _get_signature_object
    return func, inspect.signature(sig_func)
                 ~~~~~~~~~~~~~~~~~^^^^^^^^^^
  File "/opt/homebrew/Cellar/python@3.14/3.14.3_1/Frameworks/Python.framework/Versions/3.14/lib/python3.14/inspect.py", line 3322, in signature
    return Signature.from_callable(obj, follow_wrapped=follow_wrapped,
           ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                   globals=globals, locals=locals, eval_str=eval_str,
                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                   annotation_format=annotation_format)
                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/python@3.14/3.14.3_1/Frameworks/Python.framework/Versions/3.14/lib/python3.14/inspect.py", line 3037, in from_callable
    return _signature_from_callable(obj, sigcls=cls,
                                    follow_wrapper_chains=follow_wrapped,
                                    globals=globals, locals=locals, eval_str=eval_str,
                                    annotation_format=annotation_format)
  File "/opt/homebrew/Cellar/python@3.14/3.14.3_1/Frameworks/Python.framework/Versions/3.14/lib/python3.14/inspect.py", line 2512, in _signature_from_callable
    return _signature_from_function(sigcls, obj,
                                    skip_bound_arg=skip_bound_arg,
                                    globals=globals, locals=locals, eval_str=eval_str,
                                    annotation_format=annotation_format)
  File "/opt/homebrew/Cellar/python@3.14/3.14.3_1/Frameworks/Python.framework/Versions/3.14/lib/python3.14/inspect.py", line 2335, in _signature_from_function
    annotations = get_annotations(func, globals=globals, locals=locals, eval_str=eval_str,
                                  format=annotation_format)
  File "/opt/homebrew/Cellar/python@3.14/3.14.3_1/Frameworks/Python.framework/Versions/3.14/lib/python3.14/annotationlib.py", line 966, in get_annotations
    ann = _get_dunder_annotations(obj)
  File "/opt/homebrew/Cellar/python@3.14/3.14.3_1/Frameworks/Python.framework/Versions/3.14/lib/python3.14/annotationlib.py", line 1146, in _get_dunder_annotations
    ann = getattr(obj, "__annotations__", None)
  File "/Users/mschoettle/Documents/Development/mock_mre.py", line 7, in __annotate__
    def foo(x: Tuple[int, ...]):
               ^^^^^
NameError: name 'Tuple' is not defined. Did you mean: 'tuple'?

CPython versions tested on:

3.14

Operating systems tested on:

macOS

Metadata

Metadata

Assignees

No one assigned

    Labels

    type-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions