|
| 1 | +# pylint: disable=R0903, W0107 |
| 2 | + |
| 3 | +"""Test invalid return type overrides in method inheritance.""" |
| 4 | + |
| 5 | +from abc import ABC, abstractmethod |
| 6 | +from io import TextIOWrapper, BytesIO |
| 7 | + |
| 8 | +# Case 1: Simple type mismatch |
| 9 | +class Parent: |
| 10 | + """Parent class with a method returning int.""" |
| 11 | + def method(self) -> int: |
| 12 | + """Returns an integer value.""" |
| 13 | + return 42 |
| 14 | + |
| 15 | +class Child(Parent): |
| 16 | + """Child class overriding method to return a string.""" |
| 17 | + def method(self) -> str: # [invalid-overridden-method] |
| 18 | + """Overrides method to return a string.""" |
| 19 | + return "hello" |
| 20 | + |
| 21 | +# Case 2: None vs concrete type |
| 22 | +class ParentNone: |
| 23 | + """Parent class with a method returning None.""" |
| 24 | + def method(self) -> None: |
| 25 | + """Method returns None.""" |
| 26 | + raise NotImplementedError("This method should be overridden") |
| 27 | + |
| 28 | +class ChildNone(ParentNone): |
| 29 | + """Child class overriding method to return an int.""" |
| 30 | + def method(self) -> int: # [invalid-overridden-method] |
| 31 | + """Overrides method to return an integer.""" |
| 32 | + return 42 |
| 33 | + |
| 34 | +# Case 5: Abstract base class with different return type |
| 35 | +class BaseClass(ABC): |
| 36 | + """Abstract base class with an abstract method returning TextIOWrapper.""" |
| 37 | + @abstractmethod |
| 38 | + def read_file(self, path: str) -> TextIOWrapper: |
| 39 | + """Abstract method that should return a TextIOWrapper.""" |
| 40 | + raise NotImplementedError("Method must be implemented by subclass") |
| 41 | + |
| 42 | +class ChildClass(BaseClass): |
| 43 | + """Child class overriding read_file method returning BytesIO.""" |
| 44 | + def read_file(self, path: str) -> BytesIO: # [invalid-overridden-method] |
| 45 | + """Implementation returns BytesIO instead of TextIOWrapper.""" |
| 46 | + return BytesIO(b"content") |
| 47 | + |
| 48 | +# Case 6: Method returns a subtype of the expected return type (valid override) |
| 49 | +class Animal: |
| 50 | + """Base class with a method returning a generic Animal.""" |
| 51 | + def make_sound(self) -> 'Animal': |
| 52 | + """Returns an Animal instance.""" |
| 53 | + return self |
| 54 | + |
| 55 | +class Dog(Animal): |
| 56 | + """Dog class overrides make_sound method returning a Dog.""" |
| 57 | + def make_sound(self) -> 'Dog': # This is valid as Dog is a subtype of Animal |
| 58 | + """Returns a Dog instance.""" |
| 59 | + return self |
| 60 | + |
| 61 | +# Case 8: Overriding method with more specific return type annotation |
| 62 | +class FileReader: |
| 63 | + """Class for reading files.""" |
| 64 | + def get_contents(self) -> 'Any': |
| 65 | + """Returns contents of the file.""" |
| 66 | + return "file contents" |
| 67 | + |
| 68 | +class JSONReader(FileReader): |
| 69 | + """Class for reading JSON files.""" |
| 70 | + def get_contents(self) -> dict: # [invalid-overridden-method] |
| 71 | + """Overrides to return a dictionary.""" |
| 72 | + return {"key": "value"} |
| 73 | + |
| 74 | +# Case 9: Abstract method with invalid return type in subclass |
| 75 | +class AbstractClass(ABC): |
| 76 | + """Abstract class with an abstract method.""" |
| 77 | + @abstractmethod |
| 78 | + def get_value(self) -> float: |
| 79 | + """Returns a float value.""" |
| 80 | + pass |
| 81 | + |
| 82 | +class ConcreteClass(AbstractClass): |
| 83 | + """Concrete class with an invalid override.""" |
| 84 | + def get_value(self) -> str: # [invalid-overridden-method] |
| 85 | + """Returns a string instead of a float.""" |
| 86 | + return "not a float" |
0 commit comments