diff --git a/conformance/results/mypy/qualifiers_final_decorator.toml b/conformance/results/mypy/qualifiers_final_decorator.toml index e25fa2c8a..471bfded3 100644 --- a/conformance/results/mypy/qualifiers_final_decorator.toml +++ b/conformance/results/mypy/qualifiers_final_decorator.toml @@ -1,20 +1,21 @@ conformant = "Pass" output = """ qualifiers_final_decorator.py:21: error: Cannot inherit from final class "Base1" [misc] -qualifiers_final_decorator.py:56: error: Cannot override final attribute "method1" (previously declared in base class "Base2") [misc] -qualifiers_final_decorator.py:59: error: Cannot override final attribute "method2" (previously declared in base class "Base2") [misc] -qualifiers_final_decorator.py:63: error: Cannot override final attribute "method3" (previously declared in base class "Base2") [misc] -qualifiers_final_decorator.py:67: error: Cannot override final attribute "method4" (previously declared in base class "Base2") [misc] -qualifiers_final_decorator.py:80: error: Cannot override final attribute "method" (previously declared in base class "Base3") [misc] -qualifiers_final_decorator.py:84: error: @final should be applied only to overload implementation [misc] -qualifiers_final_decorator.py:94: error: Cannot override final attribute "method" (previously declared in base class "Base4") [misc] -qualifiers_final_decorator.py:118: error: Cannot override final attribute "method" (previously declared in base class "Base5_2") [misc] -qualifiers_final_decorator.py:118: error: Signature of "method" incompatible with supertype "Base5_2" [override] -qualifiers_final_decorator.py:118: note: Superclass: -qualifiers_final_decorator.py:118: note: def method(self, v: int) -> None -qualifiers_final_decorator.py:118: note: Subclass: -qualifiers_final_decorator.py:118: note: def method(self) -> None -qualifiers_final_decorator.py:125: error: @final cannot be used with non-method functions [misc] +qualifiers_final_decorator.py:63: error: Cannot override final attribute "method1" (previously declared in base class "Base2") [misc] +qualifiers_final_decorator.py:66: error: Cannot override final attribute "method2" (previously declared in base class "Base2") [misc] +qualifiers_final_decorator.py:70: error: Cannot override final attribute "method3" (previously declared in base class "Base2") [misc] +qualifiers_final_decorator.py:74: error: Cannot override final attribute "method4" (previously declared in base class "Base2") [misc] +qualifiers_final_decorator.py:85: error: Cannot override final attribute "method5" (previously declared in base class "Base2") [misc] +qualifiers_final_decorator.py:91: error: Cannot override final attribute "method" (previously declared in base class "Base3") [misc] +qualifiers_final_decorator.py:95: error: @final should be applied only to overload implementation [misc] +qualifiers_final_decorator.py:105: error: Cannot override final attribute "method" (previously declared in base class "Base4") [misc] +qualifiers_final_decorator.py:129: error: Cannot override final attribute "method" (previously declared in base class "Base5_2") [misc] +qualifiers_final_decorator.py:129: error: Signature of "method" incompatible with supertype "Base5_2" [override] +qualifiers_final_decorator.py:129: note: Superclass: +qualifiers_final_decorator.py:129: note: def method(self, v: int) -> None +qualifiers_final_decorator.py:129: note: Subclass: +qualifiers_final_decorator.py:129: note: def method(self) -> None +qualifiers_final_decorator.py:136: error: @final cannot be used with non-method functions [misc] """ conformance_automated = "Pass" errors_diff = """ diff --git a/conformance/results/pycroscope/qualifiers_final_decorator.toml b/conformance/results/pycroscope/qualifiers_final_decorator.toml index fc2652a74..6046c7160 100644 --- a/conformance/results/pycroscope/qualifiers_final_decorator.toml +++ b/conformance/results/pycroscope/qualifiers_final_decorator.toml @@ -1,15 +1,22 @@ -conformance_automated = "Pass" +conformant = "Partial" +notes = """ +Reports an internal traceback for a valid `@final` property declaration. +""" +conformance_automated = "Fail" errors_diff = """ +Line 58: Unexpected errors ['./qualifiers_final_decorator.py:58:4: Traceback (most recent call last):'] """ output = """ ./qualifiers_final_decorator.py:21:15: Cannot inherit from final class [invalid_base] -./qualifiers_final_decorator.py:56:4: Cannot override final attribute method1 [incompatible_override] -./qualifiers_final_decorator.py:60:4: Cannot override final attribute method2 [incompatible_override] -./qualifiers_final_decorator.py:64:4: Cannot override final attribute method3 [incompatible_override] -./qualifiers_final_decorator.py:75:4: Cannot override final attribute method4 [incompatible_override] -./qualifiers_final_decorator.py:86:4: @final should be applied only to the overload implementation [invalid_final] -./qualifiers_final_decorator.py:89:4: Cannot override final attribute method [incompatible_override] -./qualifiers_final_decorator.py:102:4: Cannot override final attribute method [incompatible_override] -./qualifiers_final_decorator.py:118:4: Cannot override final attribute method [incompatible_override] -./qualifiers_final_decorator.py:126:0: @final is not allowed on non-method functions [invalid_final] +./qualifiers_final_decorator.py:58:4: Traceback (most recent call last): +./qualifiers_final_decorator.py:63:4: Cannot override final attribute method1 [incompatible_override] +./qualifiers_final_decorator.py:67:4: Cannot override final attribute method2 [incompatible_override] +./qualifiers_final_decorator.py:71:4: Cannot override final attribute method3 [incompatible_override] +./qualifiers_final_decorator.py:82:4: Cannot override final attribute method4 [incompatible_override] +./qualifiers_final_decorator.py:86:4: Cannot override final attribute method5 [incompatible_override] +./qualifiers_final_decorator.py:97:4: @final should be applied only to the overload implementation [invalid_final] +./qualifiers_final_decorator.py:100:4: Cannot override final attribute method [incompatible_override] +./qualifiers_final_decorator.py:113:4: Cannot override final attribute method [incompatible_override] +./qualifiers_final_decorator.py:129:4: Cannot override final attribute method [incompatible_override] +./qualifiers_final_decorator.py:137:0: @final is not allowed on non-method functions [invalid_final] """ diff --git a/conformance/results/pyrefly/qualifiers_final_decorator.toml b/conformance/results/pyrefly/qualifiers_final_decorator.toml index 381d74150..e5990f677 100644 --- a/conformance/results/pyrefly/qualifiers_final_decorator.toml +++ b/conformance/results/pyrefly/qualifiers_final_decorator.toml @@ -4,13 +4,14 @@ errors_diff = """ """ output = """ ERROR qualifiers_final_decorator.py:21:16-21: Cannot extend final class `Base1` [invalid-inheritance] -ERROR qualifiers_final_decorator.py:56:9-16: `method1` is declared as final in parent class `Base2` [bad-override] -ERROR qualifiers_final_decorator.py:60:9-16: `method2` is declared as final in parent class `Base2` [bad-override] -ERROR qualifiers_final_decorator.py:64:9-16: `method3` is declared as final in parent class `Base2` [bad-override] -ERROR qualifiers_final_decorator.py:68:9-16: `method4` is declared as final in parent class `Base2` [bad-override] -ERROR qualifiers_final_decorator.py:81:9-15: `method` is declared as final in parent class `Base3` [bad-override] -ERROR qualifiers_final_decorator.py:86:9-15: `@final` should only be applied to the implementation of an overloaded function. [invalid-overload] -ERROR qualifiers_final_decorator.py:95:9-15: `method` is declared as final in parent class `Base4` [bad-override] -ERROR qualifiers_final_decorator.py:118:9-15: `method` is declared as final in parent class `Base5_2` [bad-override] - WARN qualifiers_final_decorator.py:125:1-7: Decorator `@final` can only be used on methods. [invalid-decorator] +ERROR qualifiers_final_decorator.py:63:9-16: `method1` is declared as final in parent class `Base2` [bad-override] +ERROR qualifiers_final_decorator.py:67:9-16: `method2` is declared as final in parent class `Base2` [bad-override] +ERROR qualifiers_final_decorator.py:71:9-16: `method3` is declared as final in parent class `Base2` [bad-override] +ERROR qualifiers_final_decorator.py:75:9-16: `method4` is declared as final in parent class `Base2` [bad-override] +ERROR qualifiers_final_decorator.py:86:9-16: `method5` is declared as final in parent class `Base2` [bad-override] +ERROR qualifiers_final_decorator.py:92:9-15: `method` is declared as final in parent class `Base3` [bad-override] +ERROR qualifiers_final_decorator.py:97:9-15: `@final` should only be applied to the implementation of an overloaded function. [invalid-overload] +ERROR qualifiers_final_decorator.py:106:9-15: `method` is declared as final in parent class `Base4` [bad-override] +ERROR qualifiers_final_decorator.py:129:9-15: `method` is declared as final in parent class `Base5_2` [bad-override] + WARN qualifiers_final_decorator.py:136:1-7: Decorator `@final` can only be used on methods. [invalid-decorator] """ diff --git a/conformance/results/pyright/qualifiers_final_decorator.toml b/conformance/results/pyright/qualifiers_final_decorator.toml index 94448af44..105a5d056 100644 --- a/conformance/results/pyright/qualifiers_final_decorator.toml +++ b/conformance/results/pyright/qualifiers_final_decorator.toml @@ -1,18 +1,19 @@ conformant = "Pass" output = """ qualifiers_final_decorator.py:21:16 - error: Base class "Base1" is marked final and cannot be subclassed (reportGeneralTypeIssues) -qualifiers_final_decorator.py:56:9 - error: Method "method1" cannot override final method defined in class "Base2" (reportIncompatibleMethodOverride) -qualifiers_final_decorator.py:60:9 - error: Method "method2" cannot override final method defined in class "Base2" (reportIncompatibleMethodOverride) -qualifiers_final_decorator.py:64:9 - error: Method "method3" cannot override final method defined in class "Base2" (reportIncompatibleMethodOverride) -qualifiers_final_decorator.py:75:9 - error: Method "method4" cannot override final method defined in class "Base2" (reportIncompatibleMethodOverride) -qualifiers_final_decorator.py:86:9 - error: @final decorator should be applied only to the implementation (reportInconsistentOverload) -qualifiers_final_decorator.py:89:9 - error: Method "method" cannot override final method defined in class "Base3" (reportIncompatibleMethodOverride) -qualifiers_final_decorator.py:102:9 - error: Method "method" cannot override final method defined in class "Base4" (reportIncompatibleMethodOverride) -qualifiers_final_decorator.py:118:9 - error: Method "method" cannot override final method defined in class "Base5_2" (reportIncompatibleMethodOverride) -qualifiers_final_decorator.py:118:9 - error: Method "method" overrides class "Base5_2" in an incompatible manner +qualifiers_final_decorator.py:63:9 - error: Method "method1" cannot override final method defined in class "Base2" (reportIncompatibleMethodOverride) +qualifiers_final_decorator.py:67:9 - error: Method "method2" cannot override final method defined in class "Base2" (reportIncompatibleMethodOverride) +qualifiers_final_decorator.py:71:9 - error: Method "method3" cannot override final method defined in class "Base2" (reportIncompatibleMethodOverride) +qualifiers_final_decorator.py:82:9 - error: Method "method4" cannot override final method defined in class "Base2" (reportIncompatibleMethodOverride) +qualifiers_final_decorator.py:86:9 - error: Method "method5" cannot override final method defined in class "Base2" (reportIncompatibleMethodOverride) +qualifiers_final_decorator.py:97:9 - error: @final decorator should be applied only to the implementation (reportInconsistentOverload) +qualifiers_final_decorator.py:100:9 - error: Method "method" cannot override final method defined in class "Base3" (reportIncompatibleMethodOverride) +qualifiers_final_decorator.py:113:9 - error: Method "method" cannot override final method defined in class "Base4" (reportIncompatibleMethodOverride) +qualifiers_final_decorator.py:129:9 - error: Method "method" cannot override final method defined in class "Base5_2" (reportIncompatibleMethodOverride) +qualifiers_final_decorator.py:129:9 - error: Method "method" overrides class "Base5_2" in an incompatible manner   Positional parameter count mismatch; base method has 2, but override has 1   Parameter 2 mismatch: base parameter "v" is keyword parameter, override parameter is position-only (reportIncompatibleMethodOverride) -qualifiers_final_decorator.py:126:5 - error: Function "func1" cannot be marked @final because it is not a method (reportGeneralTypeIssues) +qualifiers_final_decorator.py:137:5 - error: Function "func1" cannot be marked @final because it is not a method (reportGeneralTypeIssues) """ conformance_automated = "Pass" errors_diff = """ diff --git a/conformance/results/results.html b/conformance/results/results.html index 2c57ab565..cb5e030ed 100644 --- a/conformance/results/results.html +++ b/conformance/results/results.html @@ -976,7 +976,12 @@

