mypy icon indicating copy to clipboard operation
mypy copied to clipboard

[mypyc] property setter and deleter don't work with parameterized attributes

Open nstarman opened this issue 1 year ago • 6 comments

Bug Report

mypyc fails to compile a class with a property setter and deleter and a weakref attribute.

To Reproduce

  1. Defined (in a file foo.py) a class Bar with a property that has a setter and deleter and weakref attribute.
  2. run mypyc foo.py3.

e.g.

from __future__ import annotations
from typing import TypeVar, Generic
import weakref

T = TypeVar("T")

class Bar(Generic[T]):
    _attr: weakref.ReferenceType[T] | None
    def __init__(self) -> None:
        self._attr = None
    @property
    def attr(self) -> T | None:
        return self._attr() if self._attr is not None else None
    @attr.setter
    def attr(self, value: T) -> None:
        self._attr = weakref.ref(value)
    @attr.deleter
    def attr(self) -> None:
        self._attr = None

Actual Behavior

I get the following error:

File "mypyc/irbuild/classdef.py", line 87, in transform_class_def
File "mypyc/irbuild/classdef.py", line 200, in add_method
File "mypyc/irbuild/function.py", line 369, in handle_ext_method
File "mypyc/irbuild/function.py", line 312, in gen_func_item
File "mypyc/irbuild/function.py", line 351, in gen_func_ir
...: KeyError: <mypy.nodes.FuncDef object at 0x7f93d4876b80>

This error does not occur when setter and deleter are omitted.

Your Environment

  • Mypy version used: 0.950
  • Mypy command-line flags: N/A
  • Mypy configuration options from mypy.ini (and other config files): N/A
  • Python version used: 3.9
  • Operating system and version: macOS Monterey, version 12.4

nstarman avatar Jul 24 '22 19:07 nstarman

@AlexWaygood, I narrowed the source of the problem. It isn't setters and deleters by themselves, but in conjunction with (at least) weakref (and maybe other types).

nstarman avatar Aug 01 '22 16:08 nstarman

Just tested on

from __future__ import annotations
from typing import Generic, Protocol, TypeVar


T = TypeVar("T")
O = TypeVar("O", covariant=True)


class Thing(Protocol[O]):
    def __call__(self) -> O: ...


class Bar(Generic[T]):
    _attr: Thing[T] | None
    def __init__(self) -> None:
        self._attr = None
    @property
    def attr(self) -> T | None:
        return self._attr() if self._attr is not None else None
    @attr.deleter  # compiles if deleter (and what it decorates) is commented out
    def attr(self) -> None:
        self._attr = None

This raises the same exception, so I suspect the problem is actually with setting parameterized attributes?

nstarman avatar Aug 01 '22 16:08 nstarman

I'm afraid I'm only a triager here, and mypyc is one of the areas of mypy I know least about, so I'm probably not the person you want to be tagging here, I'm afraid :)

AlexWaygood avatar Aug 01 '22 16:08 AlexWaygood

Whom should I tag?

nstarman avatar Aug 01 '22 16:08 nstarman

97littleleaf11, ichard26 or JukkaL might be interested. (ichard26 isn't a core dev, but he's made several mypyc contributions and uses mypyc for compiling black.)

But we're all volunteers with limited free time :)

AlexWaygood avatar Aug 02 '22 06:08 AlexWaygood

Thanks @AlexWaygood.

@JukkaL, I think I've found an issue with how mypyc processes parametrized attributes, at least in the context of decorated methods. I've been trying to understand the error trace to submit a PR resolving this issue, but I don't yet grok Mypy(s)'s internals. Hopefully this and #13304 are easily resolved issues.

nstarman avatar Aug 02 '22 20:08 nstarman