Skip to content

stubtest crashes with TypeError when runtime value is a proxy object that overrides __class__ #20919

@JaeHyuckSa

Description

@JaeHyuckSa

Crash Report

stubtest crashes with TypeError when a runtime module-level variable is a proxy object that overrides __class__ (e.g., Django's SimpleLazyObject). The proxy passes isinstance(obj, bool) but mypyc-compiled LiteralType.__init__ rejects it because type(obj) is not bool.

Traceback

Traceback (most recent call last):
  File "mypy/stubtest.py", line 2460, in main
    return test_stubs(parse_options(sys.argv[1:]))
  File "mypy/stubtest.py", line 2308, in test_stubs
    for error in test_module(module):
  File "mypy/stubtest.py", line 257, in test_module
    yield from verify(stub, runtime, [module_name])
  File "mypy/stubtest.py", line 436, in verify_mypyfile
    yield from verify(stub_entry, runtime_entry, object_path + [entry])
  File "mypy/stubtest.py", line 1276, in verify_var
    runtime_type = get_mypy_type_of_runtime_value(runtime,
type_context=stub.type)
  File "mypy/stubtest.py", line 2013, in get_mypy_type_of_runtime_value
    return mypy.types.LiteralType(value=value, fallback=fallback)
  File "mypy/types.py", line 3228, in __init__
TypeError: union[int, str, bool, float] object expected; got
django.utils.functional.SimpleLazyObject

To Reproduce
proxy_module.py

class LazyObject:
    def __init__(self, func):
        self.__dict__["_wrapped"] = None
        self.__dict__["_setupfunc"] = func

    def _setup(self):
        self.__dict__["_wrapped"] = self._setupfunc()

    @property
    def __class__(self):
        if self._wrapped is None:
            self._setup()
        return type(self._wrapped)

    def __bool__(self):
        if self._wrapped is None:
            self._setup()
        return bool(self._wrapped)


def default_value():
    return True


DEFAULT_VALUE = LazyObject(default_value)

proxy_module.pyi

class LazyObject:
    def __init__(self, func: object) -> None: ...
    def __bool__(self) -> bool: ...

def default_value() -> bool: ...

DEFAULT_VALUE: bool

allowlist.txt

proxy_module.LazyObject.__class__

run command

stubtest proxy_module --allowlist allowlist.txt

Real-world case: Django's SimpleLazyObject uses this pattern. This crash blocks stubtest runs in ddjango-stubs.

Your Environment

  • Mypy version used: 1.19.1 (compiled: yes)
  • Mypy command-line flags: stubtest proxy_module --allowlist allowlist.txt
  • Mypy configuration options from mypy.ini (and other config files): N/A
  • Python version used: 3.12, 3.13
  • Operating system and version: Ubuntu (GitHub Actions), macOS

(If the issue is confirmed, I’d be happy to take a shot at fixing it myself.)

Metadata

Metadata

Assignees

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions