{ "info": { "author": "Jared Gillespie", "author_email": "jaredlgillespie@hotmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Utilities" ], "description": "Attach Me\n=========\n\n.. image:: https://img.shields.io/travis/JaredLGillespie/attach.me.svg\n :alt: Travis\n :target: https://travis-ci.org/JaredLGillespie/attach.me\n.. image:: https://img.shields.io/coveralls/github/JaredLGillespie/attach.me.svg\n :alt: Coveralls github\n :target: https://coveralls.io/github/JaredLGillespie/attach.me\n.. image:: https://img.shields.io/pypi/v/attach.me.svg\n :alt: PyPI\n :target: https://pypi.org/project/attach.me/\n.. image:: https://img.shields.io/pypi/wheel/attach.me.svg\n :alt: PyPI - Wheel\n :target: https://pypi.org/project/attach.me/\n.. image:: https://img.shields.io/pypi/pyversions/attach.me.svg\n :alt: PyPI - Python Version\n :target: https://pypi.org/project/attach.me/\n.. image:: https://img.shields.io/pypi/l/attach.me.svg\n :alt: PyPI - License\n :target: https://pypi.org/project/attach.me/\n\nA library for attaching additional functionality around existing functions, such as before or after execution, or given\na raised exception or specific return value.\n\n.. code-block:: python\n\n @attach(on_before=lambda: print('Initializing connection'),\n on_after=lambda: print('Connect successfully established'),\n on_error=lambda x: print('Erred establishing connection: %s' % x),\n on_return=lambda x: print('Returned connection: %s' % x))\n def connection(conn_str, params):\n conn = db(conn_str, params)\n return db.open()\n\nInstallation\n------------\n\nThe latest version of attach.me is available via ``pip``:\n\n.. code-block:: python\n\n pip install attach.me\n\nAlternatively, you can download and install from source:\n\n.. code-block:: python\n\n python setup.py install\n\nGetting Started\n---------------\n\nThe ``attach`` function contains the following signature:\n\n.. code-block:: python\n\n @attach(on_before=None, on_after=None, on_error=None, on_return=None,\n override_error=False, override_return=False, before_has_kwargs=False)\n def func(...)\n ...\n\nIt serves as both a function decorator, and a runnable wrapper and is configurable through it's dynamic parameters. Most\nof which are function callbacks which allow the user to highly configure the additional behavior.\n\nBefore / After Execution\n^^^^^^^^^^^^^^^^^^^^^^^^\n\nEither prior to the wrapped function being executed, or afterwards, another function can be called. The most simplistic\nuse case for this is logging the beginning and ending of execution of a function.\n\n.. code-block:: python\n\n @attach(on_before=lambda: logging.info('Execution began'), on_after=lambda: logging.info('Execution ended'))\n def func():\n ...\n\nIf an exception is raised by the wrapped function (or the ``on_before`` function), the ``on_after`` function isn't\ncalled.\n\nMore complex usage comes from digesting the parameters meant for the wrapped function and transforming them in some way.\nThis is accomplished by simply returning an object from the ``on_before`` function and the values will be used instead\nof the ones passed in.\n\n.. code-block:: python\n\n def sanitize(string):\n # Do some stuff\n return new_string\n\n @attach(on_before=lambda x: sanitize(x))\n def func(string):\n ...\n\nIf an iterable is returned, it is used as the args of the wrapped function. The ``before_with_kwargs`` argument can be\nset to ``True`` to specify that the return value be used as the kwargs of the wrapped function (which means it should\nbe a dictionary. If an iterable is returned and this parameter is set, the last value is used as the kwargs, and the\nrest as the args.\n\n.. code-block:: python\n\n def sanitize(string):\n # Do some stuff\n return new_string\n\n @attach(on_before=lambda x: sanitize(x), {'use_ssl': True})\n def func(string):\n ...\n\nError Handling\n^^^^^^^^^^^^^^\n\nThe ``on_error`` can be used to execute a function if an exception is raised. By default, the original exception is\nstill raised after the ``on_error`` callback is called. This can be changed by setting ``override_error`` to ``True``.\nThis can be used to instead return a value or raise a different exception.\n\n.. code-block:: python\n\n def on_error(e):\n print('Caught error: ' + str(e))\n if isinstance(e, TypeError):\n return -1\n raise\n\n @attach(on_error=on_error, override_error=True)\n def func():\n raise TypeError\n\n # -1 is returned instead of raising TypeError\n\nReturn Value Handling\n^^^^^^^^^^^^^^^^^^^^^\n\nLike raised exception, return values can consumed by a ``on_return`` function in a similar manner. By default, the\noriginal return value is still returned after the ``on_return`` callback is called. This can be changed by setting\n``override_return`` to ``True``. A common use case for this is when interacting with functions that yield a return value\nthat indicates a failed state (like ``-1`` or ``None``), while other values indicate a successful state (like ``0`` or\nan ``object``). This behavior can be transformed into a simple bool ``True`` or ``False`` return value instead.\n\n.. code-block:: python\n\n def on_return(val):\n if val in (-1, None):\n return False\n return True\n\n @attach(on_return=on_return, override_return=True)\n def func()\n return -1\n\n # False is returned instead of -1\n\nIf an exception is raised by the wrapped function (or the ``on_before`` or ``on_after`` functions), the ``on_return``\nfunction isn't called.\n\nAdvanced Usage\n--------------\n\nInstead of using as a decorator, ``attach`` can be used as an instead for wrapping an arbitrary number of function\ncalls. This can be achieved via the ``run`` method.\n\n.. code-block:: python\n\n def func_a():\n ...\n\n def func_b():\n ...\n\n attacher = attach(on_before=..., on_after=..., on_error=..., on_return=...)\n\n # Using same configured attach instance\n attach.run(func_a, args, kwargs)\n attach.run(func_b, args, kwargs)\n\nBesides using the provided ``run`` method, like any decorator functions can be locally wrapped, passed around, and\nexecuted.\n\n.. code-block:: python\n\n def func():\n ...\n\n attacher = attach(on_before=..., on_after=..., on_error=..., on_return=...)\n attach_func = attacher(func)\n attach_func(args, kwargs)\n\n # Or as a one-off like so\n attach(...)(func)(args, kwargs)\n\nEach of the function parameters that can be passed into ``attach``, can actually be configured to accepts different\nnumber of parameters depending on the function. They can each either accept 0 parameters, the parameters that would be\ntypically passed in, or the wrapped function's args and kwargs in addition to the parameters typically given.\n\nOptionally passing in the args and kwargs allows for building more complex callback functions. Each of the possible\nfunction variations are shown below.\n\n.. code-block:: python\n\n def on_before(): ...\n def on_before(*args, **kwargs): ...\n\n def on_after(): ...\n def on_after(*args, **kwargs): ...\n\n def on_error(): ...\n def on_error(error): ...\n def on_error(error, *args, **kwargs): ...\n\n def on_return(): ...\n def on_return(value): ...\n def on_return(value, *args, **kwargs): ...\n\nContribution\n------------\n\nContributions or suggestions are welcome! Feel free to `open an issue`_ if a bug is found or an enhancement is desired,\nor even a `pull request`_.\n\n.. _open an issue: https://github.com/jaredlgillespie/attach.me/issues\n.. _pull request: https://github.com/jaredlgillespie/attach.me/compare\n\nChangelog\n---------\n\nAll changes and versioning information can be found in the `CHANGELOG`_.\n\n.. _CHANGELOG: https://github.com/JaredLGillespie/attach.me/blob/master/CHANGELOG.rst\n\nLicense\n-------\n\nCopyright (c) 2018 Jared Gillespie. See `LICENSE`_ for details.\n\n.. _LICENSE: https://github.com/JaredLGillespie/attach.me/blob/master/LICENSE.txt\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/jaredlgillespie/attach.me", "keywords": "attach.me attach decorator", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "attach.me", "package_url": "https://pypi.org/project/attach.me/", "platform": "", "project_url": "https://pypi.org/project/attach.me/", "project_urls": { "Homepage": "https://github.com/jaredlgillespie/attach.me" }, "release_url": "https://pypi.org/project/attach.me/0.1.1/", "requires_dist": null, "requires_python": "", "summary": "A library for attaching additional functionality around existing functions.", "version": "0.1.1" }, "last_serial": 4089184, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "8ce104ca44983f4b52d220520e2df44e", "sha256": "fc594b2319a9f361d290167724d184586eda92ef09afc9b55979d73f14753055" }, "downloads": -1, "filename": "attach.me-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "8ce104ca44983f4b52d220520e2df44e", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7265, "upload_time": "2018-06-20T05:48:42", "url": "https://files.pythonhosted.org/packages/47/b4/a2863e8da8d31ac53c9f018225ad8adf7aafb03cd14a7b37e855d7b58b2f/attach.me-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "50eaa9eefb8f14e305356f30f7db318f", "sha256": "39d35fc95d5faad7aca8237670c0d77833759caedb75bdb2b539cc9c55a8bbd0" }, "downloads": -1, "filename": "attach.me-0.1.0.tar.gz", "has_sig": false, "md5_digest": "50eaa9eefb8f14e305356f30f7db318f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7208, "upload_time": "2018-06-20T05:48:43", "url": "https://files.pythonhosted.org/packages/20/89/eb29034ac456de07d7808f0e96310b5130d19e4a0e22f6705bafcf03d9c2/attach.me-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "bb438bffcf9d152a7b88260478b9fca6", "sha256": "84f155a1be4de633be600756964c007ea125dca6064313a2c223a07ca8c5a223" }, "downloads": -1, "filename": "attach.me-0.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "bb438bffcf9d152a7b88260478b9fca6", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7266, "upload_time": "2018-07-21T20:05:34", "url": "https://files.pythonhosted.org/packages/18/4a/35b1dc6d434cff75db1ad141d2dfc8584b189d39ea640a170eaa7cb118a8/attach.me-0.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "02a2c8a01b7c916124d3e9709744dd9e", "sha256": "84ed03b95ddeec38f2f3111a43a192a6aff7b492a5bfd52b478bf6dc907e2c6d" }, "downloads": -1, "filename": "attach.me-0.1.1.tar.gz", "has_sig": false, "md5_digest": "02a2c8a01b7c916124d3e9709744dd9e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7218, "upload_time": "2018-07-21T20:05:36", "url": "https://files.pythonhosted.org/packages/27/57/b4792161ca3e7e403e1c112cbf5970d0fa98b6886c4c99fb2509d0a9c5cd/attach.me-0.1.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "bb438bffcf9d152a7b88260478b9fca6", "sha256": "84f155a1be4de633be600756964c007ea125dca6064313a2c223a07ca8c5a223" }, "downloads": -1, "filename": "attach.me-0.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "bb438bffcf9d152a7b88260478b9fca6", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7266, "upload_time": "2018-07-21T20:05:34", "url": "https://files.pythonhosted.org/packages/18/4a/35b1dc6d434cff75db1ad141d2dfc8584b189d39ea640a170eaa7cb118a8/attach.me-0.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "02a2c8a01b7c916124d3e9709744dd9e", "sha256": "84ed03b95ddeec38f2f3111a43a192a6aff7b492a5bfd52b478bf6dc907e2c6d" }, "downloads": -1, "filename": "attach.me-0.1.1.tar.gz", "has_sig": false, "md5_digest": "02a2c8a01b7c916124d3e9709744dd9e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7218, "upload_time": "2018-07-21T20:05:36", "url": "https://files.pythonhosted.org/packages/27/57/b4792161ca3e7e403e1c112cbf5970d0fa98b6886c4c99fb2509d0a9c5cd/attach.me-0.1.1.tar.gz" } ] }