{ "info": { "author": "James Arthur", "author_email": "username: thruflo, domain: gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Environment :: Web Environment", "Framework :: Pylons", "Intended Audience :: Developers", "License :: Public Domain", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2.7", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "# Alkey\n\n[Alkey][] is a [Redis][] backed tool for generating cache keys that implicitly\nupdate / invalidate when [SQLAlchemy][] model instances change, e.g.:\n\n from alkey.cache import get_cache_key_generator\n key_generator = get_cache_key_generator()\n \n # The `cache_key` will be invalidated when `instance1` or `instance2` change.\n cache_key = key_generator(instance1, instance2)\n\nIt can be used by any [SQLAlchemy][] application that has access to [Redis][].\nPlus it has (optional) integration with the [Pyramid][] framework:\n`config.include` the package and generate keys using, e.g.:\n\n cache_key = request.cache_key(request.context)\n\n## How it Works\n\n[Alkey][] works by binding to the SQLAlchemy session's [before_flush][] and\n[after_commit][] events to maintain a unique token, in Redis, against every\nmodel instance. As long as the model instance has a unique `id` property, this\ntoken will change whenever the instance is updated or deleted. In addition,\nAlkey maintains a global write token and a token against each database table.\nYou can use these to generate cache keys that invalidate:\n\n* when an *instance* changes\n* when a *table* changes; or\n* when *anything* changes\n\nThe main algorithm is to record instances as changed when they're flushed to\nthe db in the session's new, dirty or deleted lists (identifiers in the format\n`alkey:tablename#row_id`, e.g.: `alkey:users#1`, are stored in a Redis set).\nThen, when the session's transaction is committed, the tokens for each recorded\ninstance (plus their table and the global write token) are updated. This means\nthat a cache key that contains the tokens will miss, causing the cached value\nto be regenerated.\n\nNew tokens are generated when instances are looked up that are not already\nin the cache. So keys will always be invalidated if you lose / flush your\nRedis data.\n\n> Note also that changes recorded during a transaction that's\nsubsequently rolled back will be discarded (i.e.: the tokens will not be updated)\n*unless* the rolled-back transaction is a sub-transaction. In that case — if\nyour application code explicitly uses sub-transactions — rollbacks may lead\nto unnecessary cache-misses.\n\n## Configuring a Redis Client\n\n[Alkey][] looks in the `os.environ` (i.e.: you need to provide\n[environment variables][]) for a values to configure a [redis client][]:\n\n* `REDIS_URL`: a connection string including any authenticaton information, e.g.:\n `redis://username:password@hostname:port`\n* `REDIS_DB`: defaults to `0`\n* `REDIS_MAX_CONNECTIONS`: the maximum number of connections for the client's\n connection pool (defaults to not set)\n\n## Binding to Session Events\n\nUse the `alkey.events.bind` function, e.g.:\n \n from alkey import events\n from myapp import Session # the sqlalchemy session you're using\n \n events.bind(Session)\n\n## Generating Cache Keys\n\nYou can then instantiate an `alkey.cache.CacheKeyGenerator` and call it with\nany of the following types as positional arguments to generate a cache key:\n\n* SQLAlchemy model instances\n* model instance identifiers in the format `alkey:tablename#row_id`\n* SQLAlchemy model classes\n* model class identifiers in the format `alkey:tablename#*`\n* the `alkey.constants.GLOBAL_WRITE_TOKEN`, which has the value `alkey:*#*`\n* arbitrary values that can be coerced to a unicode string\n\nE.g. using the `alkey.cache.get_cache_key_generator` factory to instantiate:\n\n from alkey.cache import get_cache_key_generator\n \n key_generator = get_cache_key_generator()\n cache_key = key_generator(instance, 'alkey:users#1', 1, 'foo', {'bar': 'baz'})\n\nOr, for example, imagine you have a `users` table, of which `user` is an instance\nwith an `id` of `1`:\n\n # Invalidate when this user changes.\n cache_key = key_generator(user)\n cache_key = key_generator('alkey:users#1')\n\n # Invalidate when any user is inserted, updated or deleted.\n cache_key = key_generator(user.__class__)\n cache_key = key_generator('alkey:users#*')\n\n # Invalidate when any instance of any type is inserted, updated or deleted.\n cache_key = key_generator('alkey:*#*')\n\nOr you can directly get the instance token with `alkey.cache.get_token`, e.g.:\n\n from alkey.cache import get_token\n from alkey.client import get_redis_client\n \n redis_client = get_redis_client()\n \n token = get_token(redis_client, user)\n token = get_token(redis_client, 'alkey:users#1')\n\n## Pyramid Integration\n\nIf you're writing a [Pyramid][] application, you can bind to the session events\nby just including the package:\n\n config.include('alkey')\n\nThis will, by default, use the [pyramid_basemodel][] threadlocal scoped session.\nTo use a different session class, provide a dotted path to it as the\n`alkey.session_cls` in your .ini settings, e.g.:\n\n alkey.session_cls=myapp.model.Session\n\nAn appropriately configured `alkey.cache.CacheKeyGenerator` instance will then\nbe available as ``request.cache_key``, e.g:\n\n key = request.cache_key(instance1, instance2, 'arbitrary string')\n\nOr e.g.: in a [Mako template][]:\n\n <%page cached=True, cache_key=${request.cache_key(1, self.uri, instance)} />\n\n## Tests\n\n[Alkey][] has been developed and tested against Python2.7. To run the tests,\ninstall `mock`, `nose` and `coverage` and either hack the `setUp` method in\n`alkey.tests:IntegrationTest` or have a Redis db available at\n`redis://localhost:6379`. Then, e.g.:\n\n $ nosetests alkey --with-doctest --with-coverage --cover-tests --cover-package alkey\n ..........................\n Name Stmts Miss Cover Missing\n ------------------------------------------------\n alkey 11 0 100% \n alkey.cache 74 0 100% \n alkey.client 73 0 100% \n alkey.constants 6 0 100% \n alkey.events 12 0 100% \n alkey.handle 76 0 100% \n alkey.interfaces 6 0 100% \n alkey.tests 184 0 100% \n alkey.utils 30 0 100% \n ------------------------------------------------\n TOTAL 472 0 100% \n ----------------------------------------------------------------------\n Ran 26 tests in 0.566s\n \n OK\n\n[alkey]: http://github.com/thruflo/alkey\n[Redis]: http://redis.io\n[SQLAlchemy]: http://www.sqlalchemy.org/\n[redis client]: https://github.com/andymccurdy/redis-py\n[before_flush]: http://docs.sqlalchemy.org/ru/latest/orm/events.html#sqlalchemy.orm.events.SessionEvents.before_flush\n[after_commit]: http://docs.sqlalchemy.org/ru/latest/orm/events.html#sqlalchemy.orm.events.SessionEvents.after_commit\n[Pyramid]: http://docs.pylonsproject.org/projects/pyramid/en/latest\n[Mako template]: http://www.makotemplates.org/\n[pyramid_basemodel]: http://github.com/thruflo/pyramid_basemodel\n[environment variables]: http://blog.akash.im/per-project-environment-variables-with-forema\n[Heroku addons]: https://www.google.co.uk/search?q=Heroku+addons+redis\n", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://github.com/thruflo/alkey", "keywords": null, "license": "This is free and unencumbered software released into the public domain.", "maintainer": null, "maintainer_email": null, "name": "alkey", "package_url": "https://pypi.org/project/alkey/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/alkey/", "project_urls": { "Download": "UNKNOWN", "Homepage": "http://github.com/thruflo/alkey" }, "release_url": "https://pypi.org/project/alkey/0.7.1/", "requires_dist": null, "requires_python": null, "summary": "Redis backed tool for generating cache keys.", "version": "0.7.1" }, "last_serial": 1738469, "releases": { "0.2.2": [ { "comment_text": "", "digests": { "md5": "2143ef484e6115a80936ad4290369e28", "sha256": "c76f9005fa303daaabe9ad0e2dc332614fc2c2ec80fea2d031b64b5f79fdd62c" }, "downloads": -1, "filename": "alkey-0.2.2.tar.gz", "has_sig": false, "md5_digest": "2143ef484e6115a80936ad4290369e28", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17985, "upload_time": "2013-04-15T09:53:57", "url": "https://files.pythonhosted.org/packages/7a/18/1d8bcba7f6c86a2c44821b0e4df468032242146620341b79c0c5aa63ab35/alkey-0.2.2.tar.gz" } ], "0.2.3": [ { "comment_text": "", "digests": { "md5": "bea44b021c3b10a3aef814545cd1623e", "sha256": "8f8c6e555eb43f2a65e38c7e3f43299f3faf29590f7873a65cb02ddb3747e80e" }, "downloads": -1, "filename": "alkey-0.2.3.tar.gz", "has_sig": false, "md5_digest": "bea44b021c3b10a3aef814545cd1623e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18469, "upload_time": "2013-04-15T21:05:08", "url": "https://files.pythonhosted.org/packages/78/05/403808dd291c30d5595b27a2f330778c94f5aa8c2c3f1ca53e4a37beae4c/alkey-0.2.3.tar.gz" } ], "0.3": [ { "comment_text": "", "digests": { "md5": "e7524fa912fdd80efe2bbb99fe960757", "sha256": "77205c42065e28fa406aa092db371c6ccfebfda03a49ad253cec0a3803b9f3af" }, "downloads": -1, "filename": "alkey-0.3.tar.gz", "has_sig": false, "md5_digest": "e7524fa912fdd80efe2bbb99fe960757", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18813, "upload_time": "2013-04-18T09:58:34", "url": "https://files.pythonhosted.org/packages/b8/6c/bbed4b55e04afd390d23aea5d033f7981122490c0d1edceaa69bc5deb58e/alkey-0.3.tar.gz" } ], "0.3.1": [ { "comment_text": "", "digests": { "md5": "1aca20537b2fbbb00d67c4df1aa2d2ee", "sha256": "5f43030717df638e781fa4bf667153192d3452dba47d5b32ddcb760d71908df9" }, "downloads": -1, "filename": "alkey-0.3.1.tar.gz", "has_sig": false, "md5_digest": "1aca20537b2fbbb00d67c4df1aa2d2ee", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16606, "upload_time": "2013-05-07T10:39:46", "url": "https://files.pythonhosted.org/packages/56/d3/38037df546078caac386c87867f528d273d2b2b8dd8132120b87224f9d3b/alkey-0.3.1.tar.gz" } ], "0.3.1.1": [ { "comment_text": "", "digests": { "md5": "11cc784aa13b44d9ba0f3300e2b4b332", "sha256": "1f5996d29b633135af849043edb8020eb06805ae762da57ac86c6fc25347c927" }, "downloads": -1, "filename": "alkey-0.3.1.1.tar.gz", "has_sig": false, "md5_digest": "11cc784aa13b44d9ba0f3300e2b4b332", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16540, "upload_time": "2013-05-07T11:56:42", "url": "https://files.pythonhosted.org/packages/52/25/8fd072f76b31a3efc0b6dc72dbdb0fa1261a860ba197fdb60126bc98887f/alkey-0.3.1.1.tar.gz" } ], "0.4": [ { "comment_text": "", "digests": { "md5": "fcbc69f31740f308ef080318a655293c", "sha256": "2c112b814bcaf0b83d085c72c323beede152ef826c49062447b53622ede0bc51" }, "downloads": -1, "filename": "alkey-0.4.tar.gz", "has_sig": false, "md5_digest": "fcbc69f31740f308ef080318a655293c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16702, "upload_time": "2013-07-19T15:35:05", "url": "https://files.pythonhosted.org/packages/4d/b5/f99eaa5f0af67706c8cbf068c3e783eae54233edf89b76e5d34a6acbce96/alkey-0.4.tar.gz" } ], "0.4.1": [ { "comment_text": "", "digests": { "md5": "049dde852bf080720dba12ba6892b19d", "sha256": "098a74fee9a636c3017205d9ab7ed9ccef93bd7fc0f2f353ce086cc1bbc87931" }, "downloads": -1, "filename": "alkey-0.4.1.tar.gz", "has_sig": false, "md5_digest": "049dde852bf080720dba12ba6892b19d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16598, "upload_time": "2013-07-22T17:12:46", "url": "https://files.pythonhosted.org/packages/16/89/12aebec5f3ba85fa5e3d543964773cbc41300cbe100d57be88d26db28acb/alkey-0.4.1.tar.gz" } ], "0.5": [ { "comment_text": "", "digests": { "md5": "1e2706634b3f4f0413f50e3d0c53684b", "sha256": "1c6603ce02752aabbb2d91bee0c363aa6cefb0f3773d218b518218589cb94117" }, "downloads": -1, "filename": "alkey-0.5.tar.gz", "has_sig": false, "md5_digest": "1e2706634b3f4f0413f50e3d0c53684b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17321, "upload_time": "2013-08-02T15:12:22", "url": "https://files.pythonhosted.org/packages/ff/79/450d0e70150ec13365c7fe1004f59173c36d53bec62c11c4ec71390a93fb/alkey-0.5.tar.gz" } ], "0.6": [ { "comment_text": "", "digests": { "md5": "3800d608b18801578968f6b86d7f2a7f", "sha256": "71fc6b5ac9ccb5a0528aa8bdf1c2ae0219d905540c7cad07ef269bf40627503e" }, "downloads": -1, "filename": "alkey-0.6.tar.gz", "has_sig": false, "md5_digest": "3800d608b18801578968f6b86d7f2a7f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14890, "upload_time": "2013-10-25T15:24:36", "url": "https://files.pythonhosted.org/packages/30/77/5e65491777fbe764f19436adbec5e0edc3cd3999d9bdc859d1ab8d4bea3a/alkey-0.6.tar.gz" } ], "0.7": [ { "comment_text": "", "digests": { "md5": "e6bdfd3e48af2fc025774d701f736dd3", "sha256": "fc54460ca1dde23500daea5dbdfe467eecf6be6133583f3ff0179ee7ee44ddc4" }, "downloads": -1, "filename": "alkey-0.7.tar.gz", "has_sig": false, "md5_digest": "e6bdfd3e48af2fc025774d701f736dd3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14664, "upload_time": "2015-09-09T14:11:49", "url": "https://files.pythonhosted.org/packages/ed/d6/e104e3eb568b92c01e6c43e9b3df8eb1a10dfda3018eb602920598bbf6a4/alkey-0.7.tar.gz" } ], "0.7.1": [ { "comment_text": "", "digests": { "md5": "bcfa11f67e334cc9950c7a074efcf3f8", "sha256": "c385db78ee1c0e5278e56c8364bcf4410ed8dcc3dc15bb1bdf92fd7861419767" }, "downloads": -1, "filename": "alkey-0.7.1.tar.gz", "has_sig": false, "md5_digest": "bcfa11f67e334cc9950c7a074efcf3f8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14719, "upload_time": "2015-09-25T14:53:29", "url": "https://files.pythonhosted.org/packages/a3/8a/abdd8951abb2b1cbed1348d8195f7eb4c1c5cc130ac45ca2337193239840/alkey-0.7.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "bcfa11f67e334cc9950c7a074efcf3f8", "sha256": "c385db78ee1c0e5278e56c8364bcf4410ed8dcc3dc15bb1bdf92fd7861419767" }, "downloads": -1, "filename": "alkey-0.7.1.tar.gz", "has_sig": false, "md5_digest": "bcfa11f67e334cc9950c7a074efcf3f8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14719, "upload_time": "2015-09-25T14:53:29", "url": "https://files.pythonhosted.org/packages/a3/8a/abdd8951abb2b1cbed1348d8195f7eb4c1c5cc130ac45ca2337193239840/alkey-0.7.1.tar.gz" } ] }