# reliable-finalizer
`reliable-finalizer` is a small utility library for convenient implementation
of finalizers in python
## Installation
```
pip install reliable-finalizer
```
## Usage
```python
from reliable_finalizer import reliable_finalizer
class UsefulClass:
... # This is a class that requires some cleanup on instance destruction
# This method will be called on object before it is garbage collected OR at the end of the program
@reliable_finalizer
def destruct(self):
... # The cleanup code
```
## Why use `reliable-finalizer`?
This library's purpose is to provide convenient syntax for reliable finalization in Python.
The built-in solution for finalization, [\_\_del\_\_()](https://docs.python.org/3/reference/datamodel.html#object.__del__), does not make guarantees strong enough to be adequately used
with an arbitrary interpreter (although it is somewhat consistent in [CPython](https://docs.python.org/3/glossary.html#term-CPython)).
Namely, it can be called multiple times, and is not guaranteed to be called at all! - `__del__()` is not a great place for cleanup code.
Standard library offers a more robust solution: [weakref.finalize()](https://docs.python.org/3/library/weakref.html#finalizer-objects). It does basically the same thing `__del__()` does, but gives stronger guarantees about its behavior: the callback is invoked once and only once.
`reliable_finalizer` decorator is a utility for creating such finalizers. Any instance of a class with `reliable_finalizer`-decorated method will have a finalizer assigned to it.
Because of that, using `reliable_finalizer` is syntactically similar to using `__del__()` - all one needs is to create a method.
## Additional details and limitations
### Manual finalizer invocation
Calling a method decorated with `reliable_finalizer` on an instance invokes the underlying finalizer, so calling it manually is completely fine - it will still only be called once. This can be useful, for example, if you want to additionally implement [context manager protocol](https://docs.python.org/3/reference/datamodel.html#context-managers) in your class:
```python
from reliable_finalizer import reliable_finalizer
class UsefulClass:
... # This is a class that requires some cleanup on instance destruction
# This method will be called on object before it is garbage collected OR at the end of the program
@reliable_finalizer
def destruct(self):
... # The cleanup code
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.destruct()
```
### Using finalizers with slots
When using `reliable_finalizer`, the underlying weakref finalizer of an instance is saved to its `__finalizer__` attribute.
If your class does not have a `__dict__` slot, it must have `__finalizer__` slot in order to use `reliable_finalizer`:
```python
from reliable_finalizer import reliable_finalizer
class UsefulClass:
... # This is a class that requires some cleanup on instance destruction
__slots__ = [
..., # Slots for the class
'__finalizer__' # This slot is required for reliable_finalizer to work, if "__dict__" is not a slot
]
# This method will be called on object before it is garbage collected OR at the end of the program
@reliable_finalizer
def destruct(self):
... # The cleanup code
```
Raw data
{
"_id": null,
"home_page": "https://github.com/TimurTimergalin/reliable-finalizer",
"name": "reliable-finalizer",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.2",
"maintainer_email": null,
"keywords": "python finalize",
"author": "TimurTimergalin",
"author_email": "tmtimergalin8080@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/a5/fe/d6090a5192d99de95bedf80135c6d163238d1174e7f48bda08fa43597cc4/reliable_finalizer-1.0.0.tar.gz",
"platform": null,
"description": "# reliable-finalizer\r\n`reliable-finalizer` is a small utility library for convenient implementation\r\nof finalizers in python\r\n## Installation\r\n```\r\npip install reliable-finalizer\r\n```\r\n## Usage\r\n\r\n```python\r\nfrom reliable_finalizer import reliable_finalizer\r\n\r\nclass UsefulClass:\r\n ... # This is a class that requires some cleanup on instance destruction\r\n \r\n # This method will be called on object before it is garbage collected OR at the end of the program\r\n @reliable_finalizer\r\n def destruct(self): \r\n ... # The cleanup code \r\n```\r\n\r\n## Why use `reliable-finalizer`?\r\nThis library's purpose is to provide convenient syntax for reliable finalization in Python.\r\nThe built-in solution for finalization, [\\_\\_del\\_\\_()](https://docs.python.org/3/reference/datamodel.html#object.__del__), does not make guarantees strong enough to be adequately used\r\nwith an arbitrary interpreter (although it is somewhat consistent in [CPython](https://docs.python.org/3/glossary.html#term-CPython)).\r\nNamely, it can be called multiple times, and is not guaranteed to be called at all! - `__del__()` is not a great place for cleanup code.\r\n\r\nStandard library offers a more robust solution: [weakref.finalize()](https://docs.python.org/3/library/weakref.html#finalizer-objects). It does basically the same thing `__del__()` does, but gives stronger guarantees about its behavior: the callback is invoked once and only once.\r\n\r\n`reliable_finalizer` decorator is a utility for creating such finalizers. Any instance of a class with `reliable_finalizer`-decorated method will have a finalizer assigned to it.\r\nBecause of that, using `reliable_finalizer` is syntactically similar to using `__del__()` - all one needs is to create a method.\r\n\r\n## Additional details and limitations\r\n### Manual finalizer invocation \r\nCalling a method decorated with `reliable_finalizer` on an instance invokes the underlying finalizer, so calling it manually is completely fine - it will still only be called once. This can be useful, for example, if you want to additionally implement [context manager protocol](https://docs.python.org/3/reference/datamodel.html#context-managers) in your class:\r\n```python\r\nfrom reliable_finalizer import reliable_finalizer\r\n\r\nclass UsefulClass:\r\n ... # This is a class that requires some cleanup on instance destruction\r\n \r\n # This method will be called on object before it is garbage collected OR at the end of the program\r\n @reliable_finalizer\r\n def destruct(self): \r\n ... # The cleanup code \r\n \r\n def __enter__(self):\r\n return self\r\n \r\n def __exit__(self, exc_type, exc_val, exc_tb):\r\n self.destruct()\r\n```\r\n### Using finalizers with slots\r\nWhen using `reliable_finalizer`, the underlying weakref finalizer of an instance is saved to its `__finalizer__` attribute.\r\nIf your class does not have a `__dict__` slot, it must have `__finalizer__` slot in order to use `reliable_finalizer`:\r\n```python\r\nfrom reliable_finalizer import reliable_finalizer\r\n\r\nclass UsefulClass:\r\n ... # This is a class that requires some cleanup on instance destruction\r\n \r\n __slots__ = [\r\n ..., # Slots for the class\r\n '__finalizer__' # This slot is required for reliable_finalizer to work, if \"__dict__\" is not a slot \r\n ]\r\n \r\n # This method will be called on object before it is garbage collected OR at the end of the program\r\n @reliable_finalizer\r\n def destruct(self): \r\n ... # The cleanup code \r\n```\r\n",
"bugtrack_url": null,
"license": null,
"summary": "Python utility for creation of reliable finalizer as an alternative to __del__ method",
"version": "1.0.0",
"project_urls": {
"Homepage": "https://github.com/TimurTimergalin/reliable-finalizer"
},
"split_keywords": [
"python",
"finalize"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "5a3bb97f775477f163f64fc47c07899e782d7bda847acf3398cd7477dcbf39ba",
"md5": "48a0bc3f8d4f019054ee65deaa56b666",
"sha256": "881c2f59ea531cece00d543da96baa6bf74f39c8b95307ccfd135261f52f851e"
},
"downloads": -1,
"filename": "reliable_finalizer-1.0.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "48a0bc3f8d4f019054ee65deaa56b666",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.2",
"size": 4102,
"upload_time": "2024-08-19T18:28:44",
"upload_time_iso_8601": "2024-08-19T18:28:44.392046Z",
"url": "https://files.pythonhosted.org/packages/5a/3b/b97f775477f163f64fc47c07899e782d7bda847acf3398cd7477dcbf39ba/reliable_finalizer-1.0.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "a5fed6090a5192d99de95bedf80135c6d163238d1174e7f48bda08fa43597cc4",
"md5": "8e62ac6ca33db77bad089d0b3c5648f0",
"sha256": "df404c5165efda3adb379b51e00a38739cdfeb694e44679fc48afc892c81d684"
},
"downloads": -1,
"filename": "reliable_finalizer-1.0.0.tar.gz",
"has_sig": false,
"md5_digest": "8e62ac6ca33db77bad089d0b3c5648f0",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.2",
"size": 3725,
"upload_time": "2024-08-19T18:28:45",
"upload_time_iso_8601": "2024-08-19T18:28:45.921740Z",
"url": "https://files.pythonhosted.org/packages/a5/fe/d6090a5192d99de95bedf80135c6d163238d1174e7f48bda08fa43597cc4/reliable_finalizer-1.0.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-08-19 18:28:45",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "TimurTimergalin",
"github_project": "reliable-finalizer",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "reliable-finalizer"
}