{ "info": { "author": "Claudio Freire", "author_email": "klaussfreire@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)", "Operating System :: OS Independent", "Programming Language :: Cython", "Programming Language :: Python", "Programming Language :: Python :: 2", "Topic :: Software Development :: Libraries" ], "description": "Dependencies:\n=============\n\n* numpy *(for optimizations in FilesCacheClient)*\n* python-memcached *(for MemcachedClient)*\n* pyzmq < 14 *(for coherence support)*\n* dnspython *(for dynamic dns-based load-balancing of MemcachedClient)*\n* cython *(for optimizations in InprocCacheClient)*\n\nOptional features\n=================\n\nWhen declaring dependencies in your project, you can reference the following optional features:\n\n* mq *(everything under chorde.mq, mostly pulls pyzmq)*\n* shmem *(shared memory utils, needed for optimized files cache clients)*\n* memcache\n* elasticache\n\nBasic Usage:\n============\n\nThe simplest way to use is to create one of the supported cache clients,\nand use it directly, like\n\n.. code:: python\n\n from chorde.clients.inproc import InprocCacheClient\n from chorde import CacheMissError\n c = InprocCacheClient(200)\n c.put(3, 10, 300) # put value 10 on key 3, TTL 5min\n assert 10 == c.get(3)\n try:\n c.get(5)\n except CacheMissError:\n print \"miss\"\n\nThis creates an In-process LRU cache. The in-process part indicates that it\nis process-private, and not shared with other processes.\n\nThere are two implementations of the LRU, with different performance\ncharacteristics. The `InprocCacheClient` can take alternative store\nimplementations as an argument, see the module for details.\n\nThe default LRUCache, accessible as `chorde.clients.inproc.Cache`,\nis a regular LRU implemented with\na priority queue and a hash table in tandem, so it has *O(log n)* writes\nand *O(1)* reads, but by default all reads entail a write (to update the\nLRU). That can be disabled by specifying custom options, see the module's\ndocumentation for more details.\n\nThere's an alternative approximate LRU, accessible in\n`chorde.clients.inproc.CuckooCache`, that implements a lazy version of\na cuckoo hash table, and has *O(1)* reads and amortized *O(1)* writes.\nIt's also quite more space-efficient than the regular LRU, so it's better\nsuited for very large caches, but its eviction strategy will be approximate,\nand thus not guaranteed to always evict the actual least-recently-used item.\n\nShared Caches\n=============\n\nThe most straightforward way to get a shared cache, is to use a memcache:\n\n.. code:: python\n\n from chorde.clients.memcached import MemcachedClient\n from chorde import CacheMissError\n c = MemcachedClient([\"localhost:11211\"], checksum_key = \"testing\")\n c.put(3, 10, 300)\n assert 10 == c.get(3)\n try:\n c.get(5)\n except CacheMissError:\n print \"miss\"\n\nThe MemcachedClient is used just like any other client, only it talks to, in this\nexample, a local memcached listening on localhost port 11211. Multiple clients\ncan be given, and a consistent hash on the key will be used to spread the load\namong them.\n\nIf a hostname is given, and the hostname points to multiple IP addresses, the\nsame effect will be obtained, and the distribution will be dynamically updated\naccording to the TTL specified on the DNS entry. This, for example, makes the\nclient work seamlessly with Amazon ElastiCache's \"configuration endpoint\",\nwhich is a DNS entry that points to one of the cache nodes. But it only works\nlike that with single-node clusters. For multi-node clusters, use\n``chorde.clients.elasticache.ElastiCacheClient``, which goes a step further\nand queries this configuration endpoint for all the other nodes.\n\nDo beware that the key used against the memcached isn't the key given, since\nthe client supports any hashable object as key, whereas memcached only supports\na subset of string keys. MemcachedClient has none of memcached's limitations\nwith regards to key format and/or length and value size. It works around\nmemcaches limitations, by constructing a derived key that is suitable for\nmemcached. However, there is overhead in providing huge keys or values, so it's generally\ngood advise to avoid them anyway.\n\nValues in the MemcachedClient are plickled, compressed and signed with the\nchecksum key, so it is relatively safe from both malicious code injection through\npickle, and transmission errors causing cPickle to dump core (which does happen when\nit is fed unchecked data).\n\nIn case the compression becomes a bottleneck, which shouldn't be a problem unless\nit is a high-traffic cache with rarely compressible values, one can disable it.\nCheck MemcachedClient's documentation for more details.\n\nTo reduce roundtrips, all clients (in particular MemcachedClients) support\ngetMulti and getTtlMulti, to fetch multiple keys at once:\n\n.. code:: python\n\n from chorde.clients.memcached import MemcachedClient\n from chorde import CacheMissError\n c = MemcachedClient([\"localhost:11211\"], checksum_key = \"testing\")\n c.put(3, 10, 300)\n c.put(4, 20, 300)\n assert {3:10, 4:20, 5:None} == dict(c.getMulti([3,4,5], None))\n\nSee the documentation on clients.base for more details.\n\nMultilevel caches\n=================\n\nA common approach when dealing with remote caches, like the above example using\nmemcached, is to have at least two levels: the memcached itself, and an in-process\nsmall cache to avoid having to talk to the memcached all the time.\n\nThis can be done straightforwardly with the tiered clients:\n\n.. code:: python\n\n from chorde.clients.memcached import MemcachedClient\n from chorde.clients.inproc import InprocCacheClient\n from chorde.clients.tiered import TieredInclusiveClient\n from chorde import CacheMissError\n l1 = InprocCacheClient(10)\n l2 = MemcachedClient([\"localhost:11211\"], checksum_key=\"test\")\n c = TieredInclusiveClient(l1,l2)\n c.put(3, 10, 300)\n assert 10 == c.get(3)\n try:\n c.get(5)\n except CacheMissError:\n print \"miss\"\n\nHere we build an *inclusive* tiered client, in which elements on higher levels are\npromoted into the lower levels by copying, rather than swapping. This means there\nis duplication among them, but this is usually best in cases like these, where the\nupper levels are shared among processes.\n\nAn exclusive client isn't provided at this moment, since there is seldom any use\nfor the exclusive pattern on these types of caches.\n\nDecorators\n==========\n\nA more natural way to think about caching, is in that it's a decorator of plain functions.\n\nRather than explicitly putting and getting from caches, one can simply consider\ncaching as an optimization on an otherwise expensive function.\n\nDecorators in chorde.decorators provide a huge amount of functionality and flexibility,\nthese examples cover only the most basic usage:\n\nAssuming *c* is the client we want to use for caching,\n\n.. code:: python\n\n from chorde.decorators import cached\n import random\n\n @cached(c, ttl=300, async_ttl=-60)\n def expensive_func(x):\n return x * random.random()\n\n print expensive_func(1)\n print expensive_func(1) # Should return the same\n print expensive_func.async()(1) # will refresh asynchronously every minute\n print expensive_func.future()(1).result() # same as before, but using the futures interface\n print expensive_func.peek(1) # just check the cache\n print expensive_func.put(1, _cache_put=5) # write an explicit value\n print expensive_func.async().lazy(1) # don't wait, raise CacheMissError if not available, compute in background\n print expensive_func.future().lazy(1).result() # same as before, but using the futures interface\n\nThere, the async_ttl means the minimum TTL that triggers\nan asynchronous recomputation (you can use it to avoid ever having to wait on a recomputation).\nThe negative value makes it relative to the total TTL, so -60 always means recompute\nevery minute (60 seconds). The plain ttl is an absolute limit, no result older than\nthat will ever be returned.\n\nThe documentation on chorde.decorators.cached will have more to say about the ways of\ninvoking cached functions.\n\nIn general, the terms are:\n\n * lazy: don't wait for computation, return a cached result or raise CacheMissError.\n When combined with async, it will compute in the background.\n * peek: don't compute. Similar to lazy, but it will never trigger a computation\n * async: expensive things (computation) happen on a background threadpool.\n * future: return futures rather than results, use the future to get notified of\n results when they're available. Actual cache access happens on a threadpool.\n A non-blocking way of calling.\n * refresh: immediately recompute the value.\n\n\nIntegration with other libraries\n--------------------------------\n\nThe decorators' future() interface is especially suited for integration with other libraries that can talk to\nfutures. Chorde's futures, however, are not directly compatible with other libraries', but they can easily be\nwrapped like so:\n\n.. code:: python\n\n import tornado.web\n import tornado.gen\n from chorde.clients.async import makeFutureWrapper\n\n WF = makeFutureWrapper(tornado.web.Future)\n\n ...\n\n @tornado.gen.coroutine\n def get(self):\n some_result = yield WF(some_func.future()(some_args))\n\n\nThere is a better way to integrate with tornado >= 4.0\n\n.. code:: python\n\n from chorde.external_integration import monkey_patch_tornado\n monkey_patch_tornado()\n\n import tornado.web\n import tornado.gen\n\n ...\n\n @tornado.gen.coroutine\n def get(self):\n some_result = yield some_func.future()(some_args)\n\n\nAdditional documentation\n========================\n\n- `In Depth Look into Caching (Part 1) `__ (English)\n- `In Depth Look into Caching (Part 2) `__ (English)\n- `Caching para hordas y estampidas por Claudio Freire - PyCon 2013 `__ (Spanish)", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://bitbucket.org/claudiofreire/chorde/", "keywords": "", "license": "LGPLv3", "maintainer": "", "maintainer_email": "", "name": "chorde", "package_url": "https://pypi.org/project/chorde/", "platform": "", "project_url": "https://pypi.org/project/chorde/", "project_urls": { "Homepage": "https://bitbucket.org/claudiofreire/chorde/" }, "release_url": "https://pypi.org/project/chorde/0.7.0/", "requires_dist": null, "requires_python": "", "summary": "Clustered Caching Library", "version": "0.7.0" }, "last_serial": 5520298, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "5570c4fe8216ce945869ba62d3ef37fe", "sha256": "28a571b37345f512feafcd21dfec60abd077a0fdb7704200069a8a9a36c41b70" }, "downloads": -1, "filename": "chorde-0.1.tar.gz", "has_sig": false, "md5_digest": "5570c4fe8216ce945869ba62d3ef37fe", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 197248, "upload_time": "2016-10-12T02:46:59", "url": "https://files.pythonhosted.org/packages/4c/6a/584bd734cebaf0a4b81e1b7765a4bf8df251dd4095e7a36125808dca0c88/chorde-0.1.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "7abfcc8aaf420da1bc46ee7fbbac3e4e", "sha256": "7a64111f0fa5cbb4b9b23b567d2c2d7998350757ac980f714859becf0a7e6682" }, "downloads": -1, "filename": "chorde-0.2.0.tar.gz", "has_sig": false, "md5_digest": "7abfcc8aaf420da1bc46ee7fbbac3e4e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 291389, "upload_time": "2017-09-20T14:02:49", "url": "https://files.pythonhosted.org/packages/e5/a0/a132313fa91af6ad9b00e1655ff1f74c14c7f5d6611cef6b4b7ceacfc801/chorde-0.2.0.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "207676f3faf7f026ba47adda453903ae", "sha256": "77f660e5feace509217907a08564bb5c98b82b65923bf67162fd95bb212c3d51" }, "downloads": -1, "filename": "chorde-0.2.1.tar.gz", "has_sig": false, "md5_digest": "207676f3faf7f026ba47adda453903ae", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 291815, "upload_time": "2017-10-12T17:56:41", "url": "https://files.pythonhosted.org/packages/5b/e9/a94e07a531e2746b862d94bcf60476d9547260b097b1308cb6131051a81d/chorde-0.2.1.tar.gz" } ], "0.3.0": [ { "comment_text": "", "digests": { "md5": "ef6dc4c461dc54e4fd41db46d4e61e1f", "sha256": "af03b669c63489d20937cc5a64718aaaa6becf778dc0abe414ccc4d5230dc52b" }, "downloads": -1, "filename": "chorde-0.3.0.tar.gz", "has_sig": false, "md5_digest": "ef6dc4c461dc54e4fd41db46d4e61e1f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 293879, "upload_time": "2017-12-06T18:36:36", "url": "https://files.pythonhosted.org/packages/f4/90/bcc65bd38f582705cfcb235779b655caa8be6a0cb727c7c8018722ea284b/chorde-0.3.0.tar.gz" } ], "0.3.1": [ { "comment_text": "", "digests": { "md5": "b15a6beee6dcc961dbbbd9ec79539b42", "sha256": "36ee2b3f8a35652561046fe5404b8f99919dbd694c7561918c2de35525bf9feb" }, "downloads": -1, "filename": "chorde-0.3.1.tar.gz", "has_sig": false, "md5_digest": "b15a6beee6dcc961dbbbd9ec79539b42", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 294066, "upload_time": "2018-02-07T18:41:36", "url": "https://files.pythonhosted.org/packages/ec/a0/fdc634b34f349adea4c38c92a9aaac218f29f81567da51ac1d863f8d4028/chorde-0.3.1.tar.gz" } ], "0.4.0": [ { "comment_text": "", "digests": { "md5": "6a034a19ca6dfd3dcf04523bdf0ec857", "sha256": "3315046fd83b3af8def5bbb6d71bcd4d02990df4b7d40d5861c725f42039933d" }, "downloads": -1, "filename": "chorde-0.4.0.tar.gz", "has_sig": false, "md5_digest": "6a034a19ca6dfd3dcf04523bdf0ec857", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 294911, "upload_time": "2018-02-19T19:14:52", "url": "https://files.pythonhosted.org/packages/02/57/d46a441e180da5df4945dba31dfa7b72b8a4ae7ee8102d230664fa81bfd5/chorde-0.4.0.tar.gz" } ], "0.4.1": [ { "comment_text": "", "digests": { "md5": "6d2a507fffe70f291179cbcfbc00a100", "sha256": "bea58ae6ab70f9e221037e2deb28788b90f7074a2ec8c84bf8c87379266b8e85" }, "downloads": -1, "filename": "chorde-0.4.1.tar.gz", "has_sig": false, "md5_digest": "6d2a507fffe70f291179cbcfbc00a100", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 295404, "upload_time": "2018-03-08T13:58:07", "url": "https://files.pythonhosted.org/packages/a7/f5/c6a51a8ecd1193caac50af9fe62d8488e25940777287864bfe26fba29eb5/chorde-0.4.1.tar.gz" } ], "0.4.2": [ { "comment_text": "", "digests": { "md5": "3649e7b2f2d42f4082ced3a81f6b68e6", "sha256": "1a75405acb79b87ae47f3917634c0c4756480df4377ccdff3d343bc299c5f9a8" }, "downloads": -1, "filename": "chorde-0.4.2.tar.gz", "has_sig": false, "md5_digest": "3649e7b2f2d42f4082ced3a81f6b68e6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1051975, "upload_time": "2018-06-14T13:40:29", "url": "https://files.pythonhosted.org/packages/d9/cc/066678d6ed7110dc170b97b784555ad9c706bb69536273153e621a883c74/chorde-0.4.2.tar.gz" } ], "0.5.0": [ { "comment_text": "", "digests": { "md5": "4e347f801bd2b851306d887859970196", "sha256": "f4c607c0cfe192568dd9095f194b57a10c248a0a530ba30bca3cf9788816b23c" }, "downloads": -1, "filename": "chorde-0.5.0.tar.gz", "has_sig": false, "md5_digest": "4e347f801bd2b851306d887859970196", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1047946, "upload_time": "2018-07-12T18:00:15", "url": "https://files.pythonhosted.org/packages/90/82/04eaedde9d244bb5c5a9454773ee5d39ee075c4b18b4494a7812e6afa068/chorde-0.5.0.tar.gz" } ], "0.5.1": [ { "comment_text": "", "digests": { "md5": "8ae73e6cf170f3827d1089beba0e125a", "sha256": "4088d5b3c460f8637b6675acbd7a35c86d27d6dd1cffd0758db9c8866d117406" }, "downloads": -1, "filename": "chorde-0.5.1.tar.gz", "has_sig": false, "md5_digest": "8ae73e6cf170f3827d1089beba0e125a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1047843, "upload_time": "2018-07-26T14:04:13", "url": "https://files.pythonhosted.org/packages/e0/48/24723d96924b62659ca3073f9fcfa15154d55595bafa2d4014f307f98323/chorde-0.5.1.tar.gz" } ], "0.5.2": [ { "comment_text": "", "digests": { "md5": "ce3631cecb810bf5f8f2c20051a339c7", "sha256": "6f31f96696790cd80b6ce0e88892a895a30561759344cca803ac1d47382952cb" }, "downloads": -1, "filename": "chorde-0.5.2.tar.gz", "has_sig": false, "md5_digest": "ce3631cecb810bf5f8f2c20051a339c7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1048473, "upload_time": "2018-08-01T14:36:48", "url": "https://files.pythonhosted.org/packages/cb/93/d69d4fa372098746bc5e9295ee67262ef809ee823b7b098ebe771fa3e41e/chorde-0.5.2.tar.gz" } ], "0.5.3": [ { "comment_text": "", "digests": { "md5": "698fbcd8b7c7337fadbbed914c26b710", "sha256": "f914e1b3dac0af3ee849e8453584d75bba420a98b5b9ea78e62a355ad2a9e73b" }, "downloads": -1, "filename": "chorde-0.5.3.tar.gz", "has_sig": false, "md5_digest": "698fbcd8b7c7337fadbbed914c26b710", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1055036, "upload_time": "2018-08-23T14:05:52", "url": "https://files.pythonhosted.org/packages/b0/76/be31efd87db7acd1ccf6ee8bc3881da7e1ec0384543a4f60759bb7a0593d/chorde-0.5.3.tar.gz" } ], "0.5.4": [ { "comment_text": "", "digests": { "md5": "553198c6c8f50c8bf1c32878857e4496", "sha256": "bc49023c7209d7a2ee8494e06ff2d879150bd93bda13a26f3ad122039bc7994f" }, "downloads": -1, "filename": "chorde-0.5.4.tar.gz", "has_sig": false, "md5_digest": "553198c6c8f50c8bf1c32878857e4496", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1055111, "upload_time": "2018-09-24T13:39:21", "url": "https://files.pythonhosted.org/packages/ca/89/7e855ac5922bf7df02027b2fc13a9fbf23cd2bd8c50982d961d67d93fa26/chorde-0.5.4.tar.gz" } ], "0.6.0": [ { "comment_text": "", "digests": { "md5": "c90868fa070ecbc3504f8fcf741e72c9", "sha256": "793023b3d5a95ad1b638b5bedd9ba630b08c8b9bac86b09dc8f09e2614189a42" }, "downloads": -1, "filename": "chorde-0.6.0.tar.gz", "has_sig": false, "md5_digest": "c90868fa070ecbc3504f8fcf741e72c9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1047279, "upload_time": "2019-04-04T14:03:11", "url": "https://files.pythonhosted.org/packages/9c/76/cd147c307a0a165beb0b6e66f5a558839c5badb6bce1ea268390102c9639/chorde-0.6.0.tar.gz" } ], "0.7.0": [ { "comment_text": "", "digests": { "md5": "518b6a7c7811f05c364a41e83c5cda28", "sha256": "d0f38a501e562fed58e14186acda8598acdaa83f022d3dfb2628b35d6a66429b" }, "downloads": -1, "filename": "chorde-0.7.0.tar.gz", "has_sig": false, "md5_digest": "518b6a7c7811f05c364a41e83c5cda28", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1041220, "upload_time": "2019-07-11T21:18:40", "url": "https://files.pythonhosted.org/packages/5c/2c/31c35a702e2dee14637dd456a041852a5ae29a30b5776de1b15e7d8d7569/chorde-0.7.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "518b6a7c7811f05c364a41e83c5cda28", "sha256": "d0f38a501e562fed58e14186acda8598acdaa83f022d3dfb2628b35d6a66429b" }, "downloads": -1, "filename": "chorde-0.7.0.tar.gz", "has_sig": false, "md5_digest": "518b6a7c7811f05c364a41e83c5cda28", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1041220, "upload_time": "2019-07-11T21:18:40", "url": "https://files.pythonhosted.org/packages/5c/2c/31c35a702e2dee14637dd456a041852a5ae29a30b5776de1b15e7d8d7569/chorde-0.7.0.tar.gz" } ] }