{ "info": { "author": "Steven Fernandez", "author_email": "steve@lonetwin.net", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Topic :: Software Development :: Libraries" ], "description": "supycache\r\n=========\r\n\r\nSimple yet capable caching decorator for python\r\n\r\nSource code: https://github.com/lonetwin/supycache\r\n\r\nInstall using pip: ``pip install supycache`` or download from https://pypi.python.org/pypi/supycache\r\n\r\nWhat is supycache ?\r\n-------------------\r\n\r\n``supycache`` is a decorator that enables caching of return values for\r\ntime-consuming functions, either in memory or on a cache server such as\r\n`memcached `_ or `redis `_.\r\n\r\nThe cache keys can either be *indedependent* or dependent (completely or\r\n*partially*) on the arguments passed to the function.\r\n\r\nThis is **different** from other similar caching decorators, for\r\ninstance,\r\n`functools.lru_cache `_\r\nwhich is dependent on all the arguments passed to the function and\r\nrequires the arguments to be hashable.\r\n\r\nIf you use the default cache backend (ie: `supycache.backends.DictCache`), you\r\ncan also provide an age for the cached values\r\n\r\nHere's an example of how you might use ``supycache``\r\n\r\n.. code:: python\r\n\r\n import time\r\n import supycache\r\n\r\n @supycache.supycache(cache_key='result', max_age=5)\r\n def execute_expensive():\r\n print 'original function called'\r\n time.sleep(15)\r\n return 42\r\n\r\n print execute_expensive() # This will take 15 seconds to execute ...\r\n original function called\r\n 42\r\n print execute_expensive() # ...not this tho', because the value is cached ...\r\n 42\r\n print supycache.default_backend.get('result') # ..keyed as `result`\r\n 42\r\n time.sleep(5) # wait for the cache to expire...\r\n execute_expensive() # This will again take 15 seconds to execute ...\r\n original function called\r\n 42\r\n print execute_expensive() # ...not this tho', because the value is re-cached ...\r\n 42\r\n\r\n\r\nSometimes you might want to be aware of the arguments that are passed to\r\nthe function:\r\n\r\n.. code:: python\r\n\r\n\r\n @supycache(cache_key='sum_of_{0}_and_{1}') # Cache the sum of x and y creating a\r\n def cached_sum(x, y): # key based on the arguments passed\r\n return x + y\r\n\r\n print cached_sum(28, 14)\r\n 42\r\n print supycache.default_backend.get('sum_of_28_and_14')\r\n 42\r\n\r\nYou can also create the key based on **partial arguments** or on the\r\n``attributes``/``items`` within the arguments.\r\n\r\n.. code:: python\r\n\r\n\r\n class User:\r\n def __init__(self, name, session_key):\r\n self.name = name\r\n self.session_key = session_key\r\n\r\n @supycache(cache_key='{user_obj.name}') # build the cache key dependent on *just*\r\n def get_username(user_obj): # the `.name` attribute\r\n time.sleep(15)\r\n return user_obj.name\r\n\r\n a = User(name='steve', session_key='0123456789')\r\n b = User(name='steve', session_key='9876543210') # same name, different session\r\n\r\n print get_username(user_obj=a) # This will take 15 seconds to execute ...\r\n steve\r\n print get_username(user_obj=a) # ...not this tho'...\r\n steve\r\n print get_username(user_obj=b) # ...and neither will this !\r\n steve\r\n\r\n\r\n @supycache(cache_key='{choices[0]}_{menu[lunch]}') # build the cache\r\n def supersized_lunch(ignored, choices=None, menu=None): # key dependent on\r\n time.sleep(15) # partial arguments\r\n return 'You get a %s %s' % (choices[-1], menu['lunch'])\r\n\r\n menu = {'breakfast' : 'eggs',\r\n 'lunch' : 'pizza',\r\n 'dinner' : 'steak'}\r\n\r\n sizes = ['small', 'medium', 'large', 'supersize']\r\n\r\n print supersized_lunch('ignored', choices=sizes, menu=menu)\r\n You get a supersize pizza # This will take 15 seconds to execute ...\r\n\r\n print supersized_lunch('changed', choices=sizes, menu=menu)\r\n You get a supersize pizza # ...not this tho'...\r\n\r\nIf that format specification for the ``cache_key`` looks familiar,\r\nyou've discovered the *secret* of supycache !\r\n\r\n.. code:: python\r\n\r\n\r\n @supycache(backend=memcached_backend, cache_key='{0}_{kw[foo]}_{obj.x}')\r\n def custom_key_built_from_args(positional, kw=None, obj=None):\r\n # now, supycache will build the `cache_key` from the arguments passed and\r\n # use the memcached_backend instance to `set` the key with the return value\r\n # of this function\r\n return 'cached'\r\n\r\nThe *secret* of supycache is quite simple -- it calls ``.format()`` on\r\nthe ``cache_key/expire_key`` with the passed ``args`` and ``kwargs`` to\r\nbuild the actual key.\r\n\r\nHowever, if you'd like to have more control on the way the\r\n``cache_key/expire_key`` are created, simply pass in a callable !\r\n\r\n.. code:: python\r\n\r\n def extract_path(url=None, *args, **kwags):\r\n return urlparse.urlparse(url).path\r\n\r\n @supycache(cache_key=extract_path, ignore_errors=False)\r\n def do_something_with(url):\r\n # will call `extract_path` at runtime passing `url` as parameter and\r\n # will use the returned value as the cache key. Also, don't ignore any\r\n # errors in the entire process if something fails (the default is to\r\n # ignore any caching errors and just return the result as tho' this\r\n # function was undecorated.\r\n return 'cached'\r\n\r\n do_something_with('http://www.example.com/foo/bar')\r\n 'cached'\r\n supycache.default_backend.get('/foo/bar')\r\n 'cached'\r\n\r\n\r\nThe ``backend`` interface is abstarcted out neatly so that backends can be\r\nswapped out without too much hassle. As long as the passed in object has a\r\n``get()``, ``set()`` and ``delete()`` methods, it can be passed to\r\n``supycache`` as a backend or can be set as the ``default_backend``.\r\n\r\n\r\nRight now though, this project has only the code and tests, no docs\r\n(barring some docstrings !). I'll be adding them soon. If interested take a\r\nlook at the tests to see the typical usage and try it out. Feedback, bug\r\nreports and pull requests would be great !\r\n\r\nHelp required\r\n-------------\r\n\r\nI would really appreciate any help you could offer, not just in implementation\r\nbut also in validating the packaging and distribution of this module via pypi\r\nsince I've not distributed any packages before.\r\n\r\nBesides that I plan on adding a few more things:\r\n\r\n * Ability to specify a ``max_age`` for all backends.\r\n * I'm not sure whether I am doing the right thing for the not the packaging\r\n of the memcached dependency. I'd like to automatically include the\r\n support for ``memcached`` or ``redis`` backends if the python memcached\r\n or redis modules are installed.\r\n * logging support", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/lonetwin/supycache", "keywords": "cache,caching,memcached,redis,memoize,memoization", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "supycache", "package_url": "https://pypi.org/project/supycache/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/supycache/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/lonetwin/supycache" }, "release_url": "https://pypi.org/project/supycache/0.3.0/", "requires_dist": null, "requires_python": null, "summary": "Simple yet capable caching decorator for python", "version": "0.3.0" }, "last_serial": 1868346, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "6b40d0327834ba5446ffb858f76bfe23", "sha256": "7cc69043d7e581823299b9923112cd4ed65eef285c17d94e5e103567e2505a1c" }, "downloads": -1, "filename": "supycache-0.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "6b40d0327834ba5446ffb858f76bfe23", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 8128, "upload_time": "2015-06-07T07:23:59", "url": "https://files.pythonhosted.org/packages/3f/2a/7b37050d04620882d8a072fd84db2478f6e87871b248b8c7646978df8401/supycache-0.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "3635609f792ba19138ae42648a82b2a4", "sha256": "421db954a1cfb08825df4258427cc8c977065f61fb839e9c2f322c6bc9f18500" }, "downloads": -1, "filename": "supycache-0.1.tar.gz", "has_sig": false, "md5_digest": "3635609f792ba19138ae42648a82b2a4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4983, "upload_time": "2015-06-07T07:23:55", "url": "https://files.pythonhosted.org/packages/5a/94/f116bdb63dc778f0ae2c1c86c42ce926ce07963cc8f2c12817a5c72c453d/supycache-0.1.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "2c1c38c95c1069caec6b99ccdb2bc3a1", "sha256": "e0ed70d8301002f822a4b395c99ded828d27b320d2937a374c82e8c3c2c54451" }, "downloads": -1, "filename": "supycache-0.2.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "2c1c38c95c1069caec6b99ccdb2bc3a1", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 8925, "upload_time": "2015-06-07T14:46:33", "url": "https://files.pythonhosted.org/packages/4b/a8/1dee508679b8446f12792dd8741af2a3885aeefd0c412d1726415eceb6c6/supycache-0.2.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9abc11d503c40969672fa2ef514df909", "sha256": "8f514d1296430bd25ac87e3a15cfbe4f94314ca93fc2bfaada41844343000913" }, "downloads": -1, "filename": "supycache-0.2.0.tar.gz", "has_sig": false, "md5_digest": "9abc11d503c40969672fa2ef514df909", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5441, "upload_time": "2015-06-07T14:46:37", "url": "https://files.pythonhosted.org/packages/05/be/4b4e7be41f8772c9ab7d37c9c7292d91781b6722b4cf9ca71946d0992e21/supycache-0.2.0.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "280b0a682385a9142848dd4b61bcac40", "sha256": "58b548398664657c74540f7423c9a870b9bb957b6ee1cf381774e80c298d54e5" }, "downloads": -1, "filename": "supycache-0.2.1.tar.gz", "has_sig": false, "md5_digest": "280b0a682385a9142848dd4b61bcac40", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5751, "upload_time": "2015-11-09T06:30:15", "url": "https://files.pythonhosted.org/packages/37/e7/2fe24798773e60b6515217904a119e80ab4338299dcd082248d920abf1fa/supycache-0.2.1.tar.gz" } ], "0.3.0": [ { "comment_text": "", "digests": { "md5": "22865e5673ac27467f81745d23efda3e", "sha256": "b85547195e1effffc14b7d06f58664a5cc657edb4794046d1d5eb42983247760" }, "downloads": -1, "filename": "supycache-0.3.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "22865e5673ac27467f81745d23efda3e", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 10556, "upload_time": "2015-12-18T09:15:55", "url": "https://files.pythonhosted.org/packages/e0/1a/c83d68c6d2bf79de5c8ab17d9b9e2f1c0c9a7566f255a41535ed7f129de6/supycache-0.3.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "aa954098ec8e46c870b467ef27a9decc", "sha256": "37aeac3074dda828b84c9614896f8b9c775700068cac1551af86945bba4cedb6" }, "downloads": -1, "filename": "supycache-0.3.0.tar.gz", "has_sig": false, "md5_digest": "aa954098ec8e46c870b467ef27a9decc", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6846, "upload_time": "2015-12-18T07:38:50", "url": "https://files.pythonhosted.org/packages/8b/97/6652ec9434c8d31b976bb6f71f777b7ffa97f883fbbd4004a88021db7880/supycache-0.3.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "22865e5673ac27467f81745d23efda3e", "sha256": "b85547195e1effffc14b7d06f58664a5cc657edb4794046d1d5eb42983247760" }, "downloads": -1, "filename": "supycache-0.3.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "22865e5673ac27467f81745d23efda3e", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 10556, "upload_time": "2015-12-18T09:15:55", "url": "https://files.pythonhosted.org/packages/e0/1a/c83d68c6d2bf79de5c8ab17d9b9e2f1c0c9a7566f255a41535ed7f129de6/supycache-0.3.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "aa954098ec8e46c870b467ef27a9decc", "sha256": "37aeac3074dda828b84c9614896f8b9c775700068cac1551af86945bba4cedb6" }, "downloads": -1, "filename": "supycache-0.3.0.tar.gz", "has_sig": false, "md5_digest": "aa954098ec8e46c870b467ef27a9decc", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6846, "upload_time": "2015-12-18T07:38:50", "url": "https://files.pythonhosted.org/packages/8b/97/6652ec9434c8d31b976bb6f71f777b7ffa97f883fbbd4004a88021db7880/supycache-0.3.0.tar.gz" } ] }