Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add conformance tests for PEP 702's @deprecated #1822

Merged
merged 12 commits into from
Jul 28, 2024
20 changes: 20 additions & 0 deletions conformance/results/mypy/directives_deprecated.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
conformant = "Unsupported"
notes = """
Does not support @deprecated.
"""
conformance_automated = "Fail"
errors_diff = """
Line 15: Expected 1 errors
Line 23: Expected 1 errors
Line 24: Expected 1 errors
Line 29: Expected 1 errors
Line 40: Expected 1 errors
Line 41: Expected 1 errors
Line 43: Expected 1 errors
Line 46: Expected 1 errors
Line 47: Expected 1 errors
Line 57: Expected 1 errors
Line 87: Expected 1 errors
"""
output = """
"""
2 changes: 1 addition & 1 deletion conformance/results/mypy/version.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
version = "mypy 1.11.0"
test_duration = 1.0
test_duration = 1.4
20 changes: 20 additions & 0 deletions conformance/results/pyre/directives_deprecated.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
conformant = "Unsupported"
notes = """
Does not support @deprecated.
"""
conformance_automated = "Fail"
errors_diff = """
Line 15: Expected 1 errors
Line 23: Expected 1 errors
Line 24: Expected 1 errors
Line 29: Expected 1 errors
Line 40: Expected 1 errors
Line 41: Expected 1 errors
Line 43: Expected 1 errors
Line 46: Expected 1 errors
Line 47: Expected 1 errors
Line 57: Expected 1 errors
Line 87: Expected 1 errors
"""
output = """
"""
2 changes: 1 addition & 1 deletion conformance/results/pyre/directives_reveal_type.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
conformant = "Partial"
notes = """"
notes = """
Produces errors rather than warnings on `reveal_type`.
"""
output = """
Expand Down
2 changes: 1 addition & 1 deletion conformance/results/pyre/version.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
version = "pyre 0.9.22"
test_duration = 2.5
test_duration = 1.8
31 changes: 31 additions & 0 deletions conformance/results/pyright/directives_deprecated.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
conformant = "Partial"
notes = """
Does not report error for deprecated magic methods.
"""
conformance_automated = "Fail"
errors_diff = """
Line 40: Expected 1 errors
Line 41: Expected 1 errors
Line 47: Expected 1 errors
Line 33: Unexpected errors ['directives_deprecated.py:33:7 - error: The class "Ham" is deprecated']
"""
output = """
directives_deprecated.py:15:44 - error: The class "Ham" is deprecated
  Use Spam instead (reportDeprecated)
directives_deprecated.py:23:9 - error: The function "norwegian_blue" is deprecated
  It is pining for the fiords (reportDeprecated)
directives_deprecated.py:24:13 - error: The function "norwegian_blue" is deprecated
  It is pining for the fiords (reportDeprecated)
directives_deprecated.py:29:9 - error: The function "foo" is deprecated
  Only str will be allowed (reportDeprecated)
directives_deprecated.py:33:7 - error: The class "Ham" is deprecated
  Use Spam instead (reportDeprecated)
directives_deprecated.py:43:6 - error: The getter for property "greasy" is deprecated
  All spam will be equally greasy (reportDeprecated)
directives_deprecated.py:46:6 - error: The setter for property "shape" is deprecated
  Shapes are becoming immutable (reportDeprecated)
directives_deprecated.py:57:9 - error: The function "lorem" is deprecated
  Deprecated (reportDeprecated)
directives_deprecated.py:87:13 - error: The method "foo" in class "Fooable" is deprecated
  Deprecated (reportDeprecated)
"""
2 changes: 1 addition & 1 deletion conformance/results/pyright/version.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
version = "pyright 1.1.373"
test_duration = 1.4
test_duration = 1.2
26 changes: 26 additions & 0 deletions conformance/results/pytype/directives_deprecated.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
conformant = "Unsupported"
notes = """
Does not support @deprecated.
"""
conformance_automated = "Fail"
errors_diff = """
Line 23: Expected 1 errors
Line 24: Expected 1 errors
Line 29: Expected 1 errors
Line 40: Expected 1 errors
Line 41: Expected 1 errors
Line 43: Expected 1 errors
Line 46: Expected 1 errors
Line 47: Expected 1 errors
Line 57: Expected 1 errors
Line 87: Expected 1 errors
Line 16: Unexpected errors ['File "directives_deprecated.py", line 16, in <module>: Can\\'t find module \\'_directives_deprecated_library\\'. [import-error]']
Line 18: Unexpected errors ['File "directives_deprecated.py", line 18, in <module>: typing_extensions.deprecated not supported yet [not-supported-yet]']
Line 66: Unexpected errors ['File "directives_deprecated.py", line 66, in <module>: typing.override not supported yet [not-supported-yet]']
"""
output = """
File "directives_deprecated.py", line 15, in <module>: Can't find module '_directives_deprecated_library'. [import-error]
File "directives_deprecated.py", line 16, in <module>: Can't find module '_directives_deprecated_library'. [import-error]
File "directives_deprecated.py", line 18, in <module>: typing_extensions.deprecated not supported yet [not-supported-yet]
File "directives_deprecated.py", line 66, in <module>: typing.override not supported yet [not-supported-yet]
"""
2 changes: 1 addition & 1 deletion conformance/results/pytype/version.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
version = "pytype 2024.04.11"
test_duration = 32.7
test_duration = 30.0
14 changes: 10 additions & 4 deletions conformance/results/results.html
Original file line number Diff line number Diff line change
Expand Up @@ -159,16 +159,16 @@ <h3>Python Type System Conformance Test Results</h3>
<div class="table_container"><table><tbody>
<tr><th class="col1">&nbsp;</th>
<th class='tc-header'><div class='tc-name'>mypy 1.11.0</div>
<div class='tc-time'>1.0sec</div>
<div class='tc-time'>1.4sec</div>
</th>
<th class='tc-header'><div class='tc-name'>pyright 1.1.373</div>
<div class='tc-time'>1.4sec</div>
<div class='tc-time'>1.2sec</div>
</th>
<th class='tc-header'><div class='tc-name'>pyre 0.9.22</div>
<div class='tc-time'>2.5sec</div>
<div class='tc-time'>1.8sec</div>
</th>
<th class='tc-header'><div class='tc-name'>pytype 2024.04.11</div>
<div class='tc-time'>32.7sec</div>
<div class='tc-time'>30.0sec</div>
</th>
</tr>
<tr><th class="column" colspan="5">
Expand Down Expand Up @@ -972,6 +972,12 @@ <h3>Python Type System Conformance Test Results</h3>
<th class="column col2 conformant">Pass</th>
<th class="column col2 partially-conformant"><div class="hover-text">Partial<span class="tooltip-text" id="bottom"><p>Does not reject a call to "cast" with additional arguments.</p></span></div></th>
</tr>
<tr><th class="column col1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;directives_deprecated</th>
<th class="column col2 not-conformant"><div class="hover-text">Unsupported<span class="tooltip-text" id="bottom"><p>Does not support @deprecated.</p></span></div></th>
<th class="column col2 partially-conformant"><div class="hover-text">Partial<span class="tooltip-text" id="bottom"><p>Does not report error for deprecated magic methods.</p></span></div></th>
<th class="column col2 not-conformant"><div class="hover-text">Unsupported<span class="tooltip-text" id="bottom"><p>Does not support @deprecated.</p></span></div></th>
<th class="column col2 not-conformant"><div class="hover-text">Unsupported<span class="tooltip-text" id="bottom"><p>Does not support @deprecated.</p></span></div></th>
</tr>
<tr><th class="column col1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;directives_no_type_check</th>
<th class="column col2 partially-conformant"><div class="hover-text">Partial<span class="tooltip-text" id="bottom"><p>Does not honor `@no_type_check` class decorator (allowed).</p><p>Does not reject invalid call of `@no_type_check` function.</p></span></div></th>
<th class="column col2 conformant"><div class="hover-text">Pass*<span class="tooltip-text" id="bottom"><p>Does not honor `@no_type_check` class decorator (allowed).</p></span></div></th>
Expand Down
44 changes: 44 additions & 0 deletions conformance/tests/_directives_deprecated_library.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"""
Support module for directive_deprecated.
"""

