{ "info": { "author": "Alec Mitchell", "author_email": "apm13@columbia.edu", "bugtrack_url": null, "classifiers": [ "Framework :: Plone", "Framework :: Plone :: 4.0", "Framework :: Plone :: 4.1", "Framework :: Plone :: 4.2", "Framework :: Plone :: 4.3", "Framework :: Zope2", "Framework :: Zope3", "Intended Audience :: Developers", "License :: OSI Approved :: Zope Public License", "Programming Language :: Python", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "This package provides an infrastructure for adding ratings to Zope\ncontent. It supports multiple categorized ratings per content object\nand includes views for displaying those ratings. For Plone rating\nsupport, please see `plone.contentratings`.\n\n\nDetailed Documentation\n**********************\n\n===============\nContent Ratings\n===============\n\nThis is a simple python package driven by Zope 3, which lets users\n(including un-authenticated users) rate content. It provides a set of\ninterfaces, adapters and views to allow the application of ratings to\nany IAnnotatable object.\n\nDependencies:\n\n- BTrees\n- persistent\n- zope.annotations\n- zope.app.content\n- zope.app.testing\n- zope.component\n- zope.componentvocabulary\n- zope.container\n- zope.interface\n- zope.lifecycleevent\n- zope.location\n- zope.schema\n- zope.tales\n\nAll of these packages are included in Zope 2.12+ and Plone 4.0+. This\npackage is tested with Plone 4.0-4.3.\n\n\nUsing contentratings in Your Packages or Products\n=================================================\n\nFirst install it somewhere in your *python path* (not in your Products\ndirectory), $INSTANCE_HOME/lib/python may be a good place to start using it\nwith zope. It can be installed as an egg from the Python Cheeseshop (PyPI).\n\nYou'll need to load the zcml for this package, so make sure that the\nconfigure.zcml for your application contains::\n\n \n\nIf you want to allow some content to be rated you must mark it as\n*annotatable*. This is because the Rating Storage is contained in an\nannotation on the content object. The standard way to do this is to\nto add the following to your product's configure.zcml::\n\n \n \n \n\n\nRating Categories\n=================\n\nThis package provides an infrastructure for defining `Rating\nCategories`. A `Rating Category` is an object implementing the\n`IRatingCategory` interface, specifying a `title`, `description` (for\nthe UI), `view_name` (how the rating should be rendered and managed in\nthe UI), TALES expressions which determine when ratings can be viewed\nor set (`read_expr` and `write_expr`), an `order` (for the UI), and\nfinally a `storage` (a factory which creates a persistent\nimplementation of a rating API to be stored in an annotation). All of\nthese attributes except `title` are optional, with sensible default\nvalues provided. Any object may have multiple Rating Categories\napplied to it each registered with a unique `name`.\n\n\nThe Default Categories\n----------------------\n\nThis package's default configuration provides two rating categories.\nOne for user ratings, and one for editorial ratings. They are\nregistered for the marker interfaces `IUserRatable` and\n`IEditorRatable` respectively. The TALES expressions used to\ndetermine when they apply are designed to work with objects contained\nin a Zope 2 CMF application (primarily for backwards compatibility\nwith older versions of `contentratings` which used direct permission\nchecks). Unless they want to allow all users to set and\nread the ratings, other applications will need to define categories with\ncustom conditions.\n\nLet's demonstrate how these categories might be used. We need to\ncreate some content and mark it with our marker interface::\n\n >>> from zope.container.sample import SampleContainer\n >>> content = SampleContainer()\n >>> from contentratings.interfaces import IUserRatable\n >>> from zope.interface import alsoProvides\n >>> alsoProvides(content, IUserRatable)\n\nNow we can adapt to the rating category using the IUserRating interface::\n\n >>> from contentratings.interfaces import IUserRating\n >>> adapted = IUserRating(content)\n >>> adapted.title\n u'User Rating'\n >>> float(adapted.averageRating)\n 0.0\n >>> rating = adapted.rate(7.0)\n >>> float(adapted.averageRating)\n 7.0\n >>> adapted.numberOfRatings\n 1\n >>> rating = adapted.rate(8.0, 'me')\n >>> float(adapted.averageRating)\n 7.5\n >>> adapted.numberOfRatings\n 2\n\nFor more details on the IUserRating API see `tests/userstorage.txt`.\n\nEditorial ratings are applied similarly, but have a much simpler\nimplementation::\n\n >>> from contentratings.interfaces import IEditorRatable, IEditorialRating\n >>> alsoProvides(content, IEditorRatable)\n >>> adapted = IEditorialRating(content)\n >>> adapted.title\n u'Editor Rating'\n >>> adapted.rating is None\n True\n >>> adapted.rating = 6.0\n >>> float(adapted.rating)\n 6.0\n >>> adapted.rating = 8.0\n >>> float(adapted.rating)\n 8.0\n\nSee `tests/editorialstorage.txt` for details on how the\nIEditorialRating API works.\n\nLet's remove these markers now so that we can examine custom\ncategories::\n\n >>> from zope.interface import noLongerProvides\n >>> noLongerProvides(content, IUserRatable)\n >>> noLongerProvides(content, IEditorRatable)\n >>> IUserRatable(content) # doctest: +ELLIPSIS\n Traceback (most recent call last):\n ...\n TypeError: ('Could not adapt', ...)\n >>> IEditorialRating(content) # doctest: +ELLIPSIS\n Traceback (most recent call last):\n ...\n TypeError: ('Could not adapt', ...)\n\nCustom Rating Categories\n------------------------\n\nThere are two ways to create a new rating category, declaratively\nusing ZCML, or programatically using the category factory directly\nfrom python. Let's look at the ZCML way first. To make it work we\nneed to enable the zcml directive::\n\n >>> from zope.configuration import xmlconfig\n >>> import contentratings\n >>> context = xmlconfig.file('meta.zcml', contentratings)\n\nLoading the package configuration will do the above automatically.\n\nNow we register our rating category using the\n`contentratings:category` directive::\n\n >>> context = xmlconfig.string(\"\"\"\n ... \n ... \n ... \"\"\", context=context)\n\n\nHere we have made use of all of the category default values. As a\nresult we have registered a category which uses the default ZODB\nstorage and `IUserRating` API, with no restrictions on who can get\nand set ratings. We can verify this easily since the categories are\nsimply adapters providing the rating interface provided by the\n(default) storage::\n\n >>> from contentratings.interfaces import IUserRating\n >>> from zope.container.sample import SampleContainer\n >>> content = SampleContainer()\n >>> adapted = IUserRating(content)\n >>> IUserRating.providedBy(adapted)\n True\n >>> adapted.context is content\n True\n >>> adapted.title\n u'My Rating Category'\n\nNote that because we provided no name in the configuration, the\nadapter was registered as the default (unnamed) adapter. The name of\nthe category is the name under which the adapter is registered and it\nis stored in the category's name attribute::\n\n >>> adapted.name\n ''\n\nTo provide multiple categories, just register them with unique names::\n\n >>> context = xmlconfig.string(\"\"\"\n ... \n ... \n ... \"\"\", context=context)\n >>> from zope.component import getAdapter\n >>> adapted = getAdapter(content, IUserRating, name=u'other')\n >>> adapted.title\n u'My Other Rating Category'\n >>> adapted.name\n u'other'\n\nIf we wanted to accomplish the same thing programatically, we could\ninstantiate the factory directly and register it as an adpater::\n\n >>> from contentratings.category import RatingsCategoryFactory\n >>> category = RatingsCategoryFactory(title=u'Another Title', name=u'another')\n >>> from zope.component import provideAdapter\n >>> provideAdapter(category, adapts=(SampleContainer,), provides=IUserRating,\n ... name=u'another')\n >>> adapted = getAdapter(content, IUserRating, name=u'another')\n >>> adapted.title\n u'Another Title'\n >>> adapted.name\n u'another'\n\nThis involves some redundancy, since the interface provided by the\nstorage has to be explicitly declared, and the category name has to be\nprovided twice. Otherwise they are equivalent.\n\nNote that categories are adapters, and adapters may only be registered under\nthe same name for different interfaces/classes. As usual, for a given name,\nthe adapter registered for the most specific interface will be chosen.\n\nThe Rating Manager\n==================\n\nWhen the adapter corresponding to a given rating category is\nqueried, the object returned is not actually a `Rating Category`\nitself, but a `Rating Manager`::\n\n >>> adapted # doctest: +ELLIPSIS\n \n >>> from contentratings.interfaces import IRatingManager\n >>> IRatingManager.providedBy(adapted)\n True\n \nThe Rating Manager provides the API of the storage, and also many of\nthe attributes of the category. It protects direct access to the\nstorage by checking the expressions specified for the category. The\nmanager is implemented as a multi-adapter on the category and the\ncontext, but generally it should not be retrieved directly. The\ncategory adapter is responsible for retrieving it. The manager is\nresponsible for setting up the category specific storage on the\ncontent object.\n\n >>> adapted.category # doctest: +ELLIPSIS\n \n >>> adapted.context # doctest: +ELLIPSIS\n \n >>> adapted.storage # doctest: +ELLIPSIS\n \n >>> isinstance(adapted.storage, adapted.category.storage)\n True\n\nSince the rating manager is responsible for security checks and\npopulating the TALES expression context, it is very likely that\napplications will want to replace this component (locally or for\nspecific content) with a subclass to provide application specific\nsecurity.\n\nThe Views\n=========\n\nThe Rating Views\n----------------\n\nEach category has an associated `view_name` which is simply the name\nof a view registered for the rating interface (e.g. IUserRating) to be\nused when rendering the category in the UI. These are looked up on\nthe Rating Manager and have access to the `IRatingManager` API, as\nwell as the protected rating storage API, as provided by the\nmanager (e.g. IUserRating).\n\nResuable base classes for rating views are provided in\n`browser/basic.py` (`BasicUserRatingView` and\n`BasicEditorialRatingView`). These views use a named vocabulary to\nvalidate input and use the IRatingManager API to determine who can and\ncannot rate content. The package configuration provides a few rating\nviews by default::\n\n ratings_view (default): A rating using 1-5 large (25px) stars\n small_stars: A rating using 1-5 small (10px) stars\n three_small_stars: A rating using 1-3 small (10px) stars\n\nThese are each highly customizable using CSS. They are all registered\nfor IUserRating. Additionally, there is a `rating_view` is registered\nfor IEditorialRating.\n\nThe views are responsible for looking up a rating vocabulary and\nvalidating user input, as well as rendering the user interface. The\nsecurity is enforced by the `Rating Manager` used by the view, however\nthe view may go directly to the storage from rating manager if it\nwants to override the expression checking (e.g. showing a user their\nown ratings, though they cannot see others). Creating new views\n(e.g. non-starred ratings) is quite simple.\n\nA utility is provided for efficiently determining a reusable session\nkey in a generic manner. This can be used to prevent repeat voting\nfrom anonymous users. Applications which implement their own\nanonymous session tracking mechanisms may override this utility\nlocally if desired.\n\nThe Aggregator Views\n--------------------\n\nThere are also views which find all the rating categories available on\nthe content object being viewed, rendering them in order. These are\nintended to be used within a viewlet, portlet, macro, or similar. The\naggregator view for user ratings is called `user-ratings` and the one\nfor editorial ratings is called `editorial-ratings`.\n\n\nThe Storage\n===========\n\nThough the `UserRatingStorage` should be sufficient fr most usecases,\nthis package provides a simplemechanism for using custom objects for\nstoring ratings. Two storage factory implementations are included,\nboth of which use the ZODB for storing ratings: one implementing the\n`IUserRating` interface and the other the `IEditorialRating`\ninterface. The former is intended to be used for any content which\nwill be rated (or voted on) by multiple users. The latter stores a\nsingle \"editorial\" rating on content, and exists primarily for\nbackwards compatibility.\n\nA custom sotrage factory (possibly sub-classed from one of the included\nimplementations), can be specified using the `storage` attribute of\nthe zcml directive, or `storage` parameter of the rating category factory.\n\nNot only are the storages replaceable, they can implement completely\ncustom APIs for managing ratings. Though the need for this is is\nprobably limited, you may create a custom storage API by making an\ninterface for managing ratings, and having that interface provide\n`IRatingType`. See the storage documentation in `tests/` for more\ninformation.\n\n\nWhy a New Rating Package\n========================\n\nThere are already the `ATRatings`, `lovely.rating`, `iqpp.rating`, and\n`iqpp.plone.rating` packages, why do we need another package?\n\nFirst, contentratings preceeds all of those except ATRatings, which is\nuseful only under Plone with Archetypes content. `contentratings` was\noriginally a very simple package intended to make it easy for\ndevelopers to add ratings to their products and applications.\nHowever, there appears to be much demand for an end-user product to\nfacilitate adding ratings to existing content objects.\n\nUnfortunately, none of these packages offer direct support for\nmultiple ratings on a single content object, which appears to be a\ncommon need. It also (along with `lovely.rating`) decouples the\nrating scoring system from the view in a manner which is probably\nundesirable for a product which wants to allow user customization of\nratings. Changing these packages to support these use-cases would\nhave required a complete rewrite. As a result, I rewrote the simplest\n(and most familiar) of these rating packages to support these\nusecases, and also created a new package to integrate this new\nfunctionality for Plone end-users (see `plone.contentratings`).\n\nToDo\n====\n\n* Provide view customization examples\n* Make the views work with Zope 3 authentication\n* Port the KSS view from plone.contentratings into contentratings (it\n currently depends on some plone KSS commands)\n\n\nCredits\n=======\n\nAuthor:\n-------\n\n* **Alec Mitchell** \n\n\nContributors:\n-------------\n\n* **Maurizio Delmonte**\n\n(feel free to add your name above if you have made significant contributions)\n\nThanks To:\n----------\n\n* **Geoff Davis** author of `ATRatings` from which icons and ideas were\n stolen.\n\n* **Philipp von Weitershausen** author of\n `Web Component Development with Zope 3`_ which provides a nice example\n of an annotation based rating product, which was the starting point for\n this implementation.\n\n* **Kai Diefenbach** author of `iqpp.plone.rating` from which other icons\n and UI ideas were stolen.\n\n* Some icons are from **Mark James'** `Silk icon set 1.3`_\n\n* The star rating is based on `CSS Star Rating Redux`_ via `iqpp.plone.rating`\n\n.. _`Web Component Development with Zope 3`: http://www.worldcookery.com/\n.. _`Silk icon set 1.3`: http://www.famfamfam.com/lab/icons/silk/\n.. _`CSS Star Rating Redux`: http://komodomedia.com/blog/index.php/2007/01/20/css-star-rating-redux/\n\n\nChangelog\n=========\n\n1.2.1 (2017-03-15)\n----------------\n\n- Fixed XSS vulnerability on rating action\n [keul, cekk]\n\n\n1.1 (2013-09-20)\n----------------\n\n* Update to support Zope 2.13 and Plone 4.0 through 4.3 and clear up\n dependencies.\n\n\n1.0-final (2011-08-21)\n----------------------\n\n* Template markup fixes for chameleon compatibility.\n\n* Added Basque and Catalan translations.\n\n1.0-rc3 (2011-05-12)\n--------------------\n\n* Optimize for average/count calculations with large numbers of\n ratings. Improve performance of most recent rating lookup.\n\n* Fixes for Plone 4.1\n\n1.0-rc2 (2010-11-28)\n--------------------\n\n* Don't use a CSS id in view only rating view so that listings with\n ratings can still have valid html.\n\n\n1.0-rc1 (2010-08-31)\n--------------------\n\n* Add support for view only rating views.\n\n* Remove _v attribute caching.\n\n* Plone 4 / Zope 2.12 compatibility (still works on Plone 3.3.4 / Zope 2.10.11):\n * permissions.py: Don't depend on Products.__ac_permissions__\n * Import ApplicationDefaultPermissions from AccessControl.Permission\n * Fix tests:\n * traverser.py, README.txt: SampleContainer class may come \n from zope.* and zope.app.*\n * utils.py: Date may or may not be followed by semicolon\n * browser/basic.py: add publishTraverse method to BasicEditorialRatingView,\n to prevent faulty traversal.\n * events.py and interfaces.py: Subclass IObjectRatedEvent from IObjectEvent\n (instead of from IObjectModifiedEvent) to prevent permissions errors.\n\n* Added this file\n\n0.2 (2009-05-11)\n----------------", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://plone.org/products/contentratings", "keywords": "ratings zope plone zope3", "license": "ZPL", "maintainer": null, "maintainer_email": null, "name": "contentratings", "package_url": "https://pypi.org/project/contentratings/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/contentratings/", "project_urls": { "Download": "UNKNOWN", "Homepage": "http://plone.org/products/contentratings" }, "release_url": "https://pypi.org/project/contentratings/1.2.1/", "requires_dist": null, "requires_python": null, "summary": "A small Zope 3 package (which also works with Zope 2.10+ and Five) that allows you to attach ratings to content.", "version": "1.2.1" }, "last_serial": 2708060, "releases": { "0.2": [ { "comment_text": "", "digests": { "md5": "4bd519f1725bd30c67ba844570c5ac2b", "sha256": "eab142bc3dc814aeafac4d8a08ad32c0c8446327e9ade8e6af65c6756b60935a" }, "downloads": -1, "filename": "contentratings-0.2-py2.4.egg", "has_sig": false, "md5_digest": "4bd519f1725bd30c67ba844570c5ac2b", "packagetype": "bdist_egg", "python_version": "2.4", "requires_python": null, "size": 34298, "upload_time": "2008-05-11T14:22:11", "url": "https://files.pythonhosted.org/packages/d4/19/1f2acf80a973344390b1c02ce49b6048bb04f1399ee697aa3fde57bdd72f/contentratings-0.2-py2.4.egg" }, { "comment_text": "", "digests": { "md5": "299a6eabde0007846b3fc2ddce831d2c", "sha256": "03fc637bbeeb292849399103f2c910a7793a670b62b2fc47a25911716ecbf539" }, "downloads": -1, "filename": "contentratings-0.2.tar.gz", "has_sig": false, "md5_digest": "299a6eabde0007846b3fc2ddce831d2c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 15381, "upload_time": "2008-05-11T14:22:12", "url": "https://files.pythonhosted.org/packages/4b/b1/980aa818c383c93f9550322544683dae1f4eeeb8b137081211c9b09fdce4/contentratings-0.2.tar.gz" } ], "1.0": [ { "comment_text": "", "digests": { "md5": "578e700309c91cac0aed2cb5ae398bd1", "sha256": "dc6ed4be91ca70ae7c1685f9cfd53614c8ffa24bbc5f6962dfad2f11bc89507c" }, "downloads": -1, "filename": "contentratings-1.0.zip", "has_sig": false, "md5_digest": "578e700309c91cac0aed2cb5ae398bd1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 117382, "upload_time": "2011-08-22T01:07:35", "url": "https://files.pythonhosted.org/packages/16/51/fd36d524da7d04cdc17572b289224b23008752991d77783fe2354ff1840f/contentratings-1.0.zip" } ], "1.0-beta1": [ { "comment_text": "", "digests": { "md5": "8a0ce4bd8d3c37bf1d9b5bf9ae498a4f", "sha256": "37fd752e9964c016b68bc67c583610b265ffb76a4b3a7cc280f0e0e00d445e4b" }, "downloads": -1, "filename": "contentratings-1.0_beta1-py2.4.egg", "has_sig": false, "md5_digest": "8a0ce4bd8d3c37bf1d9b5bf9ae498a4f", "packagetype": "bdist_egg", "python_version": "2.4", "requires_python": null, "size": 113750, "upload_time": "2008-05-11T13:47:06", "url": "https://files.pythonhosted.org/packages/d2/d3/58decfbf539f52addb2da5f7f27c94906779cd324ac8f4740ec9e534eb61/contentratings-1.0_beta1-py2.4.egg" }, { "comment_text": "", "digests": { "md5": "1de9ea586e256d5958b1768dea9b95ab", "sha256": "4fcb66e20f920d6392d928a321618b00ac137998894957f4c5b61d8afe3a5f34" }, "downloads": -1, "filename": "contentratings-1.0-beta1.tar.gz", "has_sig": false, "md5_digest": "1de9ea586e256d5958b1768dea9b95ab", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 54969, "upload_time": "2008-05-11T13:47:08", "url": "https://files.pythonhosted.org/packages/a2/af/9040c0c76aa6ecf611203cea45147ce8c16dcbc51f0c9efe3aac6fc35407/contentratings-1.0-beta1.tar.gz" } ], "1.0-rc1": [ { "comment_text": "", "digests": { "md5": "d2142f85207f5bc0aed45bb7e9f49005", "sha256": "59acbf68f6303bae226a7487ad0e9ef5d1db5a2b52311eea1c9eae0771c1708b" }, "downloads": -1, "filename": "contentratings-1.0-rc1.zip", "has_sig": false, "md5_digest": "d2142f85207f5bc0aed45bb7e9f49005", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 111091, "upload_time": "2010-09-01T04:34:46", "url": "https://files.pythonhosted.org/packages/87/5e/fd6d52e7f1d0b6b1387b4a027d4654585dd8204a1df52dfea2dfbc9b0286/contentratings-1.0-rc1.zip" } ], "1.0-rc2": [ { "comment_text": "", "digests": { "md5": "02ce168fbd1485ddcd62c77ad36f86f2", "sha256": "e24c292506b14635bdb2f1b0f4e18175cf4e168f8698e51d79b268e54c6d03f4" }, "downloads": -1, "filename": "contentratings-1.0-rc2.zip", "has_sig": false, "md5_digest": "02ce168fbd1485ddcd62c77ad36f86f2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 111129, "upload_time": "2010-11-29T05:26:19", "url": "https://files.pythonhosted.org/packages/c3/e9/2d55507df6b84df4facb474b2bb0c5e8f2e69c3aff3c44d411e397e09f6e/contentratings-1.0-rc2.zip" } ], "1.0-rc3": [ { "comment_text": "", "digests": { "md5": "5e7da3b562d8a86f29c2e2573b2bde36", "sha256": "9199fabe63cf2337ab1a179cc46781c970b78ce715fda3c4ff2dbd017667a4bd" }, "downloads": -1, "filename": "contentratings-1.0-rc3.zip", "has_sig": false, "md5_digest": "5e7da3b562d8a86f29c2e2573b2bde36", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 111489, "upload_time": "2011-05-13T01:17:00", "url": "https://files.pythonhosted.org/packages/9f/e7/0451737d7174f1031e3147615c5a8d336892b72b2285c8f8cb6363865980/contentratings-1.0-rc3.zip" } ], "1.1": [ { "comment_text": "", "digests": { "md5": "fbbe30a5e53834450f2a3a3a9500b1de", "sha256": "1ee547f4e6d6cf246a06a160534fa2439fc17b7f94da339a1351e9def07b0842" }, "downloads": -1, "filename": "contentratings-1.1.zip", "has_sig": false, "md5_digest": "fbbe30a5e53834450f2a3a3a9500b1de", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 120375, "upload_time": "2013-09-20T18:12:12", "url": "https://files.pythonhosted.org/packages/58/3b/af6e2e70c6f8c6e5dbde46cc26ba2d96aecf35f0b67eb88658a1d74ba9a5/contentratings-1.1.zip" } ], "1.2.1": [ { "comment_text": "", "digests": { "md5": "31cff29ee469207afa6ca42299894e19", "sha256": "7fe89071bfc0f716f6b3a58a43adcaee770f4d89bf3b390c3a6db2356d319e60" }, "downloads": -1, "filename": "contentratings-1.2.1.zip", "has_sig": false, "md5_digest": "31cff29ee469207afa6ca42299894e19", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 107706, "upload_time": "2017-03-15T17:54:11", "url": "https://files.pythonhosted.org/packages/47/32/f5c7c858116a8758959c33a855d4201714540c10b5f5db3d9cc02443232e/contentratings-1.2.1.zip" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "31cff29ee469207afa6ca42299894e19", "sha256": "7fe89071bfc0f716f6b3a58a43adcaee770f4d89bf3b390c3a6db2356d319e60" }, "downloads": -1, "filename": "contentratings-1.2.1.zip", "has_sig": false, "md5_digest": "31cff29ee469207afa6ca42299894e19", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 107706, "upload_time": "2017-03-15T17:54:11", "url": "https://files.pythonhosted.org/packages/47/32/f5c7c858116a8758959c33a855d4201714540c10b5f5db3d9cc02443232e/contentratings-1.2.1.zip" } ] }