{ "info": { "author": "Thomas Gl\u00e4\u00dfle", "author_email": "t_glaessle@gmx.de", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: Public Domain", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Topic :: Software Development" ], "description": "black-magic\n===========\n\n|Tests| |Coverage| |Version| |Downloads| |Unlicense|\n\nMetaprogramming modules that operate on black magic!\n\nCurrently there is only one module available. However, I am all open for\ncool ideas.\n\n\nblack_magic.decorator\n~~~~~~~~~~~~~~~~~~~~~\n\nThis module allows to create wrapper functions that look and behave identical\nto the original function. This is particularly useful for decorators.\n\nPart of the module replicates the functionality of the well-known decorator_\nmodule, but is based on creating AST nodes directly rather than composing and\ncompiling strings.\n\nFurthermore, this module makes it possible to create wrappers with modified\nsignatures. Currently, the only specialized function that is explicitly\ndedicated to this purpose is ``partial``. If you are interested in doing\nmore complex modifications you can pass a dynamically created ``Signature``\nto ``wraps``. If you make something useful, please consider contributing\nyour functionality to this module.\n\n.. _decorator: https://pypi.python.org/pypi/decorator\n\n\n.wraps()\n--------\n\n``wraps`` can be used similarly to the standard ``functools.wraps``\nfunction. However, it returns a real function, i.e. something that will\nhave a useful signature when being inspected with ``help()`` or by other\nmetaprogramming tools. Furthermore, it knows how to copy the signature\nexactly, even remembering object identity of default arguments and\nannotations:\n\n.. code-block:: python\n\n >>> from black_magic.decorator import wraps\n\n >>> def real(a=[]):\n ... pass\n\n >>> @wraps(real)\n ... def fake(*args, **kwargs):\n ... return args\n\n >>> fake()\n ([],)\n\n >>> fake(1)\n (1,)\n\n >>> fake(a=2)\n (2,)\n\n >>> fake()[0] is real()\n True\n\n\nIf you want to get real crazy you can even use ast.expr_'s:\n\n.. code-block:: python\n\n >>> import ast\n >>> fake = wraps(real)(ast.Num(n=1))\n >>> fake(0)\n 1\n\n.. _ast.expr: http://docs.python.org/3.3/library/ast.html?highlight=ast#abstract-grammar\n\n\n**WARNING**: before using ``functools.partial`` with any of the functions in\nthis module, make sure to read the warning below!\n\n\n.partial()\n----------\n\nThis is similar to the ``functools.partial`` function.\n\n.. code-block:: python\n\n >>> from black_magic.decorator import partial\n\n >>> def real(arg):\n ... print(arg)\n >>> partial(real, arg=0)()\n 0\n\nThere are some differences, though:\n\n- this function returns a function object which looks like the input\n function, except for the modified parameters.\n\n- all overwritten parameters are completely removed from the signature. In\n ``functools.partial`` this is true only for arguments bound by position.\n\n- the ``**kwargs`` are stripped first, then ``*args``\n\n .. code-block:: python\n\n >>> partial(lambda a,b,c: (a,b,c), 2, a=1)(3)\n (1, 2, 3)\n\n- by leaving the first argument empty ``partial`` can act as decorator:\n\n .. code-block:: python\n\n >>> @partial(None, 1, bar=0)\n ... def foo(bar, lum):\n ... return bar, lum\n >>> foo()\n (0, 1)\n\n- Note, that the function returned by ``partial(None, ...)`` is just like\n ``partial``: it can bind additional arguments and you can still leave the\n first parameter unspecified. This has weird properties and should not be\n used in production code, but I thought it would be great to add some\n additional brainfuck, to see where it will go.\n\n**CAUTION:** Iterative invocation of ``partial`` (with ``None`` as first\nargument) doesn't hide parameters the same way that ``partial`` applied to\na function does, i.e. you can move bound arguments to the right in later\ncalls. In code:\n\n.. code-block:: python\n\n >>> partial(None, 1)(a=0)(lambda a, b: (a, b))()\n (0, 1)\n\n\n.metapartial()\n--------------\n\nThe returned value can be called like ``partial`` bind a function to the\nparameters given here. In fact, ``partial = metapartial()``.\n\nBinding further keyword arguments via the returned function will overwrite\nkeyword parameters of previous bindings with the same name.\n\n.. code-block:: python\n\n >>> @metapartial(1, a=0, c=3)\n ... def func(a, b, *args, **kwargs):\n ... return (a, b, args, kwargs)\n >>> func(2)\n (0, 1, (2,), {'c': 3})\n\n\n.decorator()\n------------\n\nThis is the canonic utility to create decorators:\n\n.. code-block:: python\n\n >>> from black_magic.decorator import decorator\n\n >>> @decorator\n ... def plus_one(fn):\n ... def fake(*args, **kwargs):\n ... return 1 + fn(*args, **kwargs)\n ... return fake\n\n >>> @plus_one\n ... def mul_plus_one(a, b):\n ... return a * b\n\n >>> mul_plus_one(2, 3)\n 7\n\n\n.flatorator()\n-------------\n\n``flatorator`` imitates the functionality of the well known `decorator`_\nmodule.\n\n.. code-block:: python\n\n >>> from black_magic.decorator import flatorator\n\n >>> @flatorator\n ... def times_two(fn, *args, **kwargs):\n ... return 2 * fn(*args, **kwargs)\n\n >>> @times_two\n ... def add_times_two(a, b):\n ... return a + b\n\n >>> add_times_two(1, 2)\n 6\n\n\nUnder the hood\n--------------\n\nQ: This uses ugly ``str`` concat and ``eval`` code, right?\n\nA: No, it uses ugly `abstract syntax tree`_ code to do its dynamic code generation.\n\n.. _abstract syntax tree: http://docs.python.org/3.3/library/ast.html?highlight=ast#ast\n\nQ: But it's still ugly code, right?\n\nA: Yes.\n\n\nWARNING: performance hits incoming\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nDecorating a function with the tools in this module is a quite costy\noperation, so don't do it very often! Invoking the wrapper is no problem on\nthe other hand.\n\n\nWARNING: functools.partial is evil\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nBe careful when passing ``functools.partial`` objects into ``.wraps``, or\nany black magic functions more generally. ``functools.partial`` features\nvery unsensible handling of arguments that are bound by keyword. These, and\nall subsequent arguments, become keyword-only parameters. Consider the\nfollowing example:\n\n.. code-block:: python\n\n >>> import functools\n >>> def func(a, b, *args, **kwargs):\n ... return (a, b, args, kwargs)\n >>> part = functools.partial(func, a=0)\n >>> part(1)\n Traceback (most recent call last):\n ...\n TypeError: func() got multiple values for argument 'a'\n\nFurthermore, note that the ``*args`` parameter becomes completely\ninaccessible, forever!\n\nFor compatibility between python versions and ease of use, I chose to handle\n``functools.partial`` objects as if you had actually used\n``black_magic.decorator.partial`` with the same arguments, i.e.:\n\n.. code-block:: python\n\n >>> wrap = wraps(part)(part)\n >>> wrap(1, 2, c=3)\n (0, 1, (2,), {'c':3})\n\nNote, the signature imposed by ``.wraps(functools.partial(f))`` is\nequivalent to the signature of ``.wraps(.partial(f))``, which might come\nunexpected.\n\n\nTests\n~~~~~\n\nThis module has been tested to work on python{2.6, 2.7, 3.3, 3.4, 3.5}\nand PyPy1.9 using `Travis CI`_, and tested with python 3.2 locally.\n\n.. _Travis CI: https://travis-ci.org/\n\n\n\n.. |Tests| image:: https://api.travis-ci.org/coldfix/black-magic.svg?branch=master\n :target: https://travis-ci.org/coldfix/black-magic\n :alt: Tests\n\n.. |Coverage| image:: https://coveralls.io/repos/coldfix/black-magic/badge.svg?branch=master\n :target: https://coveralls.io/r/coldfix/black-magic\n :alt: Coverage\n\n.. |Version| image:: http://coldfix.de:8080/v/black-magic/badge.svg\n :target: https://pypi.python.org/pypi/black-magic/\n :alt: Latest Version\n\n.. |Downloads| image:: http://coldfix.de:8080/d/black-magic/badge.svg\n :target: https://pypi.python.org/pypi/black-magic/#downloads\n :alt: Downloads\n\n.. |Unlicense| image:: http://coldfix.de:8080/license/black-magic/badge.svg\n :target: http://unlicense.org/\n :alt: Unlicense\n\n\nChangelog\n~~~~~~~~~\n\n0.0.12\n------\nDate: 26.12.2015\n\n- fix missing UNLICENSE file in source distribution\n- some internal maintenance\n\n0.0.11\n------\nDate: 25.12.2015\n\n- add support for python 3.5\n\n0.0.10\n------\n\n- add compatibility with python3.4\n\n0.0.9\n-----\n\n- fix signature of ``black_magic.decorator.partial``: remove named\n parameter ``func`` that can prevent binding of the a parameter with the\n same name into ``**kwargs``\n- return value of ``partial`` can now be used for further parameter\n (re-)binding if the function was left open. CAREFUL: this might have\n unexpected characteristics, such as moving positional parameters to the\n right in later calls.\n- add ``metapartial`` function, that accepts only ``*args, **kwargs`` to be\n bound, while the function to be used can only be specified in a second\n step.\n- slightly improve performance of ``black_magic.decorator``. Is now\n approximately the same as the performance of the ``decorator`` module.\n\n0.0.8\n-----\n\n- convert all ``functools.partial`` to ``black_magic.partial`` with the same\n parameters.\n\n0.0.7\n-----\n\n- partial support for ``functools.partial``\n\n0.0.6\n-----\n\n- fix ``functools.update_wrapper`` emulation in ``black_magic.decorator.wraps()``\n\n0.0.5\n-----\n\n- add ``black_magic.decorator.partial``\n\n0.0.4\n-----\n\n- support any callable to be passed to ``ASTorator.decorate``\n- convert README to .rst", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/coldfix/black-magic", "keywords": "", "license": "Unlicense", "maintainer": "", "maintainer_email": "", "name": "black-magic", "package_url": "https://pypi.org/project/black-magic/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/black-magic/", "project_urls": { "Homepage": "https://github.com/coldfix/black-magic" }, "release_url": "https://pypi.org/project/black-magic/0.0.12/", "requires_dist": null, "requires_python": "", "summary": "Decorator utility that operates on black magic", "version": "0.0.12" }, "last_serial": 1877744, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "babd1b55fcc991a5477669416d0545e6", "sha256": "0a8c9f9151d140f71baff47c3cfd61e25c58177113ec18c1538aa540a9c44f57" }, "downloads": -1, "filename": "black-magic-0.0.1.tar.gz", "has_sig": false, "md5_digest": "babd1b55fcc991a5477669416d0545e6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6341, "upload_time": "2013-09-17T04:53:21", "url": "https://files.pythonhosted.org/packages/73/7e/8694b639d41cda456787e497b9602c1035c9994786058a81b17df5e6964b/black-magic-0.0.1.tar.gz" } ], "0.0.10": [ { "comment_text": "", "digests": { "md5": "d913092a355e6d97013ea0a8ca5c4e12", "sha256": "a17428a6973e85e66a5b717a8a724e1dfdb601ed5523a4dd13a6c7992885ca64" }, "downloads": -1, "filename": "black-magic-0.0.10.tar.gz", "has_sig": false, "md5_digest": "d913092a355e6d97013ea0a8ca5c4e12", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16171, "upload_time": "2014-05-28T17:45:54", "url": "https://files.pythonhosted.org/packages/83/ac/09b06aa94fa61ad6d7d1f17e5e80c8d60db47d3a92f09920088a331c489c/black-magic-0.0.10.tar.gz" } ], "0.0.11": [ { "comment_text": "", "digests": { "md5": "6d1c670df4cb746211b2cba8f8202edd", "sha256": "66581d1dcbac115d1dd5085d8c087763e2f00fc7db7114fddc9cc2ab4040a28f" }, "downloads": -1, "filename": "black-magic-0.0.11.tar.gz", "has_sig": false, "md5_digest": "6d1c670df4cb746211b2cba8f8202edd", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13740, "upload_time": "2015-12-25T14:09:32", "url": "https://files.pythonhosted.org/packages/c9/b5/b6ed123c113382341032c217637ed87014511b9978c199372ed46a6206b4/black-magic-0.0.11.tar.gz" } ], "0.0.12": [ { "comment_text": "", "digests": { "md5": "ebcf1a75bd636ac5e0f623c95db3a114", "sha256": "4d433fb9ebebf0a62ddf8108c1d21af467066de50a934a92f875058f52f44071" }, "downloads": -1, "filename": "black-magic-0.0.12.tar.gz", "has_sig": false, "md5_digest": "ebcf1a75bd636ac5e0f623c95db3a114", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13495, "upload_time": "2015-12-26T00:25:16", "url": "https://files.pythonhosted.org/packages/bd/3b/de3f4022b111afae930424e96cf731754b948e4ce3d1dea83825423b2c8f/black-magic-0.0.12.tar.gz" } ], "0.0.2": [ { "comment_text": "", "digests": { "md5": "eee384c559b01c29e5f5b8a35ada7e6c", "sha256": "11cfb9a2a5040108343dd42b7e6cbb69afb18f2626a83a350422417454a145e0" }, "downloads": -1, "filename": "black-magic-0.0.2.tar.gz", "has_sig": false, "md5_digest": "eee384c559b01c29e5f5b8a35ada7e6c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6786, "upload_time": "2013-09-19T03:51:29", "url": "https://files.pythonhosted.org/packages/0b/62/69d14abc2c41731bf95d2ff9db99b054382560ab6094515088a6ff6d9fd8/black-magic-0.0.2.tar.gz" } ], "0.0.3": [ { "comment_text": "", "digests": { "md5": "21ad5d94d2117c4142d010ce2677c468", "sha256": "fe2683ad3dc1e97ad340210560164b01c9a8cfe16f6fd4c20d3e61e31818993f" }, "downloads": -1, "filename": "black-magic-0.0.3.tar.gz", "has_sig": false, "md5_digest": "21ad5d94d2117c4142d010ce2677c468", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10341, "upload_time": "2013-10-03T13:33:20", "url": "https://files.pythonhosted.org/packages/d0/bd/f5d24681cf671a7b6759dd228927976961a681afa165f50330d4bd3d7513/black-magic-0.0.3.tar.gz" } ], "0.0.4": [ { "comment_text": "", "digests": { "md5": "adac8bdfedb4f18671a99272b9b79410", "sha256": "fe10b7b426fd81f3f5fd0a905dcdb6ee5f311fa19769ea918b92333d8a461a3f" }, "downloads": -1, "filename": "black-magic-0.0.4.tar.gz", "has_sig": false, "md5_digest": "adac8bdfedb4f18671a99272b9b79410", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10329, "upload_time": "2014-01-09T17:49:14", "url": "https://files.pythonhosted.org/packages/c4/a7/00c2799202c578090569e5724129fae41024a84c134667772c7c4196f0e6/black-magic-0.0.4.tar.gz" } ], "0.0.5": [ { "comment_text": "", "digests": { "md5": "53916763798f9c65fdeab8ce2cba4577", "sha256": "15e7434017acb238257849594c3c5670504ea675fe08001890d92195701656be" }, "downloads": -1, "filename": "black-magic-0.0.5.tar.gz", "has_sig": false, "md5_digest": "53916763798f9c65fdeab8ce2cba4577", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12859, "upload_time": "2014-02-14T06:13:54", "url": "https://files.pythonhosted.org/packages/62/c5/c1a9e55c60c99a3aed917fa4ac1b17fd3f62193105865ffdd8d2faa38af6/black-magic-0.0.5.tar.gz" } ], "0.0.6": [ { "comment_text": "", "digests": { "md5": "8232f0787ace32bbc11c2e2637442edb", "sha256": "48fe9e1ec8ce104296be2a11e4f01cfcc22ee58c04c62029fee08dfbdbd45787" }, "downloads": -1, "filename": "black-magic-0.0.6.tar.gz", "has_sig": false, "md5_digest": "8232f0787ace32bbc11c2e2637442edb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13380, "upload_time": "2014-02-24T05:14:07", "url": "https://files.pythonhosted.org/packages/c8/df/c5c3f7b609e6b13405c70aa7543ec7bbd904e4755d32e0db4f4b90211c6d/black-magic-0.0.6.tar.gz" } ], "0.0.7": [ { "comment_text": "", "digests": { "md5": "89fac9e41255e4c8535c143b1604eebe", "sha256": "39d3cb4957061a2f6bb59eff6db8ed41f1a1912f9ff5edf4aecf0ad584528a5d" }, "downloads": -1, "filename": "black-magic-0.0.7.tar.gz", "has_sig": false, "md5_digest": "89fac9e41255e4c8535c143b1604eebe", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14826, "upload_time": "2014-03-12T20:38:26", "url": "https://files.pythonhosted.org/packages/aa/63/920c917b3faa29fe2c21601133d7978322131c9bab87764b16033f2e3215/black-magic-0.0.7.tar.gz" } ], "0.0.8": [ { "comment_text": "", "digests": { "md5": "9811a08d9ed912a360ca18898608bbd0", "sha256": "1a3bf8c3319a66bc1bb80c4c404757ce5497645cfb86a4ba202a9749bc9a8536" }, "downloads": -1, "filename": "black-magic-0.0.8.tar.gz", "has_sig": false, "md5_digest": "9811a08d9ed912a360ca18898608bbd0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14537, "upload_time": "2014-03-13T01:59:20", "url": "https://files.pythonhosted.org/packages/cc/74/51c3c00a366f630fa28211c3b00c2a21a0489671e1417bd54fad11d0d991/black-magic-0.0.8.tar.gz" } ], "0.0.9": [ { "comment_text": "", "digests": { "md5": "766829079139d7de5650fd6a68d2f689", "sha256": "97a2f8264e4260caa4a590acc145dcff6747856b124281388ae3ddc3b5505429" }, "downloads": -1, "filename": "black-magic-0.0.9.tar.gz", "has_sig": false, "md5_digest": "766829079139d7de5650fd6a68d2f689", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 15978, "upload_time": "2014-03-21T12:04:34", "url": "https://files.pythonhosted.org/packages/8d/51/23608511d6a2215a628715df01e9ce18b2dd442928737fded3cbbcefd6de/black-magic-0.0.9.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "ebcf1a75bd636ac5e0f623c95db3a114", "sha256": "4d433fb9ebebf0a62ddf8108c1d21af467066de50a934a92f875058f52f44071" }, "downloads": -1, "filename": "black-magic-0.0.12.tar.gz", "has_sig": false, "md5_digest": "ebcf1a75bd636ac5e0f623c95db3a114", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13495, "upload_time": "2015-12-26T00:25:16", "url": "https://files.pythonhosted.org/packages/bd/3b/de3f4022b111afae930424e96cf731754b948e4ce3d1dea83825423b2c8f/black-magic-0.0.12.tar.gz" } ] }