{ "info": { "author": "Mattias Ugelvik", "author_email": "uglemat@gmail.com", "bugtrack_url": null, "classifiers": [ "Intended Audience :: Developers", "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Topic :: Software Development", "Topic :: Text Processing :: General" ], "description": "Contex - Contextual string manipulation\n=======================================\n\nAbstract\n---------\n\nThis package provides ``contex.rules``, an interface which enables a very declarative form of string\nmanipulation, where you can manipulate a string \"in one go\" in sophisticated ways.\n\nThis library also provides two related abstractions, ``StringContext`` and ``MatchContext``, which\ncan be used for a more stateful manipulation of strings. I recommend using ``contex.rules`` as I\nthink that makes for more readable code. Nevertheless, those abstractions are well\ndocumented and might usefully serve as building blocks. Indeed, ``contex.rules`` is implemented on\ntop of them.\n\nThe problem with our interfaces for string manipulation\n-------------------------------------------------------\n\nMy motivation for creating this package was that I was assigned a task in which it was necessary to\nchange strings such as ``'1_Photo032-2008.jpg'`` into ``'1_Photo031-2008.jpg'``. All the numbers could vary\nbetween filenames, and it seemed like I always had to do something inelegant to accomplish this task. Maybe\nit was to match the various parts and stich them back together:\n\n.. code-block:: python\n\n >>> match = re.fullmatch('(\\d+)_Photo(\\d+)-(\\d+)\\.jpg', '1_Photo032-2008.jpg')\n >>> '{}_Photo{}-{}.jpg'.format(match.group(1), '{:0>3}'.format(int(match.group(2))-1), match.group(3))\n '1_Photo031-2008.jpg'\n\nOr using ``re.sub`` with non-consuming regex groups to match the correct area of the string:\n\n.. code-block:: python\n\n >>> re.sub('(\\d+)(?=-\\d+\\.jpg)', lambda m: '{:0>3}'.format(int(m.group(1))-1), '1_Photo032-2008.jpg')\n '1_Photo031-2008.jpg'\n\nShouldn't this be simpler? Describing that string with a regular expression is simple enough, and I'm\nonly changing one little part of the string, so why do I have to fiddle around with indices, and why do\nI have to sacrifice readability? Most importantly, why do I have to experience this aesthetic pain deep\nin my heart?\n\nFirst attempt: stateful manipulation\n------------------------------------\n\nMy first idea was that our abstractions aren't fit for this sort of problem. Strings are flat, they\nhave no sense of context, and if you pull out a substring then it requires special effort to stich it\nback together. The solution? Just keep track of the ``before`` and the ``after``:\n\n.. code-block:: python\n\n >>> view = contex.match('1_Photo032-2008.jpg', '\\d+_Photo(?P\\d+)-\\d+\\.jpg')\n >>> view\n \n >>> view.group('number')\n \n >>> result = view.group('number').replace(lambda n: '{:0>3}'.format(int(n)-1))\n >>> result\n \n >>> str(result)\n '1_Photo031-2008.jpg'\n >>> \n\nThis way I can move around the \"focus point\" of the string with methods such as ``.group``, manipulate that space,\nand when I'm done convert it back to a ``str``. I can even manipulate more than one area of the string:\n\n.. code-block:: python\n\n >>> view = contex.match('1_Photo032-2008.jpg', '\\d+_Photo(?P\\d+)-(?P\\d+)\\.jpg')\n >>> view.group('number').replace('').group('year').replace(lambda y: y[-2:])\n \n >>> \n\n \n``MatchContext`` keeps track of where the matched regular expression groups are: Even though I removed the\ncontent of the \"number\" group, ``MatchContext`` knows where to find and replace the \"year\" group. It can also\ndeal with nested regex groups, 0-length matches etc.\n\n.. note::\n\n Previously (v2.0.1 and earlier) I allowed arbitrary slicing on ``MatchContext`` objects to select the focus\n point in addition to the ``.group`` method. This was a mistake. When you're dealing with 0-length slices and\n adjacent regex groups that matched 0-length strings, there arises serious problems of semantics. I found out\n that the expected semantics is inextricably linked to which regex group you previously selected with ``.group``,\n and therefore had to disallow slicing for ``MatchContext`` objects.\n\n \n\nRemoving the state: Vive la Revolution\n--------------------------------------\n\nThe ``MatchContext`` abstraction certainly is an improvement for these particular types of problems, but\nthere is one downside to it, and that is that it adds an additional layer of state to ordinary strings:\nThe programmer must remember which part of the string is in \"focus\", or, in other words, which state the\nstring is in.\n\nSo my next challenge was to eliminate the state. What I found out was that only in rare cases is the state\nneeded or useful, and this lead me to believe that the fundamental problem isn't really the abstractions we\nuse for representing strings, but rather the interfaces we have for manipulating them. Thus, pardon the pun,\nenter ``contex.rules``:\n\n.. code-block:: python\n\n >>> contex.rules('\\d+_Photo(?P\\d+)-(?P\\d+)\\.jpg', {\n ... 'number': lambda n: '{:0>3}'.format(int(n) - 1),\n ... 'year': lambda y: y[-2:]\n ... }).apply('1_Photo032-2008.jpg')\n '1_Photo031-08.jpg'\n\nOr maybe I want to change the layout of the filename completely:\n\n.. code-block:: python\n\n\n >>> contex.rules('(\\d+)_Photo(?P\\d+)-(?P\\d+)\\.jpg', {\n ... 'number': lambda n: int(n) - 1,\n ... 'year': lambda y: y[-2:]\n ... }).expand('1_Photo032-2008.jpg', 'Photo_{1}_{number:0>3}-{year}.jpeg')\n 'Photo_1_031-08.jpeg'\n\n \nThe string manipulation is done in one go. The programmer doesn't need to remember where the focus point is\nright now, or specify which order to do the replacements in. This is a much more *declarative* interface: you\ntell it what the string looks like, what changes you want made, and it figures out the rest. You don't need to\nstich the pieces back together, and can create more readable regular expressions as well because of that.\n\nNested regex groups are also allowed: the nested one will be replaced first (which will make a difference if\nthe replacement for the outer group is a callable).\n\nMore advanced example\n^^^^^^^^^^^^^^^^^^^^^\n\nHere's an example using ``re.search`` (as opposed to ``re.fullmatch``, which is the default):\n\n.. code-block:: python\n\n >>> contex.rules('(?P\\d)\\d{3}', {\n ... 'millennium': lambda s: int(s)+1,\n ... 0: lambda y: '{}'.format(y)\n ... }, method=re.search).apply('Current year: 2015')\n 'Current year: 3015'\n\nNotice that the ``'millennium'`` group is replaced before the ``0`` group.\n\n``contex.rules`` is explained in more detail in its very long docstring.\n\nDoubtful stability\n------------------\n\nIn order to retrieve certain information about the regular expressions to resolve ambiguities related to 0-length\nmatches and so on, I've seen it necessary to use ``sre_parse.parse`` to parse the regular expressions. This is\nan \"internal support module\" or something like that, and the stability of this library becomes doubtful as a result.\nMy judgement was that it would take a lot of time and effort to create my own parser for python regular expressions,\nand I could easily create some bugs in that parser too.\n\nConclusion\n----------\n\nI hope that the examples of ``contex.rules`` I have given are sufficiently intuitive so that any programmer can look\nat them and infer pretty accurately what they do, because the whole point of this endeavor is to increase readability.\n\nFurthermore, I'd be interested to see if other people can take this idea ``^\\w{7}``\n\nUsing Contex\n------------\n\nThe ``contex`` package contains 5 functions:\n\n- ``rules(regex, rule_dict, method=re.fullmatch, flags=0)`` for declarative string manipulation.\n- ``T(string)`` for converting a string into a ``StringContext`` object.\n- ``search(string, pattern, flags=0)`` and\n- ``match(string, pattern, flags=0)`` for regex searches (with the same semantic difference as in the ``re`` module).\n They both return a ``MatchContext`` object.\n- ``find(string, substring, right_side=False)`` for finding a substring, returns a ``StringContext`` object.\n \n``contex`` also contains the ``StringContext`` and ``MatchContext`` classes.\n\nInstalling\n----------\n\n``contex`` should work in both Python 2.7 and 3. \n\nInstall with ``$ pip install contex``. If you want to install for Python 3 you might want to replace ``pip`` with ``pip3``, depending on how your system is configured.\n\n\nDeveloping\n----------\n\nContex is documented and tested. Run ``$ nosetests`` or\n``$ python3 setup.py test`` to run the tests. The code is hosted at https://notabug.org/Uglemat/Contex\n\nLicense\n-------\n\nThe library is licensed under the GNU General Public License 3 or later.\nThis README file is public domain.", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://notabug.org/Uglemat/Contex", "keywords": null, "license": "GPL3+", "maintainer": null, "maintainer_email": null, "name": "contex", "package_url": "https://pypi.org/project/contex/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/contex/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://notabug.org/Uglemat/Contex" }, "release_url": "https://pypi.org/project/contex/3.1.1/", "requires_dist": null, "requires_python": null, "summary": "Contextual string manipulation", "version": "3.1.1" }, "last_serial": 1689746, "releases": { "1.0": [ { "comment_text": "", "digests": { "md5": "f5dc5be0b5debf7955e8547f680885c3", "sha256": "632737685770f50de15097109e9271e63e285dd88b31b972d09805e9164bc5a7" }, "downloads": -1, "filename": "contex-1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "f5dc5be0b5debf7955e8547f680885c3", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 12468, "upload_time": "2015-03-28T06:58:47", "url": "https://files.pythonhosted.org/packages/a8/ee/93317195040cb181e0995b821083ee1a267376d9b3af7711e125426d9a68/contex-1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "820e17e377c566d1b62753fd0aefd854", "sha256": "815e06e4a071357c0b208e47eff477b333964f160fa0bdbae4e42435cf8fee94" }, "downloads": -1, "filename": "contex-1.0.tar.gz", "has_sig": false, "md5_digest": "820e17e377c566d1b62753fd0aefd854", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9488, "upload_time": "2015-03-28T06:58:51", "url": "https://files.pythonhosted.org/packages/8d/13/1e0a536426ee96402fb8a3c6556818d750df31cf587c309df364e2f972fd/contex-1.0.tar.gz" } ], "1.1": [ { "comment_text": "", "digests": { "md5": "50a034f36ed0632069a6123c3231f51d", "sha256": "2105a067592f05952f58f91d8b29ec7fcc9b013a06a722111daa7a6a56f9b391" }, "downloads": -1, "filename": "contex-1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "50a034f36ed0632069a6123c3231f51d", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 13086, "upload_time": "2015-03-28T09:16:28", "url": "https://files.pythonhosted.org/packages/b5/c7/1c950eb713776a455b644c007632885965088af4851f5eaf7735d70f0853/contex-1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f1d6b13ceacd8fc4b17ad9a0172196ee", "sha256": "080a11f5ef46d684396e28dcf450d57f58a9e5f2bb5c7dc6fdf3537174397982" }, "downloads": -1, "filename": "contex-1.1.tar.gz", "has_sig": false, "md5_digest": "f1d6b13ceacd8fc4b17ad9a0172196ee", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10243, "upload_time": "2015-03-28T09:16:32", "url": "https://files.pythonhosted.org/packages/61/b0/8432a9b23c9ed116aaf6b06824405529a225fe37e255abd8481c17221a54/contex-1.1.tar.gz" } ], "1.2": [ { "comment_text": "", "digests": { "md5": "f6acd9659310947f3927eca43d347428", "sha256": "f2fa553783700f4cda5c3850e8a2ab0cc2a8fc18a7da8fd0e45f75a01b0f3019" }, "downloads": -1, "filename": "contex-1.2-py3-none-any.whl", "has_sig": false, "md5_digest": "f6acd9659310947f3927eca43d347428", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 13122, "upload_time": "2015-03-28T13:42:11", "url": "https://files.pythonhosted.org/packages/44/24/7916b35aadaefaf0d737e58ab112741d60b1daf15a56ec2ccd2bd8a975a8/contex-1.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "82478c7150f19067aea962dbf2311fcf", "sha256": "73b17f52d66baea0847048c36fa50a499e67807ee103943b959b73663db6f27f" }, "downloads": -1, "filename": "contex-1.2.tar.gz", "has_sig": false, "md5_digest": "82478c7150f19067aea962dbf2311fcf", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10280, "upload_time": "2015-03-28T13:42:14", "url": "https://files.pythonhosted.org/packages/6b/5e/7eb5b55891aadf2c3eac4bbe5d206b66f59faab9b899bfd29631e0f068bf/contex-1.2.tar.gz" } ], "2.0": [ { "comment_text": "", "digests": { "md5": "9e3cbdd50f59c402fbfcf694bd363e91", "sha256": "3c745f13c378f3e6b1735700da48f98676cec3c704392bb0eb3868f0dbfdd079" }, "downloads": -1, "filename": "contex-2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "9e3cbdd50f59c402fbfcf694bd363e91", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 13163, "upload_time": "2015-03-29T04:54:29", "url": "https://files.pythonhosted.org/packages/a2/de/23a8c20dd9f1ab002aa3fef0456a2e79bcdd726d11523a6ed230b31b5b43/contex-2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f9a5de657698661881646f43c15faa2a", "sha256": "09a642985f0401f0d44967b554174344bb991960af7489583a2779577cf8fe31" }, "downloads": -1, "filename": "contex-2.0.tar.gz", "has_sig": false, "md5_digest": "f9a5de657698661881646f43c15faa2a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10321, "upload_time": "2015-03-29T04:54:32", "url": "https://files.pythonhosted.org/packages/3f/18/322fb9b176219c2d055097e791cf189daea7a40cf7ab177529d07d548f31/contex-2.0.tar.gz" } ], "2.0.1": [ { "comment_text": "", "digests": { "md5": "8fb652137bc03e359158369452853164", "sha256": "6fe59cbf4dbcc1759b9588cc14258c63a8c6ba25506a61f9636905db58b50001" }, "downloads": -1, "filename": "contex-2.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "8fb652137bc03e359158369452853164", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 13186, "upload_time": "2015-03-29T05:09:40", "url": "https://files.pythonhosted.org/packages/26/60/0269ad3c13df74376fea1ee165691c6c6d84fa1d9f3202c18be1f866261b/contex-2.0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "ee35b0555c770167594ba43d602cc466", "sha256": "594eb5c1f65470724d3e2492856259994caa0431122c5aff8d54cc4a1b7b9516" }, "downloads": -1, "filename": "contex-2.0.1.tar.gz", "has_sig": false, "md5_digest": "ee35b0555c770167594ba43d602cc466", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10314, "upload_time": "2015-03-29T05:09:43", "url": "https://files.pythonhosted.org/packages/09/78/a048567c04715cfb9f90f6bbb02138dc8582df9be09d859855118f04f5c2/contex-2.0.1.tar.gz" } ], "3": [ { "comment_text": "", "digests": { "md5": "80d118116ad80ff76c5987cafa84efca", "sha256": "c29714593ce15e190e686ea2863fbd1d74fb81937034390db4b12aa282e5e272" }, "downloads": -1, "filename": "contex-3-py3-none-any.whl", "has_sig": false, "md5_digest": "80d118116ad80ff76c5987cafa84efca", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 16605, "upload_time": "2015-04-14T16:33:07", "url": "https://files.pythonhosted.org/packages/1b/d0/4ea78c8d28dac696f2f8eaab10e337f097a6c22afde2c60faed7d58acb76/contex-3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "d6498d03802aa468796ba5af216e6cee", "sha256": "6bb67f8d18471cb41d3f0342e6fa52535fea635f02a809664036929370c7327e" }, "downloads": -1, "filename": "contex-3.tar.gz", "has_sig": false, "md5_digest": "d6498d03802aa468796ba5af216e6cee", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14760, "upload_time": "2015-04-14T16:33:10", "url": "https://files.pythonhosted.org/packages/83/52/4cdb34f1708736241602d38201dae36aef9a2d742c10667ba22fe4a3ef28/contex-3.tar.gz" } ], "3.0.1": [ { "comment_text": "", "digests": { "md5": "113a47eb20034ddbd9b1dd5ecafbf69b", "sha256": "cd103d1a8f1706cb40530144ba432161da573725f8bb3eb9e996efa2855a9ed9" }, "downloads": -1, "filename": "contex-3.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "113a47eb20034ddbd9b1dd5ecafbf69b", "packagetype": "bdist_wheel", "python_version": "3.4", "requires_python": null, "size": 44698, "upload_time": "2015-08-17T12:34:22", "url": "https://files.pythonhosted.org/packages/29/19/ff0df3eaa3d8ff0940927a0847e48023641744d7245338552d8ca2f16f7c/contex-3.0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "716b6a1d428a756a984cb9c26aa5bebc", "sha256": "fae2e37ab1e4d55e087f83e8154bd1f7a5e40f3428f6c44f50d448fa894bd64e" }, "downloads": -1, "filename": "contex-3.0.1.tar.gz", "has_sig": false, "md5_digest": "716b6a1d428a756a984cb9c26aa5bebc", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14754, "upload_time": "2015-08-17T12:34:27", "url": "https://files.pythonhosted.org/packages/37/2d/967ed08d72e88d211e5ac3b00fda42976b0248469db1e7a9d6fbdeab8de8/contex-3.0.1.tar.gz" } ], "3.0.2": [ { "comment_text": "", "digests": { "md5": "aa83e8c72acee5f18a2f142a26ddb5df", "sha256": "b95c58f5e9bdafd4b52b848255ab8720fd95612dc3de49af903761571ea9c674" }, "downloads": -1, "filename": "contex-3.0.2-py3-none-any.whl", "has_sig": false, "md5_digest": "aa83e8c72acee5f18a2f142a26ddb5df", "packagetype": "bdist_wheel", "python_version": "3.4", "requires_python": null, "size": 45082, "upload_time": "2015-08-20T22:16:14", "url": "https://files.pythonhosted.org/packages/37/b4/c688f16cff1736c48778f022077500654362dad0cb68b5bde55800247ddb/contex-3.0.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "1e24d4482879da5b7fa694b84e91b778", "sha256": "0c3d9a15ff0d3aa87bab362c41f17a1d0159502ae250db93bc8b433a24647684" }, "downloads": -1, "filename": "contex-3.0.2.tar.gz", "has_sig": false, "md5_digest": "1e24d4482879da5b7fa694b84e91b778", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14866, "upload_time": "2015-08-20T22:16:08", "url": "https://files.pythonhosted.org/packages/df/96/3c418c41f97448c879f8b63657a5b5849b0ed7f1c799978bd82109ef0c16/contex-3.0.2.tar.gz" } ], "3.1": [ { "comment_text": "", "digests": { "md5": "6671ee106320f8cd1d68237f3228912b", "sha256": "b5a4cbf1ec5425492c9f4802092cda34d5bdb7ab24d7f7f46bdefa26e876d16d" }, "downloads": -1, "filename": "contex-3.1-py3-none-any.whl", "has_sig": false, "md5_digest": "6671ee106320f8cd1d68237f3228912b", "packagetype": "bdist_wheel", "python_version": "3.4", "requires_python": null, "size": 44901, "upload_time": "2015-08-23T16:31:08", "url": "https://files.pythonhosted.org/packages/09/49/ba6991f2fe82637cd41ef1a2d711df939de73c3a93fdab8e53694189c444/contex-3.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "5e1f3a26d95d04fa2bda37835106ae42", "sha256": "a7291aef1cd12a5d0e97d852bcee069bad4f63cb628b305e0927765b8c187f71" }, "downloads": -1, "filename": "contex-3.1.tar.gz", "has_sig": false, "md5_digest": "5e1f3a26d95d04fa2bda37835106ae42", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14792, "upload_time": "2015-08-23T16:31:01", "url": "https://files.pythonhosted.org/packages/e9/a2/bfa9194055c05871672ed0c7d6c9e9cf0e3e8db74172973424091a435ad1/contex-3.1.tar.gz" } ], "3.1.1": [ { "comment_text": "", "digests": { "md5": "c21081179b30bd032969fca5e00474f6", "sha256": "15758d92c3bd6ff4ca60f05913c4f69178268abb730fea8efcf0c43fbbd0aa85" }, "downloads": -1, "filename": "contex-3.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "c21081179b30bd032969fca5e00474f6", "packagetype": "bdist_wheel", "python_version": "3.4", "requires_python": null, "size": 45228, "upload_time": "2015-08-23T16:38:41", "url": "https://files.pythonhosted.org/packages/ae/e7/344fe2ff989587fc60c2543181a57cfd0e52e140adb3032eed841a1184c3/contex-3.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "e89b2c115f8c14363ab3fe3d21de1df2", "sha256": "4f09d371ed77743b89203c9b02c1bdf2e808154ae1f9f9e3d4547279b77a9d20" }, "downloads": -1, "filename": "contex-3.1.1.tar.gz", "has_sig": false, "md5_digest": "e89b2c115f8c14363ab3fe3d21de1df2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14868, "upload_time": "2015-08-23T16:38:37", "url": "https://files.pythonhosted.org/packages/c8/87/961931691ee005aeba6f6d507240a794e1c11c39e15c2002e82b406cedc3/contex-3.1.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "c21081179b30bd032969fca5e00474f6", "sha256": "15758d92c3bd6ff4ca60f05913c4f69178268abb730fea8efcf0c43fbbd0aa85" }, "downloads": -1, "filename": "contex-3.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "c21081179b30bd032969fca5e00474f6", "packagetype": "bdist_wheel", "python_version": "3.4", "requires_python": null, "size": 45228, "upload_time": "2015-08-23T16:38:41", "url": "https://files.pythonhosted.org/packages/ae/e7/344fe2ff989587fc60c2543181a57cfd0e52e140adb3032eed841a1184c3/contex-3.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "e89b2c115f8c14363ab3fe3d21de1df2", "sha256": "4f09d371ed77743b89203c9b02c1bdf2e808154ae1f9f9e3d4547279b77a9d20" }, "downloads": -1, "filename": "contex-3.1.1.tar.gz", "has_sig": false, "md5_digest": "e89b2c115f8c14363ab3fe3d21de1df2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14868, "upload_time": "2015-08-23T16:38:37", "url": "https://files.pythonhosted.org/packages/c8/87/961931691ee005aeba6f6d507240a794e1c11c39e15c2002e82b406cedc3/contex-3.1.1.tar.gz" } ] }