{ "info": { "author": "Maxim Kochurov", "author_email": "maxim.v.kochurov@gmail.com", "bugtrack_url": null, "classifiers": [], "description": "******\nbiwrap\n******\nYet simple util to make wrapper with optional arguments\n\nInstallation\n############\n\nMaster branch\n\n.. code-block:: bash\n\n pip install git+https://github.com/ferrine/biwrap\n\nLatest release\n\n.. code-block:: bash\n\n pip install biwrap\n\nProblem outlined\n################\n**Readability and transparent implementation is important.** Wrappers is an advanced topic in programming and making them readable in some cases is difficult. The particular case is parametrizable wrapper. It can either be called with or without arguments. Implementation to handle this case is often tricky and looks weird (see `SO thread `__). This package solves the problem and provides with simple and generic solution.\n\nAPI\n###\nA minimal snippet to apply it to your problem.\n\n.. code-block:: python\n\n import biwrap\n\n @biwrap.biwrap\n def wrapper(fn, arg1='default', arg2='default'):\n def wrapped(*fn_args, **fn_kwargs):\n ... # depends on `arg1`, `arg2`\n return wrapped\n\n @wrapper # use defaults\n def func1(a, b):\n ...\n\n @wrapper(arg1='non default') # change defaults\n def func2(a, b):\n ...\n\nExample\n#######\n\nLet's discuss a case when it is needed to put functions into a registry. Some functions can have alias names.\n\nNaive Solution\n**************\n\n.. code-block:: python\n\n def register(alias=None):\n def inner(fn):\n if fn.__name__ not in register.storage:\n register.storage[fn.__name__] = fn\n elif register.storage[fn.__name__] is not fn:\n raise KeyError('{} is already in storage'.format(fn.__name__))\n if alias is not None and alias not in register.storage:\n register.storage[alias] = fn\n elif alias is not None:\n raise KeyError('{} is already in storage'.format(alias))\n return fn\n return inner\n register.storage = {}\n\n\n @register()\n def f1(a):\n return a\n\n print(register.storage)\n #> {'f1': }\n\n\n @register(alias='fn3')\n def f2(a):\n return a\n\n print(register.storage)\n #> {'f1': , 'f2': , 'fn3': }\n\n\nAnalysis\n========\n\nThe above example shows redundancy in\n\n- decorator definition has double nesting (double ``def``)\n- usage requires trailing parenthesis ``@register()`` even in case we do not use optional argument\n\nMore readable code should avoid these two points and look like:\n\n.. code-block:: python\n\n def register(fn, alias=None):\n ...\n\n @register\n def f1(a):\n return a\n\n @register(alias='fn3') # <- (1)\n def f2(a):\n return a\n\nNaive implementation of the above API won't work. Line marked above as ``(1)`` will fail as first argument ``fn`` is not passed. But we want the output to be the same.\n\nBetter solution\n***************\n\n.. code-block:: python\n\n import biwrap\n\n @biwrap.biwrap\n def register(fn, alias=None):\n if fn.__name__ not in register.storage:\n register.storage[fn.__name__] = fn\n elif register.storage[fn.__name__] is not fn:\n raise KeyError('{} is already in storage'.format(fn.__name__))\n if alias is not None and alias not in register.storage:\n register.storage[alias] = fn\n elif alias is not None:\n raise KeyError('{} is already in storage'.format(alias))\n return fn\n register.storage = {}\n\n @register\n def f1(a):\n return a\n\n print(register.storage)\n #> {'f1': }\n\n @register(alias='fn3')\n def f2(a):\n return a\n\n print(register.storage)\n #> {'f1': , 'f2': , 'fn3': }\n\n\nFunctionality Overview\n######################\nSome corner cases may exist and custom coding can create a boilerplate for each usecase (see this `SO thread `__). This package takes the best and implements yet simple but generic solution to resolve them all(?).\n\nSetup\n*****\n\nLet's take a simple wrapper as an example. It will print ``hi`` or ``bye`` depending on parametrization, default is ``hi``.\n\n.. code-block:: python\n\n import biwrap\n\n @biwrap.biwrap\n def hiwrap(fn, hi=True):\n def new(*args, **kwargs):\n if hi:\n print('hi')\n else:\n print('bye')\n return fn(*args, **kwargs)\n return new\n\nCases\n*****\n\nFunction wrapping\n=================\nDefined wrapper can be used in both ways\n\n.. code-block:: python\n\n @hiwrap\n def fn(n):\n print(n)\n fn(1)\n #> hi\n #> 1\n\n @hiwrap(hi=False)\n def fn(n):\n print(n)\n fn(1)\n #> bye\n #> 1\n\n\nBound method wrapper\n=====================\n\n``biwrap`` also works for bound methods. As seen in `SO thread `__ this can be a problem as first positional argument is ``self`` instead of a function.\n\n.. code-block:: python\n\n class W:\n def __init__(self, n):\n self.n = n\n\n @biwrap.biwrap\n def wrap(self, fn, text='hi'):\n def wrapped(*args, **kwargs):\n for _ in range(self.n):\n print(text)\n return fn(*args, **kwargs)\n return wrapped\n wr = W(3)\n\n @wr.wrap\n def fn(n):\n print(n)\n\n fn(1)\n #> hi\n #> hi\n #> hi\n #> 1\n\n @wr.wrap(text='bye')\n def fn(n):\n print(n)\n\n wr.n = 2\n fn(2)\n #> bye\n #> bye\n #> 2\n\nClass methods / properties wrapping\n===================================\n\nImplementation deals with these cases as well\n\n.. code-block:: python\n\n class O:\n def __init__(self, n):\n self.n = n\n\n @classmethod\n @hiwrap\n def fn(cls, n):\n print(n)\n\n @property\n @hiwrap(hi=False)\n def num(self):\n return self.n\n\n\n o = O(2)\n o.fn(1)\n #> hi\n #> 1\n print(o.num)\n #> bye\n #> 2\n\nWrapper as a function\n=====================\n\nFunction like call is OK too\n\n.. code-block:: python\n\n def fn(n):\n print(n)\n\n fn = hiwrap(fn, hi=False)\n fn(1)\n #> bye\n #> 1\n\n", "description_content_type": null, "docs_url": null, "download_url": "https://github.com/ferrine/biwrap/archive/v0.1.6.zip", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/ferrine/biwrap", "keywords": "", "license": "MIT License", "maintainer": "", "maintainer_email": "", "name": "biwrap", "package_url": "https://pypi.org/project/biwrap/", "platform": "", "project_url": "https://pypi.org/project/biwrap/", "project_urls": { "Download": "https://github.com/ferrine/biwrap/archive/v0.1.6.zip", "Homepage": "https://github.com/ferrine/biwrap" }, "release_url": "https://pypi.org/project/biwrap/0.1.6/", "requires_dist": null, "requires_python": "", "summary": "Yet simple util to make wrapper with optional arguments", "version": "0.1.6" }, "last_serial": 3487628, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "49a2bb2fce4e584fbb5b16f35e3f0e1e", "sha256": "e2031dd5620a2f40e2566044cb15c14e2dbb2719dd3f3e106435a44485d45c88" }, "downloads": -1, "filename": "biwrap-0.1.0.tar.gz", "has_sig": false, "md5_digest": "49a2bb2fce4e584fbb5b16f35e3f0e1e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1098, "upload_time": "2018-01-13T13:07:47", "url": "https://files.pythonhosted.org/packages/38/d5/73d3c4d4b1f0dc6cbb640c1e604a1a2d75868834e65bb52a61872165b184/biwrap-0.1.0.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "474a42287d9a06bb07ff272183bb60f9", "sha256": "24b37c4a6049f19436848e2a3370ff34c8231e4dcda9f1a2eedf23b12761cf9b" }, "downloads": -1, "filename": "biwrap-0.1.2.tar.gz", "has_sig": false, "md5_digest": "474a42287d9a06bb07ff272183bb60f9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4283, "upload_time": "2018-01-13T20:55:15", "url": "https://files.pythonhosted.org/packages/b3/27/e6011f75c7572ae69f00e29b8a6c68e5eb9d00c3583a6a5862aea3fff2ea/biwrap-0.1.2.tar.gz" } ], "0.1.3": [ { "comment_text": "", "digests": { "md5": "052e397e816157944aa9b7889bde6ca0", "sha256": "0c51f04764f405d1e63d303decf07422afc42fbeb84b4472e758617cd5e6643b" }, "downloads": -1, "filename": "biwrap-0.1.3.tar.gz", "has_sig": false, "md5_digest": "052e397e816157944aa9b7889bde6ca0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4330, "upload_time": "2018-01-13T20:57:34", "url": "https://files.pythonhosted.org/packages/dd/3e/f1cb50ef067a143e47ce7f8e502e0915aadadaaf5e7d9100d6cfd2293a81/biwrap-0.1.3.tar.gz" } ], "0.1.4": [ { "comment_text": "", "digests": { "md5": "dfc2e7a364123bef449ffcac7d9d09e0", "sha256": "c0c8c15ac520a3c569d84808cb054494d959c2d925f9167af6a452ecb37dff0d" }, "downloads": -1, "filename": "biwrap-0.1.4.tar.gz", "has_sig": false, "md5_digest": "dfc2e7a364123bef449ffcac7d9d09e0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 3723, "upload_time": "2018-01-13T21:00:03", "url": "https://files.pythonhosted.org/packages/c8/e9/f33dc8723307b0d43164d9d7b6c626085c3b0b2e24b93b12974685204617/biwrap-0.1.4.tar.gz" } ], "0.1.5": [ { "comment_text": "", "digests": { "md5": "7e8658947a7f729e9620b76e3db28617", "sha256": "633f275d09e12706b0b96fb7f3b246ecac816470a04112e1d1dc5c4c37665634" }, "downloads": -1, "filename": "biwrap-0.1.5.tar.gz", "has_sig": false, "md5_digest": "7e8658947a7f729e9620b76e3db28617", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 3743, "upload_time": "2018-01-13T21:03:23", "url": "https://files.pythonhosted.org/packages/b2/10/dd29e16f2be4ce7250791f94e9901987d698bb7deb33c79007f77c69aa80/biwrap-0.1.5.tar.gz" } ], "0.1.6": [ { "comment_text": "", "digests": { "md5": "10b52d62edcdb656e72ae1bfb67cb821", "sha256": "f6346f9973727d101258cf03e5c343197b8fc50a8f7fe80353e808581a021450" }, "downloads": -1, "filename": "biwrap-0.1.6.tar.gz", "has_sig": false, "md5_digest": "10b52d62edcdb656e72ae1bfb67cb821", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 3891, "upload_time": "2018-01-13T22:33:07", "url": "https://files.pythonhosted.org/packages/ac/54/78d4d5459d7385f90908185641647ff2e8ed4a4b5c239976f78e26888679/biwrap-0.1.6.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "10b52d62edcdb656e72ae1bfb67cb821", "sha256": "f6346f9973727d101258cf03e5c343197b8fc50a8f7fe80353e808581a021450" }, "downloads": -1, "filename": "biwrap-0.1.6.tar.gz", "has_sig": false, "md5_digest": "10b52d62edcdb656e72ae1bfb67cb821", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 3891, "upload_time": "2018-01-13T22:33:07", "url": "https://files.pythonhosted.org/packages/ac/54/78d4d5459d7385f90908185641647ff2e8ed4a4b5c239976f78e26888679/biwrap-0.1.6.tar.gz" } ] }