Advanced descriptors
====================
.. image:: https://github.com/python-useful-helpers/advanced-descriptors/workflows/Python%20package/badge.svg
:target: https://github.com/python-useful-helpers/advanced-descriptors/actions
.. image:: https://readthedocs.org/projects/advanced-descriptors/badge/?version=latest
:target: http://advanced-descriptors.readthedocs.io/
:alt: Documentation Status
.. image:: https://img.shields.io/pypi/v/advanced-descriptors.svg
:target: https://pypi.python.org/pypi/advanced-descriptors
.. image:: https://img.shields.io/pypi/pyversions/advanced-descriptors.svg
:target: https://pypi.python.org/pypi/advanced-descriptors
.. image:: https://img.shields.io/pypi/status/advanced-descriptors.svg
:target: https://pypi.python.org/pypi/advanced-descriptors
.. image:: https://img.shields.io/github/license/python-useful-helpers/advanced-descriptors.svg
:target: https://raw.githubusercontent.com/python-useful-helpers/advanced-descriptors/master/LICENSE
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
:target: https://github.com/ambv/black
This package includes helpers for special cases:
* `SeparateClassMethod` - allow to have classmethod and normal method both with the same name.
* `AdvancedProperty` - property with possibility to set class wide getter.
* `LogOnAccess` - property with logging on successful get/set/delete or failure.
SeparateClassMethod
-------------------
This descriptor can be set using standard decorator syntax.
Create instance with arguments:
.. code-block:: python
def imeth(instance):
return instance.value
def cmeth(owner):
return owner.value
class Target(object):
value = 1
def __init__(self):
self.value = 2
getval = advanced_descriptors.SeparateClassMethod(
imeth, cmeth
)
Create instance wrapping as decorator:
.. code-block:: python
class Target(object):
value = 1
def __init__(self):
self.value = 2
@advanced_descriptors.SeparateClassMethod
def getval(self):
return self.value
@getval.class_method
def getval(cls):
return cls.value
Cases with method only and classmethod only is useless:
method as-is and `@classmethod` should be used in corresponding cases.
.. note::
classmethod receives class as argument. IDE's don't know about custom descriptors and substitutes `self` by default.
AdvancedProperty
----------------
This descriptor should be used in cases, when in addition to normal property API, class getter is required.
If class-wide setter and deleter also required - you should use standard propery in metaclass.
Usage examples:
1. In addition to normal property API:
.. code-block:: python
class Target(object):
_value = 777
def __init__(self):
self._value = 42
@advanced_descriptors.AdvancedProperty
def val(self):
return self._value
@val.setter
def val(self, value):
self._value = value
@val.deleter
def val(self):
self._value = 0
@val.cgetter
def val(cls):
return cls._value
2. Use class-wide getter for instance too:
.. code-block:: python
class Target(object):
_value = 1
val = advanced_descriptors.AdvancedProperty()
@val.cgetter
def val(cls):
return cls._value
.. note::
class-wide getter receives class as argument. IDE's don't know about custom descriptors and substitutes `self` by default.
LogOnAccess
-----------
This special case of property is useful in cases, where a lot of properties should be logged by similar way without writing a lot of code.
Basic API is conform with `property`, but in addition it is possible to customize logger, log levels and log conditions.
Usage examples:
1. Simple usage.
All by default.
logger is re-used from instance if available with names `logger` or `log` else used internal `advanced_descriptors.log_on_access` logger:
.. code-block:: python
import logging
class Target(object):
def init(self, val='ok')
self.val = val
self.logger = logging.get_logger(self.__class__.__name__) # Single for class, follow subclassing
def __repr__(self):
return "{cls}(val={self.val})".format(cls=self.__class__.__name__, self=self)
@advanced_descriptors.LogOnAccess
def ok(self):
return self.val
@ok.setter
def ok(self, val):
self.val = val
@ok.deleter
def ok(self):
self.val = ""
2. Use with global logger for class:
.. code-block:: python
class Target(object):
def init(self, val='ok')
self.val = val
def __repr__(self):
return "{cls}(val={self.val})".format(cls=self.__class__.__name__, self=self)
@advanced_descriptors.LogOnAccess
def ok(self):
return self.val
@ok.setter
def ok(self, val):
self.val = val
@ok.deleter
def ok(self):
self.val = ""
ok.logger = 'test_logger'
ok.log_level = logging.INFO
ok.exc_level = logging.ERROR
ok.log_object_repr = True # As by default
ok.log_success = True # As by default
ok.log_failure = True # As by default
ok.log_traceback = True # As by default
ok.override_name = None # As by default: use original name
Testing
=======
The main test mechanism for the package `advanced-descriptors` is using `tox`.
Available environments can be collected via `tox -l`
CI systems
==========
For CI/CD GitHub actions is used:
`GitHub actions: <https://github.com/python-useful-helpers/advanced-descriptors/actions>`_ is used for checking: PEP8, pylint, bandit, installation possibility and unit tests.
Raw data
{
"_id": null,
"home_page": "",
"name": "advanced-descriptors",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.7.0",
"maintainer_email": "Alexey Stepanov <penguinolog@gmail.com>, Antonio Esposito <esposito.cloud@gmail.com>, Dennis Dmitriev <dis-xcom@gmail.com>",
"keywords": "descriptor,property,classmethod,development",
"author": "",
"author_email": "Alexey Stepanov <penguinolog@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/ec/08/d726ac712f5d0dec1c1630bb129586b26a30668ca9e53f09033caa5e3861/advanced-descriptors-4.0.3.tar.gz",
"platform": null,
"description": "Advanced descriptors\n====================\n\n.. image:: https://github.com/python-useful-helpers/advanced-descriptors/workflows/Python%20package/badge.svg\n :target: https://github.com/python-useful-helpers/advanced-descriptors/actions\n.. image:: https://readthedocs.org/projects/advanced-descriptors/badge/?version=latest\n :target: http://advanced-descriptors.readthedocs.io/\n :alt: Documentation Status\n.. image:: https://img.shields.io/pypi/v/advanced-descriptors.svg\n :target: https://pypi.python.org/pypi/advanced-descriptors\n.. image:: https://img.shields.io/pypi/pyversions/advanced-descriptors.svg\n :target: https://pypi.python.org/pypi/advanced-descriptors\n.. image:: https://img.shields.io/pypi/status/advanced-descriptors.svg\n :target: https://pypi.python.org/pypi/advanced-descriptors\n.. image:: https://img.shields.io/github/license/python-useful-helpers/advanced-descriptors.svg\n :target: https://raw.githubusercontent.com/python-useful-helpers/advanced-descriptors/master/LICENSE\n.. image:: https://img.shields.io/badge/code%20style-black-000000.svg\n :target: https://github.com/ambv/black\n\nThis package includes helpers for special cases:\n\n* `SeparateClassMethod` - allow to have classmethod and normal method both with the same name.\n\n* `AdvancedProperty` - property with possibility to set class wide getter.\n\n* `LogOnAccess` - property with logging on successful get/set/delete or failure.\n\nSeparateClassMethod\n-------------------\n\nThis descriptor can be set using standard decorator syntax.\nCreate instance with arguments:\n\n.. code-block:: python\n\n def imeth(instance):\n return instance.value\n\n def cmeth(owner):\n return owner.value\n\n class Target(object):\n value = 1\n\n def __init__(self):\n self.value = 2\n getval = advanced_descriptors.SeparateClassMethod(\n imeth, cmeth\n )\n\nCreate instance wrapping as decorator:\n\n.. code-block:: python\n\n class Target(object):\n value = 1\n\n def __init__(self):\n self.value = 2\n\n @advanced_descriptors.SeparateClassMethod\n def getval(self):\n return self.value\n\n @getval.class_method\n def getval(cls):\n return cls.value\n\nCases with method only and classmethod only is useless:\nmethod as-is and `@classmethod` should be used in corresponding cases.\n\n.. note::\n\n classmethod receives class as argument. IDE's don't know about custom descriptors and substitutes `self` by default.\n\nAdvancedProperty\n----------------\n\nThis descriptor should be used in cases, when in addition to normal property API, class getter is required.\nIf class-wide setter and deleter also required - you should use standard propery in metaclass.\n\nUsage examples:\n\n1. In addition to normal property API:\n\n .. code-block:: python\n\n class Target(object):\n _value = 777\n\n def __init__(self):\n self._value = 42\n\n @advanced_descriptors.AdvancedProperty\n def val(self):\n return self._value\n\n @val.setter\n def val(self, value):\n self._value = value\n\n @val.deleter\n def val(self):\n self._value = 0\n\n @val.cgetter\n def val(cls):\n return cls._value\n\n2. Use class-wide getter for instance too:\n\n .. code-block:: python\n\n class Target(object):\n _value = 1\n\n val = advanced_descriptors.AdvancedProperty()\n\n @val.cgetter\n def val(cls):\n return cls._value\n\n.. note::\n\n class-wide getter receives class as argument. IDE's don't know about custom descriptors and substitutes `self` by default.\n\nLogOnAccess\n-----------\n\nThis special case of property is useful in cases, where a lot of properties should be logged by similar way without writing a lot of code.\n\nBasic API is conform with `property`, but in addition it is possible to customize logger, log levels and log conditions.\n\nUsage examples:\n\n1. Simple usage.\n All by default.\n logger is re-used from instance if available with names `logger` or `log` else used internal `advanced_descriptors.log_on_access` logger:\n\n .. code-block:: python\n\n import logging\n\n class Target(object):\n\n def init(self, val='ok')\n self.val = val\n self.logger = logging.get_logger(self.__class__.__name__) # Single for class, follow subclassing\n\n def __repr__(self):\n return \"{cls}(val={self.val})\".format(cls=self.__class__.__name__, self=self)\n\n @advanced_descriptors.LogOnAccess\n def ok(self):\n return self.val\n\n @ok.setter\n def ok(self, val):\n self.val = val\n\n @ok.deleter\n def ok(self):\n self.val = \"\"\n\n2. Use with global logger for class:\n\n .. code-block:: python\n\n class Target(object):\n\n def init(self, val='ok')\n self.val = val\n\n def __repr__(self):\n return \"{cls}(val={self.val})\".format(cls=self.__class__.__name__, self=self)\n\n @advanced_descriptors.LogOnAccess\n def ok(self):\n return self.val\n\n @ok.setter\n def ok(self, val):\n self.val = val\n\n @ok.deleter\n def ok(self):\n self.val = \"\"\n\n ok.logger = 'test_logger'\n ok.log_level = logging.INFO\n ok.exc_level = logging.ERROR\n ok.log_object_repr = True # As by default\n ok.log_success = True # As by default\n ok.log_failure = True # As by default\n ok.log_traceback = True # As by default\n ok.override_name = None # As by default: use original name\n\nTesting\n=======\nThe main test mechanism for the package `advanced-descriptors` is using `tox`.\nAvailable environments can be collected via `tox -l`\n\nCI systems\n==========\nFor CI/CD GitHub actions is used:\n\n`GitHub actions: <https://github.com/python-useful-helpers/advanced-descriptors/actions>`_ is used for checking: PEP8, pylint, bandit, installation possibility and unit tests.\n",
"bugtrack_url": null,
"license": "Apache License, Version 2.0",
"summary": "Advanced descriptors for special cases.",
"version": "4.0.3",
"split_keywords": [
"descriptor",
"property",
"classmethod",
"development"
],
"urls": [
{
"comment_text": "",
"digests": {
"md5": "6ed7c5958b2bca05c59d76c524ebdbe8",
"sha256": "433fa4bbd21c099a7c0f60d5777efde6e3a4b088d7d68e679e1c5a02bd95a78c"
},
"downloads": -1,
"filename": "advanced_descriptors-4.0.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "6ed7c5958b2bca05c59d76c524ebdbe8",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7.0",
"size": 16937,
"upload_time": "2022-12-16T11:59:52",
"upload_time_iso_8601": "2022-12-16T11:59:52.130994Z",
"url": "https://files.pythonhosted.org/packages/a4/e4/1aa2b3aed1ae5f785c27d1bfbf13900c06555919e4361c65818e2d800b2f/advanced_descriptors-4.0.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"md5": "5300a6f39607a1c2556aec2f3a2a4aaa",
"sha256": "32de74f9ea432b394214ea615aea2f09bdd9389483826e251c97a18271b673e5"
},
"downloads": -1,
"filename": "advanced-descriptors-4.0.3.tar.gz",
"has_sig": false,
"md5_digest": "5300a6f39607a1c2556aec2f3a2a4aaa",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7.0",
"size": 18133,
"upload_time": "2022-12-16T11:59:53",
"upload_time_iso_8601": "2022-12-16T11:59:53.819219Z",
"url": "https://files.pythonhosted.org/packages/ec/08/d726ac712f5d0dec1c1630bb129586b26a30668ca9e53f09033caa5e3861/advanced-descriptors-4.0.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2022-12-16 11:59:53",
"github": false,
"gitlab": false,
"bitbucket": false,
"lcname": "advanced-descriptors"
}