diff --git a/CHANGELOG.md b/CHANGELOG.md index 942fdb5e762fd4b72e057652d8a1a6d718360cce..07ae32375d2aae0076b9dce84c8b4a72f2329431 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2 +1,4 @@ # v2.17.3 +* changed the behaviour of `Closeable` to adjust + for semi-initialized classes diff --git a/satella/__init__.py b/satella/__init__.py index 28fb20fa71919730dab45d893092876406b5d945..0aa561c6fd5e030019ac22d0d6dd3c8515a2d17e 100644 --- a/satella/__init__.py +++ b/satella/__init__.py @@ -1 +1 @@ -__version__ = '2.17.3a1' +__version__ = '2.17.3' diff --git a/satella/coding/misc.py b/satella/coding/misc.py index e6277795fc0bb12e4aad41bbec7c55428fb70f34..ed970434fc518582ba80c72a61e11dfd7522ea24 100644 --- a/satella/coding/misc.py +++ b/satella/coding/misc.py @@ -59,9 +59,10 @@ class Closeable: Can be also used as a context manager, with close() called upon __exit__. - You should extend both __init__ and close() + .. warning:: You should extend both __init__ and close(). Invoke __init__() at the end of + your class constructor, this will prevent the destructor from closing on half-initialized classes. """ - __slots__ = ('__finalized',) + __slots__ = '__finalized', def __init__(self): self.__finalized = False @@ -90,7 +91,7 @@ class Closeable: try: return not self.__finalized except AttributeError: - raise RuntimeError('__finalized not found, did you forget to call the constructor?') + return False # the device does not need clean up finally: self.__finalized = True diff --git a/tests/test_coding/test_misc.py b/tests/test_coding/test_misc.py index 48a714921f0cee572ebd70f3f7ec8b8982a4498b..5826fbca5d159578521b1eb9061a1d14f866c9bb 100644 --- a/tests/test_coding/test_misc.py +++ b/tests/test_coding/test_misc.py @@ -13,6 +13,21 @@ logger = logging.getLogger(__name__) class TestCase(unittest.TestCase): + def test_closeable_semi_initialized_classes(self): + slf = self + + class Test(Closeable): + def __init__(self): + raise ValueError() + self.a = 5 + super().__init__() + + def close(self): + if super().close(): + slf.fail('Tried to close an uninitialized class!') + + self.assertRaises(ValueError, Test) + def test_cant_compare_me(self): class Uncomparable: def __eq__(self, other):