{ "info": { "author": "Istv\u00e1n P\u00e1sztor", "author_email": "pasztorpisti@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 2", "Programming Language :: Python :: 3", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "==============\ndecorator-args\n==============\n\nOptional/required/keyword-only decorator arguments made easy.\n\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n\n\n.. image:: https://img.shields.io/travis/pasztorpisti/decorator-args.svg?style=flat\n :target: https://travis-ci.org/pasztorpisti/decorator-args\n :alt: build\n\n.. image:: https://img.shields.io/codacy/0e4f7e6a2823485ba20496c7c96a42e7/master.svg?style=flat\n :target: https://www.codacy.com/app/pasztorpisti/decorator-args\n :alt: code quality\n\n.. image:: https://landscape.io/github/pasztorpisti/decorator-args/master/landscape.svg?style=flat\n :target: https://landscape.io/github/pasztorpisti/decorator-args/master\n :alt: code health\n\n.. image:: https://img.shields.io/coveralls/pasztorpisti/decorator-args/master.svg?style=flat\n :target: https://coveralls.io/r/pasztorpisti/decorator-args?branch=master\n :alt: coverage\n\n.. image:: https://img.shields.io/pypi/v/decorator-args.svg?style=flat\n :target: https://pypi.python.org/pypi/decorator-args\n :alt: pypi\n\n.. image:: https://img.shields.io/github/tag/pasztorpisti/decorator-args.svg?style=flat\n :target: https://github.com/pasztorpisti/decorator-args\n :alt: github\n\n.. image:: https://img.shields.io/github/license/pasztorpisti/decorator-args.svg?style=flat\n :target: https://github.com/pasztorpisti/decorator-args/blob/master/LICENSE.txt\n :alt: license: MIT\n\n\nThis mini-library is far from being revolutionary or essential but its features may come in handy for some.\nIt is a chaotic set of ideas and features that I don't really feel to be rock solid but I think it isn't an\nunforgivable guilt to release it to the wild. In worst case you can open a \"Please destruct this code/library\"\nissue on its github page.\n\n\n.. contents::\n\n\nInstallation\n============\n\n.. code-block:: sh\n\n pip install decorator-args\n\nAlternatively you can download the distribution from the following places:\n\n- https://pypi.python.org/pypi/decorator-args#downloads\n- https://github.com/pasztorpisti/decorator-args/releases\n\n\nUsage\n=====\n\n\nProblem to solve\n----------------\n\nThe following code snippet shows two examples:\n\n1. Applying a decorator called ``argless`` without any arguments.\n2. Applying a decorator called ``argful`` that receives arguments before applying it.\n\n.. code-block:: python\n\n #1\n @argless\n def decorated_function():\n ...\n\n #2\n @argful('arg1_value', arg2='arg2_value')\n def decorated_function():\n ...\n\n\nThis library tries to make it easier to implement decorators that receive arguments (like ``argful_decorator`` above).\nBesides this it has some related extra features to offer (optional and keyword-only decorator args).\n\n\nHow this library helps\n----------------------\n\nThe previously used ``argful`` decorator can be implemented in countless ways but the two most standard ways to do it\nwithout this library looks like this:\n\n1. \"Inception-style\" implementation as a function:\n\n.. code-block:: python\n\n def argful(arg1, arg2='arg2_default'):\n # TODO: Validate and pre-process decorator args as early as possible for easier debugging\n def decorate(decoratable):\n @functools.wraps(decoratable)\n def wrapper(*args, **kwargs):\n # TODO: Manipulate the input and output of the wrapped\n # decoratable object and use arg1 and arg2 if you want...\n return decoratable(*args, **kwargs)\n return wrapper\n return decorate\n\n\n2. Implementation as a class:\n\n.. code-block:: python\n\n class argful(object):\n def __init__(self, arg1, arg2='arg2_default'):\n # TODO: Validate and pre-process decorator args as early as possible for easier debugging\n self.arg1 = arg1\n self.arg2 = arg2\n\n def __call__(self, decoratable):\n @functools.wraps(decoratable)\n def wrapper(*args, **kwargs)\n # TODO: Manipulate the input and output of the wrapped\n # decoratable object and use self.arg1 and self.arg2 if you want...\n return decoratable(*args, **kwargs)\n return wrapper\n\n\nThe ``decorator_args.decorator_args`` decorator provided by this library can remove a level of indirection from the\n\"Inception-style\" implementation seen in example #1 making the code simpler and more readable:\n\n.. code-block:: python\n\n from decorator_args import decorator_args\n\n\n @decorator_args\n def argful(decoratable, arg1, arg2='arg2_default'):\n @functools.wraps(decoratable)\n def wrapper(*args, **kwargs):\n # TODO: Manipulate the input and output of the wrapped\n # decoratable object and use arg1 and arg2 if you want...\n return decoratable(*args, **kwargs)\n return wrapper\n\n\nAt the same time this library offers the following extra features:\n\n- It can force keyword-only argument passing for your decorator. In some cases this is desirable because it can make\n code easier to read and understand:\n\n.. code-block:: python\n\n # Decorator implementation with keyword-only decorator arguments:\n @decorator_args(keyword_only=True)\n def argful(decoratable, arg1, arg2='arg2_default'):\n ...\n\n\n # This would fail with a ``TypeError('This decorator receives only keyword arguments')``\n @argful('arg1_value', arg2='arg2_value')\n def decorated_function():\n ...\n\n\n # This is OK because all args are passed as keyword args\n @argful(arg1='arg1_value', arg2='arg2_value')\n def decorated_function():\n ...\n\n- If your decorator doesn't have required arguments and you use the ``optional`` feature of this library than you can\n apply your decorator without an argument list when you don't want to pass any args to it:\n\n.. code-block:: python\n\n # Decorator implementation with optional argument list:\n # Note that our decorator doesn't have required args other than the decoratable object:\n @decorator_args(optional=True)\n def argful(decoratable, arg1='arg1_default', arg2='arg2_default'):\n ...\n\n\n # This works because of using `optional=True` above:\n @argful\n def decorated_function():\n ...\n\n\n # This would work even without `optional=True` in our decorator implementation:\n @argful()\n def decorated_function():\n ...\n\n\n # Of course passing actual args also works as expected:\n @argful('arg1_value', 'arg2_value')\n def decorated_function():\n ...\n\n\nLibrary interface\n=================\n\nThe library offers a ``decorator_args.decorator_args`` decorator that is the main \"workhorse\" of the library and a\nset of other decorators that are just convenience helpers around the previously mentioned main decorator.\nSyntax-wise the arguments of these decorators are optional and keyword-only.\n\n\nMain \"entrypoint\"\n-----------------\n\ndecorator_args.\\ **decorator_args**\\ *(\\*, keyword_only=False, optional=False, is_decoratable_object=None)*\n\n The main decorator of the library. All other decorators are just convenience helpers based on this one.\n\n - ``keyword_only``: Makes the arguments of your decorator keyword-only. Passing any positional arguments to your\n decorator will result in a ``TypeError`` with an appropriate error message.\n - ``optional``: ``optional=True`` allows you to write ``@your_decorator`` instead of ``@your_decorator()``.\n When you apply your decorator without passing any args to it you can omit the empty brackets\n that specify the empty decorator argument list.\n - ``is_decoratable_object``: This argument can be used only when ``keyword_only=False`` and ``optional=True``.\n When the argument list of your decorator is optional and you apply your decorator by passing only a single\n positional argument to the decorator this library has hard time to decide whether that single positional argument\n is an optional decorator argument or a decoratable object. This decision is made by the library function\n ``decorator_args.default_is_decoratable_object(obj)`` function which returns ``True`` if the given single\n positional argument is a function, method, or class. This default behavior is good in most of the cases when\n your decorator receives only simple arguments like integers, strings, bools, etc... However if your decorator\n can receive a single positional argument that can be a function, method, or class, then the default behavior\n isn't suitable. There are several workarounds to this problem, one of them is providing your own\n ``is_decoratable_object(obj)`` implementation through the currently documented decorator argument. You probably\n have additional info to make an accurate distinction between decorator arguments and decoratable objects to\n provide a working ``is_decoratable_object(obj)`` implementation.\n\n In such pathological edge-cases you can also use the following workarounds besides the previously documented\n custom ``is_decoratable_object(obj)`` implementation:\n\n - When you apply your decorator with only a single argument that is a function/method/class you can\n pass the argument as a keyword-argument. This way it will be detected as a decorator argument for sure.\n This is however just a dirty hack that still leaves chance for the users of your decorator to make an\n error. This can result in long debugging sessions.\n - You can make your optional arguments keyword-only with ``keyword_only=True``.\n This completely eliminates the problem.\n - Don't make the argument list of this decorator optional. With a required decorator argument list this\n problem isn't present.\n\n\nHelpers: convenience API\n------------------------\n\nThe convenience API provides a set of decorators that are just \"wrappers\" around the main\n``decorator_args.decorator_args`` decorator. These convenience decorators just bind some of the main decorator\narguments to some constants.\n\n\ndecorator_args.\\ **optional_decorator_args**\\ *(\\*, keyword_only=False, is_decoratable_object=None)*\n\n Works just like the main ``decorator_args.decorator_args`` decorator with ``optional=True``.\n\ndecorator_args.\\ **keyword_only_decorator_args**\\ *(\\*, optional=False)*\n\n Works just like the main ``decorator_args.decorator_args`` decorator with ``keyword_only=True``.\n\ndecorator_args.\\ **optional_keyword_only_decorator_args**\\ *()*\n\n Works just like the main ``decorator_args.decorator_args`` decorator with ``optional=True`` and\n ``keyword_only=True``.\n\n\nImplementing your decorators in a \"twisted\" way\n===============================================\n\nThe tricky implementation of the library ensures that the decorators provided by this library can be applied to your\ndecorators even in some exotic cases:\n\n - `When your decorator is a bound instance/class/static method`_\n - `When your decorator is a bound __call__ magic (instance)method`_\n\n\nWhen your decorator is a bound instance/class/static method\n-----------------------------------------------------------\n\n.. code-block:: python\n\n class AnyClass(object):\n @decorator_args\n def decorator_when_bound(self, decoratable, arg1, arg2):\n ...\n\n # It is important to apply @decorator_args after @classmethod!\n @decorator_args\n @classmethod\n def decorator_when_bound_2(cls, decoratable, arg1, arg2):\n ...\n\n # It is important to apply @decorator_args after @statimethod!\n @decorator_args\n @staticmethod\n def decorator_when_bound_3(decoratable, arg1, arg2):\n ...\n\n\n any_class_instance = AnyClass()\n\n decorator_with_args = any_class_instance.decorator_when_bound\n decorator_with_args_2 = AnyClass.decorator_when_bound_2\n decorator_with_args_3a = any_class_instance.decorator_when_bound_3\n decorator_with_args_3b = AnyClass.decorator_when_bound_3\n\n\nWhen your decorator is a bound __call__ magic (instance)method\n--------------------------------------------------------------\n\n.. code-block:: python\n\n class AnyClass(object):\n @decorator_args\n def __call__(self, decoratable, arg1, arg2):\n ...\n\n\n # Because of the syntactic sugar provided by python it is as simple as:\n decorator_with_args = AnyClass()\n", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/pasztorpisti/decorator-args", "keywords": "optional required keyword only decorator arguments args", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "decorator-args", "package_url": "https://pypi.org/project/decorator-args/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/decorator-args/", "project_urls": { "Homepage": "https://github.com/pasztorpisti/decorator-args" }, "release_url": "https://pypi.org/project/decorator-args/1.1/", "requires_dist": null, "requires_python": "", "summary": "Optional/required/keyword-only decorator arguments made easy.", "version": "1.1" }, "last_serial": 2063662, "releases": { "1.0": [ { "comment_text": "", "digests": { "md5": "b78a895e6455187433f9c49b36946efb", "sha256": "976180904fc5e5f707abfcea652f72c68b506774427da699f8165a3e154e5a45" }, "downloads": -1, "filename": "decorator_args-1.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "b78a895e6455187433f9c49b36946efb", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 3685, "upload_time": "2016-04-14T00:18:33", "url": "https://files.pythonhosted.org/packages/fd/13/0667e2e4d58c03062144dc127b47611b470fd5cbf897417e628aa479c1b0/decorator_args-1.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a05ed2ae299b875d98a3af520e69c886", "sha256": "6c43fdf9134f99447a2006384b462181f3b17c522521a73c13638f9a9ac6ec4e" }, "downloads": -1, "filename": "decorator-args-1.0.tar.gz", "has_sig": false, "md5_digest": "a05ed2ae299b875d98a3af520e69c886", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5580, "upload_time": "2016-04-14T00:18:43", "url": "https://files.pythonhosted.org/packages/83/02/450f9719389aa1285c89c69398bf538f92c78eae58758fee0fdec1d56777/decorator-args-1.0.tar.gz" } ], "1.1": [ { "comment_text": "", "digests": { "md5": "42d9027818378caacaef02e26b853a37", "sha256": "5bc1cce935619b7dea4f9c21fd29b9bf047c56e3290d514e2983e3b4a729afdd" }, "downloads": -1, "filename": "decorator_args-1.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "42d9027818378caacaef02e26b853a37", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 3680, "upload_time": "2016-04-14T12:38:14", "url": "https://files.pythonhosted.org/packages/c1/c3/268341bbc5621d20ff76b90b31d55da82054841784b2f61a9325ad8294ab/decorator_args-1.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "16337954f9e973614a0bcbcf4916824e", "sha256": "8579eb4e051df06892903a4e8c21e7a6ade053a7ec448674ac827bd59195bf66" }, "downloads": -1, "filename": "decorator-args-1.1.tar.gz", "has_sig": false, "md5_digest": "16337954f9e973614a0bcbcf4916824e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8262, "upload_time": "2016-04-14T12:38:38", "url": "https://files.pythonhosted.org/packages/ba/c7/29d10ee1553fdab1c07de9e93d2b9da68a3be33f78036b1bc04ab92db744/decorator-args-1.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "42d9027818378caacaef02e26b853a37", "sha256": "5bc1cce935619b7dea4f9c21fd29b9bf047c56e3290d514e2983e3b4a729afdd" }, "downloads": -1, "filename": "decorator_args-1.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "42d9027818378caacaef02e26b853a37", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 3680, "upload_time": "2016-04-14T12:38:14", "url": "https://files.pythonhosted.org/packages/c1/c3/268341bbc5621d20ff76b90b31d55da82054841784b2f61a9325ad8294ab/decorator_args-1.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "16337954f9e973614a0bcbcf4916824e", "sha256": "8579eb4e051df06892903a4e8c21e7a6ade053a7ec448674ac827bd59195bf66" }, "downloads": -1, "filename": "decorator-args-1.1.tar.gz", "has_sig": false, "md5_digest": "16337954f9e973614a0bcbcf4916824e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8262, "upload_time": "2016-04-14T12:38:38", "url": "https://files.pythonhosted.org/packages/ba/c7/29d10ee1553fdab1c07de9e93d2b9da68a3be33f78036b1bc04ab92db744/decorator-args-1.1.tar.gz" } ] }