Skip to content

@deprecated on a class makes it a non-native class #1245

Open
python/mypy
#22167

Description

@rheard

A class that is decorated with @deprecated("...") (PEP 702, from warnings or typing_extensions) is compiled as a non-native class, because deprecated isn't one of the class decorators that native classes support. Nothing reports this. The decorator looks like metadata, so it's an easy way to lose most of the benefit of compiling a class.

# mod.py
import time
from typing_extensions import deprecated


@deprecated("Old is deprecated")
class Old:
    def __init__(self, x: int) -> None:
        self.x = x

    def m(self) -> int:
        return self.x + 1


class Plain:
    def __init__(self, x: int) -> None:
        self.x = x

    def m(self) -> int:
        return self.x + 1


def use_old(o: Old, n: int) -> float:
    t0 = time.perf_counter()
    total = 0
    for i in range(n):
        total += o.m() + o.x
    return (time.perf_counter() - t0) / n * 1e9


def use_plain(o: Plain, n: int) -> float:
    t0 = time.perf_counter()
    total = 0
    for i in range(n):
        total += o.m() + o.x
    return (time.perf_counter() - t0) / n * 1e9
# run.py
import warnings
import mod

warnings.simplefilter("ignore")
print(type(mod.Old.m).__name__, type(mod.Plain.m).__name__)
print("Old:   %.1f ns per iteration" % mod.use_old(mod.Old(1), 2_000_000))
print("Plain: %.1f ns per iteration" % mod.use_plain(mod.Plain(1), 2_000_000))

Output after mypyc mod.py:

m_Old_obj method_descriptor
Old:   212.7 ns per iteration
Plain: 16.9 ns per iteration

Other consequences:

  • Together with @mypyc_attr(native_class=True) it's a compile error: Class is marked as native_class=True but it can't be a native class. Classes that have decorators other than supported decorators can't be native classes.
  • The class gets the other limitations of non-native classes. If it defines __new__, mypyc reports
    "object.__new__()" not supported for non-extension classes. A compiled subclass that calls
    super().m() doesn't build for me (unresolved external symbol CPyDef_Old___m), although that one
    looks like a separate problem with non-native base classes.

Expected: the class is still a native class, and creating an instance or a subclass of it emits the warning, like in interpreted Python.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions