{ "info": { "author": "Josiah Carlson", "author_email": "josiah.carlson@gmail.com", "bugtrack_url": null, "classifiers": [ "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Topic :: Software Development :: Libraries", "Topic :: Utilities" ], "description": "lua_call - a Redis + Lua scripting namespace and calling library for Python\n\nCopyright 2014 Josiah Carlson\n\nThis library released under the MIT license.\n\nWhat is lua_call?\n=================\n\nThis library implements a script transformation function along with some\nuseful utilities to allow you to call Lua scripts from other Lua scripts\nin Redis. There are also some Python-side wrappers to aid in calling Lua from\nPython, but that's just a bonus.\n\nGenerally speaking, it adds an internal calling semantic that allows you to\npass `KEYS` and `ARGV` between your internal Lua scripts in a sane manner.\nThis allows you, as a developer, to to develop your Lua scripts using better\npractices than copying/pasting similar code between scripts.\n\nLimitations\n===========\n\nDue to the way we handle calling conventions, you must be careful in how you\nuse `KEYS` and `ARGV`. Because we are not using a full-on parser for the Lua\nlanguage, we use a regular expression to discover uses of `KEYS` and `ARGV` to\nalter. More specifically, we take examples like the following::\n\n local passed_keys = KEYS\n local source = KEYS[1]\n local arg = ARGV[1]\n local z = redis.call('KEYS', ...)\n\n... and translate them into::\n\n local passed_keys = _KEYS\n local source = _KEYS[1]\n local arg = _ARGV[1]\n local z = redis.call('KEYS', ...)\n\nNote that we didn't mangle the `KEYS` in `redis.call()`, but if you were to\nhave the following::\n\n local string = 'this is a string with KEYS and ARGV, oops!'\n\n... we will mangle the string into::\n\n local string = 'this is a string with _KEYS and _ARGV, oops!'\n\nThere are other potential corner cases where our name mangling might be\nincorrect, and you are advised to keep your usage of `KEYS` and `ARGV` to\nreading or writing to `KEYS` and `ARGV` or to the simple literal strings of\n`'KEYS'` and `'ARGV'` as in `redis.call('KEYS', ...)`.\n\nDefining scripts using lua_call\n===============================\n\nYou have a Redis connection during script definition\n----------------------------------------------------\n\nIf you have your Redis connection available while defining your Lua scripts,\nyou can use the following calls to automatically define and register the\nfunction wrappers in the Python module, automatically load the script into\nRedis, and register the function for internal calling inside Redis::\n\n # contents of example.py\n from redis import Redis\n from lua_call import function\n\n conn = Redis(...)\n\n function .return_args(\"\"\"\n return ARGV\n \"\"\", conn)\n\n function .call_return(\"\"\"\n CALL.return_args({}, {1, 2, 3, ARGV})\n \"\"\", conn)\n\nWe describe how to use these functions just past the next section.\n\nYou don't have a Redis connection during script definition\n----------------------------------------------------------\n\nIf you don't have a connection during script definition, you can omit the\nconnection argument during definition. In this case, the scripts will not be\nregistered, so you must later call `load_scripts()` to register them. The\nfollowing is more or less equivalent to the 'have a connection' section\nabove::\n\n # contents of example.py\n from redis import Redis\n from lua_call import function, load_scripts\n \n function .return_args(\"\"\"\n return ARGV\n \"\"\")\n \n function .call_return(\"\"\"\n CALL.return_args({}, {1, 2, 3, ARGV})\n \"\"\")\n \n load_scripts(Redis(), __name__)\n\nCalling scripts defined with lua_call\n=====================================\n\nAssuming that you have defined your scripts using one of the two methods\noutlined above, the `example` module will have functions defined in the module\nnamespace called `return_args()` and `call_return()`. These wrappers around\nthe script take exactly 3 arguments: a Redis connection, then a list of `KEYS`\nand a list of `ARGV` that are passed to the called scripts.\n\nAn example of their use can be seen below::\n\n >>> from redis import Redis\n >>> conn = Redis()\n >>> import example\n >>> example.return_args(conn, [], [1, 2, 3])\n ['1', '2', '3']\n >>> example.call_return(conn, [], [4, 5, 6])\n [1, 2, 3, ['4', '5', '6']]\n\nNote that while KEYS and ARGV passed from outside Redis are translated into\nstrings as part of the calling process, internal calls do not change the types\nof arguments passed.\n\nHow it works\n============\n\nThis library takes scripts that you define, possibly including other Lua\nscript calls, and changes the source code to allow you to actually perform\nthose calls. Generally speaking, you can think of this as introducing a new\nglobal value in Redis by the name of `CALL`, which allows you to both register\nfunctions and call those functions. Now, the truth is that there is no new\nglobal value available in Redis Lua scripting, but your scripts will act as\nthough that is the case.\n\nAs an example of what actually goes on, let's say that we start out with a Lua\nscript defined as the below, which is from the included `example.py`::\n\n return CALL.return_args({}, {1, 2, 3, _ARGV})\n\nAfter our transformation (and applying some source code formatting and extra\ncomments so you can understand what is going on easier), we get the following\nscript::\n\n -- We reference either the externally-called KEYS/ARGV or the internally\n -- called KEYS/ARGV in locals called _KEYS and _ARGV\n local _KEYS, _ARGV;\n if #ARGV == 0 or type(ARGV[#ARGV]) == 'string' then\n -- Use the standard KEYS and ARGV as passed from the external caller\n _KEYS = KEYS;\n _ARGV = ARGV;\n else\n -- Pull the KEYS and ARGV from the table appended to ARGV\n _KEYS = ARGV[#ARGV][1];\n _ARGV = ARGV[#ARGV][2];\n\n -- We remove the pushed reference to prevent circular references,\n -- which can crash Redis if you aren't careful\n table.remove(ARGV);\n end;\n\n -- push the arguments onto the ARGV table as call stack arguments\n table.insert(ARGV, {{}, {1, 2, 3, _ARGV}});\n\n -- fetch the script hash from the name and call the function\n return _G[redis.call('HGET', ':registry', 'example.return_args')]();\n\nGenerally, there is some header code prepended to your source, KEYS and ARGV\nreferences are changed to _KEYS and _ARGV, and any time you want to make a\ncall to another script, we append your arguments to the end of the ARGV table,\nand pull the destination script name from a Redis-backed function registry.\n\nEarly versions of this library required assigning the result of a call to a\nlocal variable before returning, but this is no longer necessary.\n\nLicensing and source code mangling\n==================================\n\nTechnically speaking, this library will alter the Lua script source code that\nyou pass in order to insert the code that handles internal calls. I do not\nconsider this purposeful alteration to result in your code being in any way\nderived from or related to this library. Your source code remains your source\ncode, and this library is a utility to aid in your development and maintenance\nprocesses.", "description_content_type": null, "docs_url": null, "download_url": "http://pypi.python.org/pypi/lua_call/", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://github.com/josiahcarlson/lua-call/", "keywords": null, "license": "MIT", "maintainer": null, "maintainer_email": null, "name": "lua_call", "package_url": "https://pypi.org/project/lua_call/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/lua_call/", "project_urls": { "Download": "http://pypi.python.org/pypi/lua_call/", "Homepage": "http://github.com/josiahcarlson/lua-call/" }, "release_url": "https://pypi.org/project/lua_call/0.10.0/", "requires_dist": null, "requires_python": null, "summary": "Call Lua scripts from other Lua scripts in Redis", "version": "0.10.0" }, "last_serial": 1046325, "releases": { "0.10.0": [ { "comment_text": "", "digests": { "md5": "39da6da144c219cc667df790caf28bd1", "sha256": "dc13ff28f1b60f81dcac18fb002446523d306f29169a7a1ce262390471d17c40" }, "downloads": -1, "filename": "lua_call-0.10.0.tar.gz", "has_sig": false, "md5_digest": "39da6da144c219cc667df790caf28bd1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9257, "upload_time": "2014-03-30T23:06:24", "url": "https://files.pythonhosted.org/packages/28/e6/52a6a9871dca7121218fc31edb211e077564d8fbd01b227d9a82ae644195/lua_call-0.10.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "39da6da144c219cc667df790caf28bd1", "sha256": "dc13ff28f1b60f81dcac18fb002446523d306f29169a7a1ce262390471d17c40" }, "downloads": -1, "filename": "lua_call-0.10.0.tar.gz", "has_sig": false, "md5_digest": "39da6da144c219cc667df790caf28bd1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9257, "upload_time": "2014-03-30T23:06:24", "url": "https://files.pythonhosted.org/packages/28/e6/52a6a9871dca7121218fc31edb211e077564d8fbd01b227d9a82ae644195/lua_call-0.10.0.tar.gz" } ] }