{ "info": { "author": "Uli Fouquet", "author_email": "grok-dev@zope.org", "bugtrack_url": null, "classifiers": [ "Environment :: Web Environment", "Framework :: Zope3", "Intended Audience :: Developers", "License :: OSI Approved :: Zope Public License", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: Implementation", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy" ], "description": "==================\ngrokcore.chameleon\n==================\n\n`grokcore.chameleon` makes it possible to use Chameleon page templates in Grok.\nFor more information on Grok and Chameleon page templates see:\n\n- http://pagetemplates.org/\n- http://pagetemplates.org/docs/latest/\n- http://pypi.python.org/pypi/Chameleon\n- http://grok.zope.org/\n\n.. contents::\n\nInstallation\n============\n\nNote that future versions of grok will depend itself on grokcore.chameleon\nand configure it. In other words, chameleon-based templates will be available\nby default from that version on!\n\nTo use Chameleon page templates with Grok all you need is to install\ngrokcore.chameleon as an egg and include its ZCML. The best place to do\nthis is to make `grokcore.chameleon` a dependency of your application by\nadding it to your ``install_requires`` list in ``setup.cfg``. If you\nused grokproject to create your application ``setup.py`` is located in the\nproject root. It should look something like this::\n\n install_requires=['setuptools',\n 'grokcore.chameleon',\n # Add extra requirements here\n ],\n\nNote that if you use the ``allow-picked-versions = false`` directive in your\nproject's ``buildout.cfg``, you will have to add version number specifications\nfor several packages to your ``[versions]`` section.\n\nThen include ``grokcore.chameleon`` in your ``configure.zcml``. If you used\ngrokproject to create your application it's at\n``src//configure.zcml``. Add the include line after the include\nline for grok, but before the grokking of the current package. It should look\nsomething like this::\n\n \n \n \n\nIf you use ``autoInclude`` in your ``configure.zcml``, you should not\nhave to do this latter step.\n\nThen run ``bin/buildout`` again. You should now see buildout saying\nsomething like (where version numbers can vary)::\n\n Getting distribution for 'grokcore.chameleon'.\n Got grokcore.chameleon 0.5.\n\nThat's all. You can now start using Chameleon page templates in your\nGrok application.\n\nUsage\n=====\n\n``grokcore.chameleon`` supports the Grok standard of placing templates in a\ntemplates directory, for example ``app_templates``, so you can use Chameleon\npage templates by simply placing the Chameleon page templates in the templates\ndirectory, just as you would with regular ZPT templates.\n\nAlthough chameleon templates themselves do not have a standard for the file\nextensions for templates, Grok needs to have an association between an filename\nextension and a template language implementation so it knows which\nimplementation to use.\n\n`grokcore.chameleon` declares to use the extension ``*.cpt`` (``Chameleon page\ntemplate``) for Chameleon page templates.\n\nYou can also use Chameleon page templates inline. The syntax for this\nis::\n\n from grokcore.chameleon.components import ChameleonPageTemplate\n index = ChameleonPageTemplate('the html code')\n\nOr if you use files::\n\n from grokcore.chameleon.components import ChameleonPageTemplateFile\n index = ChameleonPageTemplateFile(filename='thefilename.html')\n\n\n====================\nDetailed Description\n====================\n\nGrok-support for using chameleon driven templates.\n\nWith `grokcore.chameleon` you can use templates parsed and rendered by\n`Chameleon`_ using the Zope Page Template templating language.\n\nChameleon Zope page templates\n=============================\n\nChameleon provides support for Zope page templates which can be used\nfrom grok writing templates with the ``.cpt`` (=Chameleon Page\nTemplate) filename extension.\n\nChameleon page templates differ from standard Zope page templates in a\nfew aspects, most notably:\n\n* Expressions are parsed in ``Python-mode`` by default. This means,\n instead of ``tal:content=\"view/value\"`` you must use\n ``tal:content=\"view.value\"``. Every occurence of TAL-expressions\n starting with ``python:`` now can be shortened by skipping this\n marker.\n\n* Also Genshi-like variable substitutions are supported. For example\n you can write ``${myvar}`` instead of ``tal:content=\"myvar\"``.\n\nBeside this, most rules for regular Zope page templates apply also to\nchameleon page templates.\n\nSee the `Chameleon`_ page for more information.\n\n.. _Chameleon: http://chameleon.repoze.org/docs/latest/zpt.html\n\nPrerequisites\n=============\n\nBefore we can see the templates in action, we care for correct\nregistration and set some used variables:\n\n >>> import os\n >>> testdir = os.path.join(os.path.dirname(__file__), 'tests')\n >>> cpt_fixture = os.path.join(testdir, 'cpt_fixture')\n >>> template_dir = os.path.join(cpt_fixture, 'app_templates')\n\nWe register everything. Before we can grok our fixture, we have to\ngrok the `grokcore.chameleon` package. This way the new template types\nare registered with the framework:\n\n >>> import grokcore.view\n >>> grokcore.view.testing.grok('grokcore.chameleon')\n >>> grokcore.view.testing.grok('grokcore.chameleon.tests.cpt_fixture')\n\nWe create a mammoth, which should provide us a bunch of chameleon page\ntemplate driven views and put it in the database to setup location\ninfo::\n\n >>> from grokcore.chameleon.tests.cpt_fixture.app import Mammoth\n >>> manfred = Mammoth()\n >>> getRootFolder()['manfred'] = manfred\n\nFurthermore we prepare for getting the different views on manfred:\n\n >>> from zope.publisher.browser import TestRequest\n >>> from zope.component import getMultiAdapter\n >>> request = TestRequest()\n\nSimple templates\n================\n\nWe prepared a plain cavepainting view. The template looks like this:\n\n >>> cavepainting_cpt = os.path.join(template_dir, 'cavepainting.cpt')\n >>> print(open(cavepainting_cpt, 'r').read())\n \n \n A cave painting.\n \n \n\nThe rendered view looks like this:\n\n >>> view = getMultiAdapter((manfred, request),\n ... name='cavepainting')\n >>> print(view())\n \n \n A cave painting.\n \n \n\nSubstituting variables\n======================\n\nA template can access variables like ``view``, ``context``, ``static``\nand its methods and attributes. The ``food`` view does exactly\nthis. The template looks like this:\n\n >>> food_cpt = os.path.join(template_dir, 'food.cpt')\n >>> print(open(food_cpt, 'r').read())\n \n \n \n ${view.me_do()}\n \n CSS-URL: ${path:static/test.css}\n My context is: ${view.url(context)}\n ${foo}\n \n \n \n \n\nThe rendered view looks like this:\n\n >>> view = getMultiAdapter((manfred, request), name='food')\n >>> print(view())\n \n \n \n <ME GROK EAT MAMMOTH!>\n \n CSS-URL: dummy:/test.css\n My context is: http://127.0.0.1/manfred\n a FOO\n a FOO\n \n \n \n\nAs we can see, there is a difference between Genshi-like substitution\nand TAL-like substitution: while both expressions::\n\n ${view.me_do()}\n\nand::\n\n \n\nactually render the same string ````, the former\ndoes this straight and plain, while the latter performs additionally\nHTML-encoding of the string. Therefore the output of both expressions\ndiffer. It's::\n\n \n\nfor the former expression and::\n\n <ME GROK EAT MAMMOTH!>\n\nfor the latter.\n\n\nSupported variables\n===================\n\nEach template provides at least the following vars:\n\n* ``template``\n the template instance\n\n* ``view``\n the associated view\n\n* ``context``\n the context of the view\n\n* ``request``\n the current request\n\nas we can see, when we look at the ``vars.cpt`` from our fixture:\n\n >>> cpt_file = os.path.join(template_dir, 'vars.cpt')\n >>> print(open(cpt_file, 'r').read())\n \n \n This template knows about the following vars:\n \n template (the template instance):\n ${template}\n \n view (the associated view):\n ${view}\n \n context (the context of the view):\n ${context}\n \n request (the current request):\n ${request}\n \n \n\nand render it:\n\n >>> view = getMultiAdapter((manfred, request), name='vars')\n >>> print(view())\n \n \n This template knows about the following vars:\n \n template (the template instance):\n <PageTemplateFile ...vars.cpt>\n \n view (the associated view):\n <grokcore.chameleon.tests.cpt_fixture.app.Vars object at 0x...>\n \n context (the context of the view):\n <grokcore.chameleon.tests.cpt_fixture.app.Mammoth object at 0x...>\n \n request (the current request):\n CONTENT_LENGTH:\t0\n GATEWAY_INTERFACE:\tTestFooInterface/1.0\n HTTP_HOST:\t127.0.0.1\n SERVER_URL:\thttp://127.0.0.1\n \n \n\nCustom template namespace names are supported:\n\n >>> view = getMultiAdapter((manfred, request), name='namespace')\n >>> print(view())\n \n \n This template knows about the following custom namespace name:\n \n myname:\n Henk\n \n \n \n\nInline Templates\n================\n\nWe can also define inline templates. In our ``app.py`` we defined an\ninline template like this::\n\n from grokcore.chameleon import components\n\n ...\n\n class Inline(grokcore.view.View):\n sometext = 'Some Text'\n\n inline = components.ChameleonPageTemplate(\n \"ME GROK HAS INLINES! ${view.sometext}\")\n\nIf we render this view we get:\n\n >>> view = getMultiAdapter((manfred, request), name='inline')\n >>> print(view())\n ME GROK HAS INLINES! Some Text\n\nTAL expressions\n===============\n\nStarting with ``grokcore.chameleon`` 0.5 we deploy the all-in-one\n`Chameleon`_ package.\n\nWhat TAL/TALES expressions in templates are supported depends mainly\nfrom the installed version of `Chameleon`, while we support some\nadditional, Zope-related TALES expressions.\n\nA list of all supported expressions and statements can be found at the\n`chameleon.zpt documentation\n`_. The additional\nTALES expressions provided by ``grokcore.chameleon`` are:\n\n* ``exists``\n Tell whether a name exists in the templates' namespace.\n\n* ``not``\n Evaluate the expression to a boolean value and invert it.\n\n* ``path``\n Handle the expression as a path and not as a Python expression.\n\n* ``provider``\n Support for viewlet providers.\n\n.. note:: Starting with ``grokcore.chameleon`` 0.5 support for the\n Python expression ``exists()`` has been dropped. The TALES\n expression ``exists: path/to/something`` is still available.\n\nIn our ``app.py`` we defined a special view for showing some special\nexpressions. This also includes a viewlet::\n\n import grok\n from grokcore.chameleon import components\n\n class Mammoth(grok.Application, grok.Container):\n pass\n\n ...\n\n class Expressions(grok.View):\n pass\n\n class MainArea(grok.ViewletManager):\n grok.name('main')\n\n class MainContent(grok.Viewlet):\n grok.view(Expressions)\n grok.viewletmanager(MainArea)\n def render(self):\n return 'Hello from viewlet'\n\nNow we can make use of the TALES expressions ``not:``, ``path:``,\n``exists:`` and ``provider:`` in the ``expressions.cpt`` template of\nour fixture:\n\n >>> cpt_file = os.path.join(template_dir, 'expressions.cpt')\n >>> print(open(cpt_file, 'r').read())\n \n \n
\n \n
\n ${food}\n
\n \n \n
\n
\n
\n
\n \n \n
\n \n \n \n \n
\n \n \n\nand render it:\n\n >>> view = getMultiAdapter((manfred, request), name='expressions')\n >>> print(view())\n \n \n \n \n
\n Yummy Dinoburger\n
\n \n \n
False
\n
False
\n
True
\n
True
\n \n \n
YUMMY DINOBURGER
\n \n \n Hello from viewlet\n \n \n \n \n\nTranslation\n===========\n\n >>> # Monkeypatch zope.i18n.negotiate\n >>> import zope.i18n\n >>> import zope.i18n.config\n >>> print(getMultiAdapter((manfred, request), name='menu')())\n \n \n

Menu

\n
    \n
  1. Deepfried breaded veal cutlets
  2. \n
\n \n \n\n >>> # What's for food today in Germany?\n >>> # We need to monkey patch the language settings for this test.\n >>> old_1, old_2 = zope.i18n.negotiate, zope.i18n.config.ALLOWED_LANGUAGES\n >>> zope.i18n.negotiate = lambda context: 'de'\n >>> zope.i18n.config.ALLOWED_LANGUAGES = ['de']\n >>> print(getMultiAdapter((manfred, request), name='menu')())\n \n \n

Menu

\n
    \n
  1. Schnitzel
  2. \n
\n \n \n\n >>> # Restore the monkey patch.\n >>> zope.i18n.negotiate, zope.i18n.config.ALLOWED_LANGUAGES = old_1, old_2\n\nMacros\n======\n\nWith ``grokcore.chameleon`` we can also use macros, although it is a bit\ndifferent from regular Zope page templates.\n\nWe can define macros like this:\n\n >>> cpt_file = os.path.join(template_dir, 'macromaster.cpt')\n >>> print(open(cpt_file, 'r').read())\n

\n Hello from macro master\n

\n\nThe defined macro ``hello`` can be rendered in another Chameleon\ntemplate with the METAL attribute ``use-macro``.\n\nTo refer to a local macro, i.e. a macros defined in the same template,\nyou can use something like::\n\n
']\">\n Replaced by macro\n
\n\nwhere ```` must be an existing macro name.\n\nTo refer to macros in external templates, you must use the ``path:`` expression\nlike this::\n\n
/template/macros/\">\n Replaced by external macro\n
\n\nwhere ```` refers to an existing view on ``context`` and ``macro-\nname`` again refers to an existing macro in the specified template.\n\nNote, that this is different from how you refer to macros in standard Zope page\ntemplates. The short notation ``view/macros/`` works only with\nregular Zope page templates.\n\nThe following template makes use of both methods:\n\n >>> cpt_file = os.path.join(template_dir, 'macrouser.cpt')\n >>> print(open(cpt_file, 'r').read())\n \n \n

\n Hi there from macro user!\n

\n
\n Fill this\n
\n \n
\n user slot\n Fill this too\n
\n \n \n\nWhen rendered also the slot defined in the master template is filled by macro\nuser content:\n\n >>> cpt_file = os.path.join(template_dir, 'macrouser.cpt')\n >>> view = getMultiAdapter((manfred, request), name='macrouser')\n >>> print(view())\n \n \n

\n Hi there from macro user!\n

\n

\n Hi there from macro user!\n

\n \n \n

\n Hello from user slot\n \n

\n \n \n\n\nClean up:\n\n >>> del getRootFolder()['manfred']\n\nDifferences from regular Zope page templates\n============================================\n\n* Macros are referenced differently. See appropriate section above.\n\n* Expressions are parsed in ``Python-mode`` by default. This means, instead\n of ``tal:content=\"view/value\"`` you must use ``tal:content=\"view.value\"``.\n Every occurence of TAL-expressions starting with ``python:`` now can be\n shortened by skipping this marker.\n\n\nCHANGES\n*******\n\n3.0.1 (2018-01-12)\n==================\n\n- Rearrange tests such that Travis CI can pick up all functional tests too.\n\n3.0.0 (2018-01-11)\n==================\n\n- Python 3 compatibility.\n\n1.0.4 (2014-07-29)\n==================\n\n- Improve the performances of the translate mechanism with Chameleon\n 2.10 or more recent.\n\n1.0.3 (2012-10-12)\n==================\n\n- Fix broken translations when using Chameleon 2.9 or more recent.\n\n1.0.2 (2012-05-07)\n==================\n\n- With not using the z3c.pt PageTemplateFile baseclass, the behaviour of\n finding the template file relative to the module was lost. This has been\n fixed.\n\n1.0.1 (2012-05-03)\n==================\n\n- Make sure the minimal version requirements are defined.\n\n1.0 (2012-05-01)\n================\n\n- The ``target_language`` mangling was lost in version 1.0rc4.\n Copied from z3c.pt.\n\n1.0rc4 (2012-01-03)\n===================\n\n- Update to newes Chameleon 2.7.1\n- Using some Components/Expressions directly from Chameleon instead of z3c.pt\n\n1.0rc3 (2011-07-14)\n===================\n\n- Rename megrok.chameleon into grokcore.chameleon to make it an official part\n of Grok.\n\nEarlier versions\n================\n\n- Earlier versions of grokcore.chameleon came by the name megrok.chameleon.", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://pypi.python.org/pypi/grokcore.chameleon", "keywords": "grok chameleon template", "license": "ZPL", "maintainer": "", "maintainer_email": "", "name": "grokcore.chameleon", "package_url": "https://pypi.org/project/grokcore.chameleon/", "platform": "", "project_url": "https://pypi.org/project/grokcore.chameleon/", "project_urls": { "Homepage": "http://pypi.python.org/pypi/grokcore.chameleon" }, "release_url": "https://pypi.org/project/grokcore.chameleon/3.0.1/", "requires_dist": null, "requires_python": "", "summary": "Chameleon page template support for Grok", "version": "3.0.1" }, "last_serial": 3483904, "releases": { "1.0": [ { "comment_text": "", "digests": { "md5": "41f0c6c85e2a50ad1c8c2123669aec91", "sha256": "031c61d064fcd0207462cd79b39c89359bd492c7f0537c70109746b26aed83e9" }, "downloads": -1, "filename": "grokcore.chameleon-1.0.tar.gz", "has_sig": false, "md5_digest": "41f0c6c85e2a50ad1c8c2123669aec91", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 27952, "upload_time": "2012-05-01T19:33:47", "url": "https://files.pythonhosted.org/packages/5c/87/624ba28a4685543844bb2437019b96468d8379781c87f3b1f9edea09e6fe/grokcore.chameleon-1.0.tar.gz" } ], "1.0.1": [ { "comment_text": "", "digests": { "md5": "2439006011ec47d2801a4f02b6271033", "sha256": "8d6f5e8a877eb0a2551d5e4fb50ec053dfb60ed6f9831994952e238d663cf9f6" }, "downloads": -1, "filename": "grokcore.chameleon-1.0.1.tar.gz", "has_sig": false, "md5_digest": "2439006011ec47d2801a4f02b6271033", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 23332, "upload_time": "2012-05-03T12:12:11", "url": "https://files.pythonhosted.org/packages/48/cd/5668d140213e48bb345cad27018b3b6a5347a018669cbc1046c2d73120c0/grokcore.chameleon-1.0.1.tar.gz" } ], "1.0.2": [ { "comment_text": "", "digests": { "md5": "176f6a8a1a8837f0329a53e713f6e6c3", "sha256": "d796ccc6a874e2143d706c229c558f526375d523893e50f6ee01a6ac37456eb6" }, "downloads": -1, "filename": "grokcore.chameleon-1.0.2.tar.gz", "has_sig": false, "md5_digest": "176f6a8a1a8837f0329a53e713f6e6c3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24320, "upload_time": "2012-05-07T17:47:34", "url": "https://files.pythonhosted.org/packages/b1/d0/3f3cf5b57096bd681405e3109b58975621a1e3fda42e2ab45d51e8179e88/grokcore.chameleon-1.0.2.tar.gz" } ], "1.0.3": [ { "comment_text": "", "digests": { "md5": "304eb554f4c1e0a71cefee279b1762c3", "sha256": "52db3ed22f6f55bb709b8599ff306bd2e37424251246c657035c79a6c40f04dc" }, "downloads": -1, "filename": "grokcore.chameleon-1.0.3.tar.gz", "has_sig": false, "md5_digest": "304eb554f4c1e0a71cefee279b1762c3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 20845, "upload_time": "2012-10-12T09:13:23", "url": "https://files.pythonhosted.org/packages/3e/c4/e38ddea477db95ecef783b98ea47c23ef530e3036bcda0aa47b86e5acec8/grokcore.chameleon-1.0.3.tar.gz" } ], "1.0.4": [ { "comment_text": "", "digests": { "md5": "1a58d62312fa0c80c336e6b57acd76c4", "sha256": "d8af82196c4d65c854c9fd3b326d39d4732eff7c82569b0b188169d55cf3cb09" }, "downloads": -1, "filename": "grokcore.chameleon-1.0.4.zip", "has_sig": false, "md5_digest": "1a58d62312fa0c80c336e6b57acd76c4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 35558, "upload_time": "2014-07-29T10:16:41", "url": "https://files.pythonhosted.org/packages/29/99/c2e207ea800f5998d8dccfb4b5dd337efe593d42858bc34cceeef4bb8146/grokcore.chameleon-1.0.4.zip" } ], "1.0rc3": [ { "comment_text": "", "digests": { "md5": "647532007a6e989dc0e581234078d66b", "sha256": "3da3b92bff5b2109bc9e04606d665b94b93027a23e6ae5ba2f298fa3949d90ed" }, "downloads": -1, "filename": "grokcore.chameleon-1.0rc3.tar.gz", "has_sig": false, "md5_digest": "647532007a6e989dc0e581234078d66b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 19454, "upload_time": "2011-07-14T15:43:11", "url": "https://files.pythonhosted.org/packages/8d/d0/3a2e8ee25ef6997c9ba740fb3aaa33c274a207c171851477a4cdb8ea4f9a/grokcore.chameleon-1.0rc3.tar.gz" } ], "1.0rc4": [ { "comment_text": "", "digests": { "md5": "662f6e92af7d7bfc48dab58bda7da275", "sha256": "486cf0726681201fd194f3dd051a6456a17949d492f0e8f77f16bfc505c9a9d2" }, "downloads": -1, "filename": "grokcore.chameleon-1.0rc4.tar.gz", "has_sig": false, "md5_digest": "662f6e92af7d7bfc48dab58bda7da275", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22650, "upload_time": "2012-01-03T14:19:28", "url": "https://files.pythonhosted.org/packages/c5/79/3d0ed11c796ea9cb5b7bb3c7b3337df50d5c16b98acda37bf886b1f21c9b/grokcore.chameleon-1.0rc4.tar.gz" } ], "3.0.0": [ { "comment_text": "", "digests": { "md5": "29a5a5ed7e3f442db02ef889b9993d7e", "sha256": "4dd0a1a400d6ab3d521fd99960843af3fa8ad918deb1c0b1f2179c18e3bd043b" }, "downloads": -1, "filename": "grokcore.chameleon-3.0.0.tar.gz", "has_sig": false, "md5_digest": "29a5a5ed7e3f442db02ef889b9993d7e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22721, "upload_time": "2018-01-11T08:54:42", "url": "https://files.pythonhosted.org/packages/88/8b/83bff4d587a964a8373f44cec440beb2a68b7092e7aa21e51d00d7d7e3e0/grokcore.chameleon-3.0.0.tar.gz" } ], "3.0.1": [ { "comment_text": "", "digests": { "md5": "7640aa794e2b405f6ae1238639507909", "sha256": "3eb9d4b9bf34b2172e3aedd6f088e74fba2d9dd1f51aa30a4d3ef1a319167aec" }, "downloads": -1, "filename": "grokcore.chameleon-3.0.1.tar.gz", "has_sig": false, "md5_digest": "7640aa794e2b405f6ae1238639507909", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22928, "upload_time": "2018-01-12T12:52:20", "url": "https://files.pythonhosted.org/packages/15/96/4917264b7f29bd82c4c5a3334d66c794c187b08a125b3d368eb3f146237e/grokcore.chameleon-3.0.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "7640aa794e2b405f6ae1238639507909", "sha256": "3eb9d4b9bf34b2172e3aedd6f088e74fba2d9dd1f51aa30a4d3ef1a319167aec" }, "downloads": -1, "filename": "grokcore.chameleon-3.0.1.tar.gz", "has_sig": false, "md5_digest": "7640aa794e2b405f6ae1238639507909", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22928, "upload_time": "2018-01-12T12:52:20", "url": "https://files.pythonhosted.org/packages/15/96/4917264b7f29bd82c4c5a3334d66c794c187b08a125b3d368eb3f146237e/grokcore.chameleon-3.0.1.tar.gz" } ] }