from typing import Self, overload

from typing_extensions import deprecated


@deprecated("Use Spam instead")
class Ham: ...


@deprecated("It is pining for the fiords")
def norwegian_blue(x: int) -> int: ...


@overload
@deprecated("Only str will be allowed")
def foo(x: int) -> str: ...


@overload
def foo(x: str) -> str: ...


def foo(x: int | str) -> str: ...


class Spam:

@deprecated("There is enough spam in the world")
def __add__(self, other: object) -> Self: ...

@property
@deprecated("All spam will be equally greasy")
def greasy(self) -> float: ...

@property
def shape(self) -> str: ...

@shape.setter
@deprecated("Shapes are becoming immutable")
def shape(self, value: str) -> None: ...
116 changes: 116 additions & 0 deletions conformance/tests/directives_deprecated.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
"""
Tests the warnings.deprecated function.
"""

# pyright: reportDeprecated=true

# Specification: https://typing.readthedocs.io/en/latest/spec/directives.html#deprecated
# See also https://peps.python.org/pep-0702/

# > Type checkers should produce a diagnostic whenever they encounter a usage of an object
erictraut marked this conversation as resolved.
Show resolved Hide resolved
# > marked as deprecated. [...] For deprecated classes and functions, this includes:

# > * `from` imports

from _directives_deprecated_library import Ham # E: Use of deprecated class Ham
import _directives_deprecated_library as library