Python Type System Conformance Test Results

qualifiers_final_decorator Pass - Pass + + Partial + + Pass Pass Pass @@ -985,7 +990,7 @@

Python Type System Conformance Test Results

2 / 3 • 66.7% - 2.5 / 3 • 83.3% + 2 / 3 • 66.7% 3 / 3 • 100.0% 3 / 3 • 100.0% 3 / 3 • 100.0% @@ -2588,7 +2593,7 @@

Python Type System Conformance Test Results

109 / 141 • 77.3% - 130 / 141 • 92.2% + 129.5 / 141 • 91.8% 140 / 141 • 99.3% 136 / 141 • 96.5% 125 / 141 • 88.7% diff --git a/conformance/results/ty/qualifiers_final_decorator.toml b/conformance/results/ty/qualifiers_final_decorator.toml index 7236dc2a4..cb69fda36 100644 --- a/conformance/results/ty/qualifiers_final_decorator.toml +++ b/conformance/results/ty/qualifiers_final_decorator.toml @@ -3,14 +3,15 @@ errors_diff = """ """ output = """ qualifiers_final_decorator.py:21:16: error[subclass-of-final-class] Class `Derived1` cannot inherit from final class `Base1` -qualifiers_final_decorator.py:56:9: error[override-of-final-method] Cannot override final member `method1` from superclass `Base2` -qualifiers_final_decorator.py:60:9: error[override-of-final-method] Cannot override final member `method2` from superclass `Base2` -qualifiers_final_decorator.py:64:9: error[override-of-final-method] Cannot override final member `method3` from superclass `Base2` -qualifiers_final_decorator.py:75:9: error[override-of-final-method] Cannot override final member `method4` from superclass `Base2` -qualifiers_final_decorator.py:86:9: error[invalid-overload] `@final` decorator should be applied only to the overload implementation -qualifiers_final_decorator.py:89:9: error[override-of-final-method] Cannot override final member `method` from superclass `Base3` -qualifiers_final_decorator.py:102:9: error[override-of-final-method] Cannot override final member `method` from superclass `Base4` -qualifiers_final_decorator.py:118:9: error[invalid-method-override] Invalid override of method `method`: Definition is incompatible with `Base5_2.method` -qualifiers_final_decorator.py:118:9: error[override-of-final-method] Cannot override final member `method` from superclass `Base5_2` -qualifiers_final_decorator.py:125:1: error[final-on-non-method] `@final` cannot be applied to non-method function `func1` +qualifiers_final_decorator.py:63:9: error[override-of-final-method] Cannot override final member `method1` from superclass `Base2` +qualifiers_final_decorator.py:67:9: error[override-of-final-method] Cannot override final member `method2` from superclass `Base2` +qualifiers_final_decorator.py:71:9: error[override-of-final-method] Cannot override final member `method3` from superclass `Base2` +qualifiers_final_decorator.py:82:9: error[override-of-final-method] Cannot override final member `method4` from superclass `Base2` +qualifiers_final_decorator.py:86:9: error[override-of-final-method] Cannot override final member `method5` from superclass `Base2` +qualifiers_final_decorator.py:97:9: error[invalid-overload] `@final` decorator should be applied only to the overload implementation +qualifiers_final_decorator.py:100:9: error[override-of-final-method] Cannot override final member `method` from superclass `Base3` +qualifiers_final_decorator.py:113:9: error[override-of-final-method] Cannot override final member `method` from superclass `Base4` +qualifiers_final_decorator.py:129:9: error[invalid-method-override] Invalid override of method `method`: Definition is incompatible with `Base5_2.method` +qualifiers_final_decorator.py:129:9: error[override-of-final-method] Cannot override final member `method` from superclass `Base5_2` +qualifiers_final_decorator.py:136:1: error[final-on-non-method] `@final` cannot be applied to non-method function `func1` """ diff --git a/conformance/results/zuban/qualifiers_final_decorator.toml b/conformance/results/zuban/qualifiers_final_decorator.toml index bbedc5e60..153cf6bbd 100644 --- a/conformance/results/zuban/qualifiers_final_decorator.toml +++ b/conformance/results/zuban/qualifiers_final_decorator.toml @@ -3,18 +3,19 @@ errors_diff = """ """ output = """ qualifiers_final_decorator.py:21: error: Cannot inherit from final class "Base1" [misc] -qualifiers_final_decorator.py:56: error: Cannot override final attribute "method1" (previously declared in base class "Base2") [misc] -qualifiers_final_decorator.py:59: error: Cannot override final attribute "method2" (previously declared in base class "Base2") [misc] -qualifiers_final_decorator.py:63: error: Cannot override final attribute "method3" (previously declared in base class "Base2") [misc] -qualifiers_final_decorator.py:67: error: Cannot override final attribute "method4" (previously declared in base class "Base2") [misc] -qualifiers_final_decorator.py:80: error: Cannot override final attribute "method" (previously declared in base class "Base3") [misc] -qualifiers_final_decorator.py:85: error: @final should be applied only to overload implementation [misc] -qualifiers_final_decorator.py:94: error: Cannot override final attribute "method" (previously declared in base class "Base4") [misc] -qualifiers_final_decorator.py:118: error: Cannot override final attribute "method" (previously declared in base class "Base5_2") [misc] -qualifiers_final_decorator.py:118: error: Signature of "method" incompatible with supertype "Base5_2" [override] -qualifiers_final_decorator.py:118: note: Superclass: -qualifiers_final_decorator.py:118: note: def method(self, v: int) -> None -qualifiers_final_decorator.py:118: note: Subclass: -qualifiers_final_decorator.py:118: note: def method(self) -> None -qualifiers_final_decorator.py:125: error: @final cannot be used with non-method functions [misc] +qualifiers_final_decorator.py:63: error: Cannot override final attribute "method1" (previously declared in base class "Base2") [misc] +qualifiers_final_decorator.py:66: error: Cannot override final attribute "method2" (previously declared in base class "Base2") [misc] +qualifiers_final_decorator.py:70: error: Cannot override final attribute "method3" (previously declared in base class "Base2") [misc] +qualifiers_final_decorator.py:74: error: Cannot override final attribute "method4" (previously declared in base class "Base2") [misc] +qualifiers_final_decorator.py:85: error: Cannot override final attribute "method5" (previously declared in base class "Base2") [misc] +qualifiers_final_decorator.py:91: error: Cannot override final attribute "method" (previously declared in base class "Base3") [misc] +qualifiers_final_decorator.py:96: error: @final should be applied only to overload implementation [misc] +qualifiers_final_decorator.py:105: error: Cannot override final attribute "method" (previously declared in base class "Base4") [misc] +qualifiers_final_decorator.py:129: error: Cannot override final attribute "method" (previously declared in base class "Base5_2") [misc] +qualifiers_final_decorator.py:129: error: Signature of "method" incompatible with supertype "Base5_2" [override] +qualifiers_final_decorator.py:129: note: Superclass: +qualifiers_final_decorator.py:129: note: def method(self, v: int) -> None +qualifiers_final_decorator.py:129: note: Subclass: +qualifiers_final_decorator.py:129: note: def method(self) -> None +qualifiers_final_decorator.py:136: error: @final cannot be used with non-method functions [misc] """ diff --git a/conformance/tests/qualifiers_final_decorator.py b/conformance/tests/qualifiers_final_decorator.py index 5f131f462..057dc6bc1 100644 --- a/conformance/tests/qualifiers_final_decorator.py +++ b/conformance/tests/qualifiers_final_decorator.py @@ -51,6 +51,13 @@ def method4(self, x: str) -> str: def method4(self, x: int | str) -> int | str: return 0 + # > The @final decorator can be combined with previous decorators, like @property. + + @final + @property + def method5(self) -> int: + return 0 + class Derived2(Base2): def method1(self) -> None: # E @@ -75,6 +82,10 @@ def method4(self, x: str) -> str: def method4(self, x: int | str) -> int | str: # E[method4] return 0 + @property # E[method5] + def method5(self) -> bool: # E[method5] + return True + class Derived3(Base3): @overload # E[Derived3] diff --git a/docs/spec/qualifiers.rst b/docs/spec/qualifiers.rst index 6814692e0..641633f76 100644 --- a/docs/spec/qualifiers.rst +++ b/docs/spec/qualifiers.rst @@ -66,6 +66,22 @@ implementation (or on the first overload, for stubs):: def method(self, x=None): ... +The ``@final`` decorator can be combined with previous decorators, like +``@property``. Example:: + + from typing import final + + class Base: + @final + @property + def foo(self) -> None: + ... + + class Derived(Base): + @property + def foo(self) -> None: # Error: Cannot override final attribute "foo" + ... + It is an error to use ``@final`` on a non-method function. .. _`uppercase-final`: