| # SPDX-License-Identifier: MIT |
| |
| import abc |
| import inspect |
| |
| import pytest |
| |
| import attrs |
| |
| from attr._compat import PY_3_10_PLUS, PY_3_12_PLUS |
| |
| |
| @pytest.mark.skipif( |
| not PY_3_10_PLUS, reason="abc.update_abstractmethods is 3.10+" |
| ) |
| class TestUpdateAbstractMethods: |
| def test_abc_implementation(self, slots): |
| """ |
| If an attrs class implements an abstract method, it stops being |
| abstract. |
| """ |
| |
| class Ordered(abc.ABC): |
| @abc.abstractmethod |
| def __lt__(self, other): |
| pass |
| |
| @abc.abstractmethod |
| def __le__(self, other): |
| pass |
| |
| @attrs.define(order=True, slots=slots) |
| class Concrete(Ordered): |
| x: int |
| |
| assert not inspect.isabstract(Concrete) |
| assert Concrete(2) > Concrete(1) |
| |
| def test_remain_abstract(self, slots): |
| """ |
| If an attrs class inherits from an abstract class but doesn't implement |
| abstract methods, it remains abstract. |
| """ |
| |
| class A(abc.ABC): |
| @abc.abstractmethod |
| def foo(self): |
| pass |
| |
| @attrs.define(slots=slots) |
| class StillAbstract(A): |
| pass |
| |
| assert inspect.isabstract(StillAbstract) |
| expected_exception_message = ( |
| "^Can't instantiate abstract class StillAbstract without an " |
| "implementation for abstract method 'foo'$" |
| if PY_3_12_PLUS |
| else "class StillAbstract with abstract method foo" |
| ) |
| with pytest.raises(TypeError, match=expected_exception_message): |
| StillAbstract() |