from typing_extensions import deprecated


# > * References through module, class, or instance attributes

library.norwegian_blue(1) # E: Use of deprecated function norwegian_blue
map(library.norwegian_blue, [1, 2, 3]) # E: Use of deprecated function norwegian_blue


# > For deprecated overloads, this includes all calls that resolve to the deprecated overload.

library.foo(1) # E: Use of deprecated overload for foo
library.foo("x") # OK


ham = Ham() # OK (already reported above)


# > * Any syntax that indirectly triggers a call to the function.

spam = library.Spam()

_ = spam + 1 # E: Use of deprecated method Spam.__add__
spam += 1 # E: Use of deprecated method Spam.__add__

spam.greasy # E: Use of deprecated property Spam.greasy
spam.shape # OK

spam.shape = "cube" # E: Use of deprecated property setter Spam.shape
spam.shape += "cube" # E: Use of deprecated property setter Spam.shape


class Invocable:

@deprecated("Deprecated")
def __call__(self) -> None: ...

invocable = Invocable()
invocable() # E: Use of deprecated method __call__


# > * Any usage of deprecated objects in their defining module

@deprecated("Deprecated")
def lorem() -> None: ...


ipsum = lorem() # E: Use of deprecated function lorem


# > There are additional scenarios where deprecations could come into play.
# > For example, an object may implement a `typing.Protocol`,
# > but one of the methods required for protocol compliance is deprecated.
# > As scenarios such as this one appear complex and relatively unlikely to come up in practice,
# > this PEP does not mandate that type checkers detect them.

from typing import Protocol, override


class Fooable(Protocol):

@deprecated("Deprecated")
def foo(self) -> None: ...

def bar(self) -> None: ...


class Fooer(Fooable):

@override
def foo(self) -> None: # E?: Implementation of deprecated method foo
...

def bar(self) -> None: ...


def foo_it(fooable: Fooable) -> None:
fooable.foo() # E: Use of deprecated method foo
fooable.bar()


# https://github.com/python/typing/pull/1822#discussion_r1693991644

class Fooable2(Protocol):

def foo(self) -> None: ...


class Concrete:

@deprecated("Deprecated")
def foo(self) -> None: ...


def take_fooable(f: Fooable2) -> None: ...


def caller(c: Concrete) -> None:
take_fooable(c) # E?: Concrete is a Fooable2, but only because of a deprecated method