{ "info": { "author": "Malthe Borch", "author_email": "mborch@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "Programming Language :: Python" ], "description": "Overview\n========\n\nThis library provides a mechanism to use partial application on bound\nmethods using AST (abstract syntax tree) transformation. You can use\npartial application as an optimization method, an alternative to code\ngeneration (either indirectly or through the AST abstraction).\n\nThe concrete approach lies somewhere between \"currying\" and\ncooking. We interpret the Python-code manually by walking the AST,\nfollowing standard Python logic (literally interpreting every\nnode). Computations that can be carried out while walking are saved\nfor later reference (and discarded when possible). When possible,\ncomputations are carried out using the running interpreter.\n\nUsage\n-----\n\nYou use the ``cook`` function on any bound method.\n\n >>> from curry import cook\n >>> cooked = cook(some_bound_method)\n\nExample\n-------\n\nThe starting point is an instance of some class::\n\n >>> class Example(object):\n ... def __init__(self, value):\n ... self.value = value\n ...\n ... def __call__(self, other):\n ... return self.value + other\n\nWe can then use partial application on the bound call-method of some\ninstance::\n\n >>> from curry import cook\n >>> example = Example(1)\n >>> cooked = cook(example.__call__)\n >>> cooked(1)\n 2\n\nAdditional examples are included as part of a functional test suite;\nthey also serve as documentation and are a good starting point to\nlearn when and how to use partial application.\n\nPickling\n--------\n\nThe library includes an alternative to the built-in ``pickle`` module\n(and its C-extension counterpart)::\n\n >>> from curry import dumps, loads\n >>> p = dumps(some_object)\n >>> some_object = loads(p)\n\nWhat makes these functions interesting is their performance and space\nproperties. The \"pickles\" generated are typically 50% smaller and may\nbe up to 50% faster to unpickle (or up to 200% slower). There's a\ncatch: the pickling operation itself is some twenty times slower.\n\nThis pickle implementation is experimental at best, but possibly\nsuitable in situations where you unpickle much more frequently than\nyou pickle. For instance, it could be used for an object data store\nwith frequent reads.\n\nBe aware that the pickles generated are vulnerable to\nincompatibilities between interpreter versions (it uses the\n``marshal`` module to serialize code).\n\nAuthor\n------\n\nThis library is developed and maintained by Malthe Borch\n. The AST utility library was adapted from the\nGenshi codebase and is copyright (c) by 2008 Edgewall Software.\n\nThis software is released and maintained under the BSD license.\n\nLiner notes\n===========\n\nPartial application is an entirely logical proposition; in theory, it\nshould work on any method. To actually benefit from it, classes must\nbe written in a suitable way. This section details the technical\nconsiderations that will guide the developer to a correct\nimplementation.\n\nObject state\n------------\n\nAn abstract syntax tree consists of nodes corresponding to the Python\ngrammar. The expression nodes represent a computation which will\neventually be carried out. Expression nodes that may be evaluated\nduring partial application are termed `resolved`. In terms of\nthe tree structure, it's only possible to resolve nodes that contain\nsubnodes that are resolved.\n\nWhen an expression node is resolved, it's replaced by a custom node\nclass ``Resolved``, which holds the computed value (may be any Python\nobject). As a technical detail, resolved nodes are not assigned a\nsymbol name until they are visited by the code generator transform;\ninternally, they are referenced using their object identity.\n\nAs a result of evaluation during partial application, we will often\nhave to instantiate new (stateful) objects. Initially, the state of\nthese objects is known. The AST may also contain names that correspond\nto variable input. Such varibles are undefined at the time of partial\napplication. When an undefined variable touches a known object, the\nstate of that object becomes undefined, too::\n\n >>> out = []\n >>> out.append(\"Hello\")\n >>> out.append(string)\n >>> \"\".join(out)\n\nIf ``string`` is undefined, this code reduces logically to the\nfollowing, after partial application::\n\n >>> out = [\"Hello\"]\n >>> out.append(string)\n >>> \"\".join(out)\n\nThe state of the list is recorded at the time where it's state is\nfirst undefined. This will be described in more detail later.\n\nState invalidation\n------------------\n\nThe known state of an object is invalidated if it touches an undefined\nobject. It can only happen on the invokation of a method, but to this\nextent we must be careful to note the way Python implements its\ngrammar. All operations are passed on to special methods and this\nobviously qualifies as method invokation::\n\n >>> out = [\"Hello\"]\n >>> out += string\n\nThis invokes the ``__radd__`` method on the list object. Since\n``string`` is undefined, it invalidates the known state of the list.\n\nAs an optimization, the transformer knows about a number of built-in\nmethods that are static (the state of the object never changes on\ninvokation)::\n\n >>> out = [\"Hello\"]\n >>> out.count(string)\n\nThe static ``count`` method merely counts the occurrances of a given\nstring. We do not have to invalidate the list.\n\nIt's important to note that any object that (transitively) references\nan undefined object must itself by undefined.\n\nRestoring object state\n----------------------\n\nIn the examples above, the mutable list object is seen as to be\nrestored by using the list constructor, providing the elements that\nare known. This is essentially an optimization. In the general case,\nwe could use pickles the save and restore state, but this turns out to\nbe very inefficient.\n\nRather, since the complete state of a resolved object is known, we can\nrestore the state using the ``__new__`` constructor and by setting the\ninstance dictionary.\n\nInstances of builtin primitives like ``list`` and ``set`` do not have\nan instance dictionary. Their state is their value. We handle these as\nspecial cases for optimal performance. The other cases are as\nfollows:\n\n- Classes derived from mutable builtins. We instantiate the instance\n by calling the ``__new__`` constructor of the builtin (passing the\n class), then set the state using the builtin ``__init__`` method and\n finally restore the instance dictionary.\n\n- Classes derived from ``object``. We may instantiate the instance by\n calling the ``__new__`` constructor of ``object`` (passing the\n class), then restore the instance dictionary.\n\n- Either of the above that define the ``__slots__`` property. Instead of\n restoring the instance dictionary, we set each attribute.\n\nTo save an object's state in general we transitively generate logic to\ninstantiate and update the state of its subobjects (contained in the\nobject dictionary). Note that this logic is then itself equivalent to\na Python pickle, although spelled out as executable code.\n\nDynamic evaluation\n------------------\n\nThe ``exec`` statement and the ``eval`` function behave\ndifferently. The string argument are parsed as respectively a\nstatement and an expression and inserted as-is into the AST.\n\nApplications include dynamic (local) variable assignment and\nexpression evaluation, both integral to template processing.\n\nFunction calls\n--------------\n\nThere are four different scenarios. Either the function is known, or\nthe arguments are known, or both, or neither.\n\n- If both the function and its arguments are known, we compute the\n result immediately.\n\n- If the function is known, but not the arguments, we include the\n function as a closure and process partial application on it.\n\nTo-Do\n-----\n\n- Star arguments and double-star keyword arguments.\n\n- Ability to mark a method as \"static\", e.g. using a decorator.\n\n\n\nChangelog\n=========\n\n0.2 (released 2009/07/29)\n-------------------------\n\nFeatures:\n\n- Added pickling capability (experimental), both as standalone\n functions and integrated with cooking machinery to preserve and\n restore object state.\n\nBugfixes:\n\n- Make sure assignments are made to names only.\n\n0.1.1 (released 2009/06/02)\n---------------------------\n\n- Fixed documentation formatting.\n\n- Removed debugging statements.\n\n0.1 (released 2009/06/02)\n-------------------------\n\n- Initial public release.", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "UNKNOWN", "keywords": "cooking partial curry optimization ast pickle", "license": "BSD", "maintainer": null, "maintainer_email": null, "name": "curry", "package_url": "https://pypi.org/project/curry/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/curry/", "project_urls": { "Download": "UNKNOWN", "Homepage": "UNKNOWN" }, "release_url": "https://pypi.org/project/curry/0.2/", "requires_dist": null, "requires_python": null, "summary": "Partial application of Python methods.", "version": "0.2" }, "last_serial": 788691, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "db33cb4dd8f256f291471469f1470357", "sha256": "ea0f662db9b55eedc8974e3df808119d4b603c6cc6d0e553639ede0a0701bdae" }, "downloads": -1, "filename": "curry-0.1.tar.gz", "has_sig": false, "md5_digest": "db33cb4dd8f256f291471469f1470357", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 21295, "upload_time": "2009-06-02T07:03:46", "url": "https://files.pythonhosted.org/packages/31/d6/18bc479b03e9295f031fcf3a4c373e57b72e220228e1a0fc1ff46e1670cd/curry-0.1.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "5c87d27a249a1962d46fae529a3a07f0", "sha256": "3999c41f8021cfc89b7904c944ec2bd8a165b7b4949b4c1c47ef497d1cc4a8a0" }, "downloads": -1, "filename": "curry-0.1.1.tar.gz", "has_sig": false, "md5_digest": "5c87d27a249a1962d46fae529a3a07f0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24825, "upload_time": "2009-06-02T18:00:12", "url": "https://files.pythonhosted.org/packages/20/b5/ca605475d60ebcb8a75b124a95b62290c2d9e75c26f02d4b30254d6f8379/curry-0.1.1.tar.gz" } ], "0.2": [ { "comment_text": "", "digests": { "md5": "64a2232ee160c8c39bf992c2bb159098", "sha256": "7ecf097dc7ee3ced3d25b059f6e28e811bd45eb75495e9b013e2bd8fa419357d" }, "downloads": -1, "filename": "curry-0.2.tar.gz", "has_sig": false, "md5_digest": "64a2232ee160c8c39bf992c2bb159098", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 27178, "upload_time": "2009-07-29T23:42:57", "url": "https://files.pythonhosted.org/packages/e3/b1/654dd3c20b2be334f80f7fc9be008b3098a2f55cd26d71a40c24717c7f35/curry-0.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "64a2232ee160c8c39bf992c2bb159098", "sha256": "7ecf097dc7ee3ced3d25b059f6e28e811bd45eb75495e9b013e2bd8fa419357d" }, "downloads": -1, "filename": "curry-0.2.tar.gz", "has_sig": false, "md5_digest": "64a2232ee160c8c39bf992c2bb159098", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 27178, "upload_time": "2009-07-29T23:42:57", "url": "https://files.pythonhosted.org/packages/e3/b1/654dd3c20b2be334f80f7fc9be008b3098a2f55cd26d71a40c24717c7f35/curry-0.2.tar.gz" } ] }