{ "info": { "author": "Eric Casteleijn", "author_email": "thisfred@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Topic :: Software Development :: Libraries" ], "description": "val\n===\n\n.. image:: https://travis-ci.org/thisfred/val.svg?branch=master\n :target: https://travis-ci.org/thisfred/val\n.. image:: https://coveralls.io/repos/thisfred/val/badge.svg?branch=master\n :target: https://coveralls.io/r/thisfred/val?branch=master\n\nA validator for arbitrary Python objects. Works with Python 2 and 3.\n\n.. image:: http://thisfred.github.io/val.jpg\n\nInspired by some of the wonderful ideas in schema_ and flatland_, many of which\nI outright stole.\n\nThe goal is to make validation faster than either, while keeping the very\npythonic and minimal style of schema_ , at the expense of more advanced\nfeatures.\n\nCurrent status is: used in production code, but only in one place that I know\nof.\n\nI have not optimized much, but for the kind of schemas I need (specifically: to\nvalidate JSON that has been loaded into python structures as part of a REST\nAPI,) I have some anecdotal evidence that it's around ten times faster than\nboth schema and flatland. (Again, that is mostly because it does way less.)\n\nThe schemas understood by val are very similar to the ones in schema_ , but not\n100% compatible.\n\n\nSyntax\n~~~~~~\n\nElements that can occur in a schema are: \n\n\nLiterals\n--------\n\nSimple literal values will match equal values:\n\n.. code:: python\n\n >>> from val import Schema\n >>> Schema(12).validates(12)\n True\n\n >>> Schema('foo').validates('foo')\n True\n\n\nTypes\n-----\n\nTypes and classes will validate anything that is an instance of the type:\n\n.. code:: python\n\n >>> Schema(int).validates(12)\n True\n\n >>> Schema(str).validates('foo')\n True\n\n >>> Schema(str).validates('fn\u00f8rd')\n True\n\n >>> Schema(list).validates([12, 'foo'])\n True\n\n >>> Schema(dict).validates({'foo': 12})\n True\n\n >>> class Foo(object):\n ... pass\n\n >>> instance = Foo()\n >>> Schema(Foo).validates(instance)\n True\n\n >>> class SubClass(Foo):\n ... pass\n\n >>> subclass_instance = SubClass()\n >>> Schema(Foo).validates(subclass_instance)\n True\n\n >>> schema = Schema(object)\n >>> all(schema.validates(thing) for thing in [\n ... instance, (12, 43, 'strawberries'), {}])\n True\n\n\nLists\n-----\n\nLists will validate list values all of whose elements are validated by at least\none of the elements in the schema (order or number of elements do not matter,\nsee `Ordered()`_):\n\n.. code:: python\n\n >>> Schema([str, int]).validates([12, 'foo', 'bar', 'baz', 42])\n True\n\n >>> schema = Schema(['foo', 'bar', 13])\n >>> schema.validates(['foo'])\n True\n\n >>> schema.validates(['foo', 13])\n True\n\n >>> schema.validates(['bar', 'bar', 13, 'bar'])\n True\n\n\nDictionaries\n------------\n\nDictionaries will validate dictionaries all of whose key value pairs are\nvalidated by at least one of the key value pairs in the schema, and that are\nnot missing any of the keys specified (unless they are specified as\n`Optional()`_):\n\n.. code:: python\n\n >>> schema = Schema({'foo': int, str: int})\n >>> schema.validates({'foo': 83})\n True\n\n >>> schema.validates({'foo': 12, 'bar': 888, 'baz': 299})\n True\n\n >>> schema.validate({'foo': 'bar'})\n Traceback (most recent call last):\n ...\n val.NotValid: 'foo': 'bar' is not of type \n\n >>> schema.validate({'qux': 19})\n Traceback (most recent call last):\n ...\n val.NotValid: missing key: 'foo'\n\n >>> schema.validate({'foo': 21, 12: 'bar'})\n Traceback (most recent call last):\n ...\n val.NotValid: 12: 'bar' not matched\n\n\nCallables\n---------\n\nCallables (that aren't of type ``type``) will validate any value for which the\ncallable returns a truthy value. TypeErrors or ValueErrors in the call will\nresult in a NotValid exception:\n\n.. code:: python\n\n >>> schema = Schema(lambda x: x < 10)\n >>> schema.validates(9)\n True\n\n >>> schema.validate(10)\n Traceback (most recent call last):\n ...\n val.NotValid: 10 invalidated by ''\n\nTo get nicer error messages, use functions rather than lambdas (if the function\nhas a doc string it will be used in the error message, otherwise the name of\nthe funtion will):\n\n.. code:: python\n\n >>> def less_than_ten(n):\n ... \"\"\"Must be less than 10.\"\"\"\n ... return n < 10\n\n >>> schema = Schema(less_than_ten)\n >>> schema.validates(9)\n True\n\n >>> schema.validate(10)\n Traceback (most recent call last):\n ...\n val.NotValid: 10 invalidated by 'Must be less than 10.'\n\n\nConvert()\n---------\n\n``Convert(callable)`` will call the callable on the value being validated,\nand substitute the result of that call for the original value in the\nvalidated structure. TypeErrors or ValueErrors in the call will result in a\nNotValid exception. This or supplying `Default Values`_ are the only ways to\nmodify the data during validation. For that reason it should be used sparingly.\n\nConvert is useful to convert between representations (for instance from\ntimestamps to datetime objects, or uuid string representations to uuid objects,\netc.):\n\n.. code:: python\n\n >>> from val import Convert\n >>> schema = Schema(Convert(int))\n >>> schema.validate('12')\n 12\n\n >>> schema.validate(42.34)\n 42\n\n >>> schema.validate('foo')\n Traceback (most recent call last):\n ...\n val.NotValid: invalid literal for int() with base 10: 'foo'\n\n\nOr()\n----\n\n``Or(element1, element2, ...)`` will validate a value validated by any of the\nelements passed into the Or:\n\n.. code:: python\n\n >>> from val import Or\n >>> schema = Or('foo', int)\n >>> schema.validates('foo')\n True\n\n >>> schema.validates(12)\n True\n\n >>> schema.validate('bar')\n Traceback (most recent call last):\n ...\n val.NotValid: 'bar' is not equal to 'foo', 'bar' is not of type \n\n\nAnd()\n-----\n\n``And(element1, element2, ...)`` will validate a value validated by all of\nthe elements passed into the And:\n\n.. code:: python\n\n >>> from val import And\n >>> schema = And(Convert(int), lambda x: x < 12, lambda x: x >= 3)\n >>> schema.validate('3')\n 3\n\n >>> schema.validate(11.6)\n 11\n\n >>> schema.validate('12')\n Traceback (most recent call last):\n ...\n val.NotValid: 12 invalidated by ''\n\n >>> schema.validate(42.77)\n Traceback (most recent call last):\n ...\n val.NotValid: 42 invalidated by ''\n\n >>> schema.validate('foo')\n Traceback (most recent call last):\n ...\n val.NotValid: invalid literal for int() with base 10: 'foo'\n\n\nOptional()\n----------\n\n``{Optional(simple_literal_key): value}`` will match any key value pair that\nmatches ``simple_literal_key: value`` but the schema will still validate\ndictionary values with no matching key.\n\n\n.. code:: python\n\n >>> from val import Optional\n >>> schema = Schema({Optional('foo'): 12})\n >>> schema.validates({'foo': 12})\n True\n\n >>> schema.validates({})\n True\n\n >>> schema.validate({'foo': 13})\n Traceback (most recent call last):\n ...\n val.NotValid: 'foo': 13 is not equal to 12\n\n >>> schema.validate({'foo': 'bar'})\n Traceback (most recent call last):\n ...\n val.NotValid: 'foo': 'bar' is not equal to 12\n\n\nOrdered()\n---------\n\n``Ordered([element1, element2, element3])`` will validate a list with\n**exactly** 3 elements, each of which must be validated by the corresponding\nelement in the schema. If order and number of elements do not matter, just\nuse `Lists`_:\n\n.. code:: python\n\n >>> from val import Ordered\n >>> schema = Ordered([int, str, int, None])\n >>> schema.validates([12, 'fnord', 42, None])\n True\n\n >>> schema.validate(['fnord', 42, None, 12])\n Traceback (most recent call last):\n ...\n val.NotValid: 'fnord' is not of type \n\n >>> schema.validate([12, 'fnord', 42, None, 12])\n Traceback (most recent call last):\n ...\n val.NotValid: [12, 'fnord', 42, None, 12] does not have exactly 4 values. (Got 5.)\n\n\nParsed Schemas\n--------------\n\nOther parsed schema objects. So this works:\n\n.. code:: python\n\n >>> sub_schema = Schema({'foo': str, str: int})\n >>> schema = Schema(\n ... {'key1': sub_schema,\n ... 'key2': sub_schema,\n ... str: sub_schema})\n\n >>> schema.validates({\n ... 'key1': {'foo': 'bar'},\n ... 'key2': {'foo': 'qux', 'baz': 43},\n ... 'whatever': {'foo': 'doo', 'fsck': 22, 'tsk': 2992}})\n True\n\n\nFAQ\n~~~\n\n\nHow do I validate only some of the keys in a dictionary?\n--------------------------------------------------------\n\nOften when validating input there will be values present that your code doesn't\nact upon, and doesn't care about the presence or absence of. You can make your\nschema similarly indifferent by adding ``str: object`` (assuming the keys in\nthe dictionary are all strings, like they are when your data comes from JSON.\nIf even the type of the keys is variable, you can use ``object: object``.) This\nwill match and validate any keys in the dictionary that you didn't explicitly\nspecify.\n\n.. code:: python\n\n >>> schema = Schema({\n ... 'username': str,\n ... 'password': str,\n ... str: object})\n\n >>> schema.validates({\n ... 'username': 'bob',\n ... 'password': 'hella rancid hazelnuts',\n ... 'shopping_cart': {\n ... 'contents': ['Meet the Parens: A Lisp primer.']}})\n True\n\n >>> schema.validate({\n ... 'username': 'connie',\n ... 'goldfish': 12})\n Traceback (most recent call last):\n ...\n val.NotValid: missing key: 'password'\n\n\nAdvanced Topics\n~~~~~~~~~~~~~~~\n\n\nDefault Values\n--------------\n\nOne can supply a default value to any (subclass of) Schema, which will be used\nin place of the validated value if that evaluates to `False`.\n\n.. code:: python\n\n >>> schema = Schema(str, default='default value')\n >>> schema.validate('supplied value')\n 'supplied value'\n\n >>> schema.validate('')\n 'default value'\n\nNote that the original value must still be valid for the schema, so this will\nnot work:\n\n.. code:: python\n\n >>> schema.validates(None)\n False\n\nBut this will:\n\n.. code:: python\n\n >>> schema = Or(str, None, default='default value')\n >>> schema.validate(None)\n 'default value'\n\nDefault values will also work for dictionary keys that are specified as\n`Optional`:\n\n.. code:: python\n\n >>> schema = Schema(\n ... {'foo': str,\n ... Optional('bar'): Or(int, None, default=23)})\n\n >>> schema.validate({'foo': 'yes'}) == {'bar': 23, 'foo': 'yes'}\n True\n\n\nAdditional Validators\n---------------------\n\nSometimes it is useful to do validation that depends on multiple parts of the\ndata at once. For this purpose, Schemas can be initialized with additional\nvalidators.\n\n\n.. code:: python\n\n >>> def maximum_total(value):\n ... \"\"\"The total sum must not exceed 500.\"\"\"\n ... return sum(value.values()) <= 500\n\n >>> schema = Schema({str: int}, additional_validators=(maximum_total,))\n >>> schema.validates({'foo': 12, 'bar': 400})\n True\n\n >>> schema.validate({'foo': 250, 'bar': 251})\n Traceback (most recent call last):\n ...\n val.NotValid: ... invalidated by 'The total sum must not exceed 500.'\n\n\nSerializing Schemas\n-------------------\n\nWhen your application receives JSON from clients, it can be useful to define\nexplicit schemas that those clients have to abide by. Pointing to source code \nisn't an especially great way to communicate to other developers what is or\nisn't considered valid JSON by your application, especially if they aren't \ndeveloping in Python. For this purpose, teleport_, a lightweight JSON format to\ndescribe schemas, is better suited.\n\nA subset of valid val schemas is serializable/exportable to teleport_. \nNote that things like default values and additional validators will be lost\nwhen serializing to teleport, because it has no way to express them.\n\nCombining doctests with this serialization provides a way to specify what your\napplication considers valid, and verify in your tests that you didn't\nunintentionally break clients' assumptions.\n\nIf your code contains the following schema for todo items:\n\n.. code:: python\n\n >>> todo = Schema({\n ... \"task\": str,\n ... Optional(\"priority\"): int,\n ... Optional(\"status\"): str})\n\nThen in your API documentation you could use the ``document()`` helper and\nhave doctests verify the output, as is the case here.\n\n.. code:: python\n\n >>> from val import tp\n >>> print(tp.document(todo))\n {\n \"Struct\": {\n \"optional\": {\n \"priority\": \"Integer\",\n \"status\": \"String\"\n },\n \"required\": {\n \"task\": \"String\"\n }\n }\n }\n\n\n.. _schema: https://github.com/halst/schema\n.. _flatland: http://discorporate.us/projects/flatland/\n.. _teleport: http://www.teleport-json.org/", "description_content_type": null, "docs_url": null, "download_url": null, "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://github.com/thisfred/val", "keywords": "validation validators", "license": "BSD", "maintainer": null, "maintainer_email": null, "name": "val", "package_url": "https://pypi.org/project/val/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/val/", "project_urls": { "Homepage": "http://github.com/thisfred/val" }, "release_url": "https://pypi.org/project/val/0.6/", "requires_dist": null, "requires_python": null, "summary": "Python object validator", "version": "0.6" }, "last_serial": 1425994, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "ec145d023763eda8e9e69e50be6fd17c", "sha256": "20f233521448eb5ab316b5a66e94b1b29aabf7fe24019692a0d70833c0851595" }, "downloads": -1, "filename": "val-0.1.tar.gz", "has_sig": false, "md5_digest": "ec145d023763eda8e9e69e50be6fd17c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4077, "upload_time": "2013-08-16T00:35:44", "url": "https://files.pythonhosted.org/packages/a7/c5/d4db5f569214bc220f249c6415daf0098879728c9236eb7405a33d807522/val-0.1.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "b9abe7c77a598591a7cddd767e51ccc3", "sha256": "520d3a91aac6fe2bca60de6743df5579c735f38e3e4351a490844f73d5ee0924" }, "downloads": -1, "filename": "val-0.1.1.tar.gz", "has_sig": false, "md5_digest": "b9abe7c77a598591a7cddd767e51ccc3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4494, "upload_time": "2013-08-16T00:43:08", "url": "https://files.pythonhosted.org/packages/42/8e/e631079d32bb07041d25d3ad40921252aefbbc67a1b80529989da5a1d863/val-0.1.1.tar.gz" }, { "comment_text": "", "digests": { "md5": "4e19a004d222a50dc6cc38c310b5e119", "sha256": "e1a7860e2aeb8d1f44d2f47d5b41e8d01c264a4c9693bdd16257b85a2729ebed" }, "downloads": -1, "filename": "val-0.2.0.tar.gz", "has_sig": false, "md5_digest": "4e19a004d222a50dc6cc38c310b5e119", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4887, "upload_time": "2013-08-16T22:48:24", "url": "https://files.pythonhosted.org/packages/68/39/80019b5e8d44d5df54bb394b47ce96a4b04cdfa8f1fd59013c70f7d49156/val-0.2.0.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "db754f5196e27f80100d89d3cd2b3b4d", "sha256": "2ac2649887e3c876c1eedc720e39db6393873787f6d851031d25c5698aad050e" }, "downloads": -1, "filename": "val-0.2.1.tar.gz", "has_sig": false, "md5_digest": "db754f5196e27f80100d89d3cd2b3b4d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4947, "upload_time": "2013-08-21T01:10:52", "url": "https://files.pythonhosted.org/packages/a9/f7/bd5d0b5622539f321eb1b460ffbc46431cee29be978a83ed86466d96dd3f/val-0.2.1.tar.gz" } ], "0.3.0": [ { "comment_text": "", "digests": { "md5": "e377599172f8558f657872303ef1fe64", "sha256": "65d8ecc98d24d38eac92dc79d44a166950649d6a06f92a5bc6dfc79a17ba7901" }, "downloads": -1, "filename": "val-0.3.0.tar.gz", "has_sig": false, "md5_digest": "e377599172f8558f657872303ef1fe64", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5302, "upload_time": "2013-10-09T20:38:06", "url": "https://files.pythonhosted.org/packages/f3/47/3863adb1e4298867cda3d63af18ef82dd6c3d90be602055a8590b3913dd4/val-0.3.0.tar.gz" } ], "0.3.1": [ { "comment_text": "", "digests": { "md5": "e9ba4affe5fda97fbbffa902a13a1910", "sha256": "899c5883b059cc897d26878d293dd60cff8161631d0e6d09f9e5a7f6e3597869" }, "downloads": -1, "filename": "val-0.3.1.tar.gz", "has_sig": false, "md5_digest": "e9ba4affe5fda97fbbffa902a13a1910", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5358, "upload_time": "2013-10-09T22:16:28", "url": "https://files.pythonhosted.org/packages/9d/3f/48662c4ac9e0ba3a23defc4b6c2bd2aa373b5e62ca86c224fa963812f654/val-0.3.1.tar.gz" } ], "0.3.2": [ { "comment_text": "", "digests": { "md5": "2a140314db49c1a232f5a9f4de7a1a17", "sha256": "291c88b15ed31a5eea93de787a39d45af531ee80541e9d49352a2783cf056fec" }, "downloads": -1, "filename": "val-0.3.2.tar.gz", "has_sig": false, "md5_digest": "2a140314db49c1a232f5a9f4de7a1a17", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5370, "upload_time": "2013-10-31T19:16:42", "url": "https://files.pythonhosted.org/packages/8b/65/7f3adcd27c0c64e3c03f9c6f21ca4c99a2e7c2a6d5c7b92d43f128a40008/val-0.3.2.tar.gz" } ], "0.3.3": [ { "comment_text": "", "digests": { "md5": "199666a861de290897137826a7e70f8c", "sha256": "d63c7150785d9909cf7a0e7166a0f42f52f3a677230a9f9d36a735d90dfcd4a4" }, "downloads": -1, "filename": "val-0.3.3.tar.gz", "has_sig": false, "md5_digest": "199666a861de290897137826a7e70f8c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5313, "upload_time": "2013-10-31T21:06:02", "url": "https://files.pythonhosted.org/packages/17/92/63f252811641dbf2302dd28f45f896b42764318e8e09034b3ff555e6ec23/val-0.3.3.tar.gz" } ], "0.4.0": [ { "comment_text": "", "digests": { "md5": "17f70d1b3f93f420380ffeca07f7f915", "sha256": "5ff7ad9b156d76e79c04968560f7811faff61bfed4d9f200ca2d0f62f0c6c16b" }, "downloads": -1, "filename": "val-0.4.0.tar.gz", "has_sig": false, "md5_digest": "17f70d1b3f93f420380ffeca07f7f915", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5432, "upload_time": "2014-02-12T00:40:13", "url": "https://files.pythonhosted.org/packages/7d/28/6f302c285850ff201b5e02e45f833b958ebd919681a05330368f26d85bcc/val-0.4.0.tar.gz" } ], "0.4.1": [ { "comment_text": "", "digests": { "md5": "50ddb3bc1c98258df4c816cbf864471e", "sha256": "4f9d818562e4bf3959808a97bbace231a6979029e7c321f7e75632b37c481108" }, "downloads": -1, "filename": "val-0.4.1.tar.gz", "has_sig": false, "md5_digest": "50ddb3bc1c98258df4c816cbf864471e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7562, "upload_time": "2014-04-08T16:33:11", "url": "https://files.pythonhosted.org/packages/a3/ac/a4e135a794f2e8acc458d3b40545d86bfdc550f72a7ca3c94f882bb99a47/val-0.4.1.tar.gz" } ], "0.5.0": [ { "comment_text": "", "digests": { "md5": "98599f6dbd2cee28852835cb80ac0a9f", "sha256": "78c15ea73657d0d937aec7943f13331138f2e10039a26700c0c443105c7d7660" }, "downloads": -1, "filename": "val-0.5.0.tar.gz", "has_sig": false, "md5_digest": "98599f6dbd2cee28852835cb80ac0a9f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6655, "upload_time": "2014-04-23T04:54:53", "url": "https://files.pythonhosted.org/packages/c4/ef/ca04b9f7266eba74bc6c8d2618aaa7a63aadf1e2f09adfa7a1fed5e7ba16/val-0.5.0.tar.gz" } ], "0.5.1": [ { "comment_text": "", "digests": { "md5": "a198be04f7b12488c48bb432d90378f3", "sha256": "abf46adf6763dbcf677992657ace60b18b421e08746ca7517d41947d300c3e89" }, "downloads": -1, "filename": "val-0.5.1.tar.gz", "has_sig": false, "md5_digest": "a198be04f7b12488c48bb432d90378f3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7297, "upload_time": "2014-05-11T22:15:29", "url": "https://files.pythonhosted.org/packages/63/37/368ca302f1d9bb154a7274b121fb6b4d7a02a68fa774abd9410b6838221c/val-0.5.1.tar.gz" } ], "0.5.2": [ { "comment_text": "", "digests": { "md5": "95e38b229657c351b2a156aa421cc4ea", "sha256": "2fd1d3171e11ce5722869339dab48d3f549c043b6320144af9bb5326e7dd282d" }, "downloads": -1, "filename": "val-0.5.2.tar.gz", "has_sig": false, "md5_digest": "95e38b229657c351b2a156aa421cc4ea", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7586, "upload_time": "2014-05-11T23:20:49", "url": "https://files.pythonhosted.org/packages/fb/ad/cbdb13c84f7d22c9749f66ba8e04dd8d414fef18091e6672fcbf605d8fba/val-0.5.2.tar.gz" } ], "0.5.3": [ { "comment_text": "", "digests": { "md5": "07697fb41ad101fcdb061a679e98df07", "sha256": "6a882340a2e02544546d72926a52b2c434fa4181134d2b17cbe6dd5fb3a9d78b" }, "downloads": -1, "filename": "val-0.5.3.tar.gz", "has_sig": false, "md5_digest": "07697fb41ad101fcdb061a679e98df07", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7554, "upload_time": "2015-02-08T03:39:08", "url": "https://files.pythonhosted.org/packages/af/ec/e0a1c5ab126d650b8c2a810a218470527cf6cdd2bcc3a2a0a0f0320c4e26/val-0.5.3.tar.gz" } ], "0.6": [ { "comment_text": "", "digests": { "md5": "bd81f8fed4f0955ababf091ebd3c7fa0", "sha256": "ac1cbbd956d1215549e1ad81b91750020acb759ece97a190aea88f1ac260cc49" }, "downloads": -1, "filename": "val-0.6-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "bd81f8fed4f0955ababf091ebd3c7fa0", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 16734, "upload_time": "2015-02-16T21:13:49", "url": "https://files.pythonhosted.org/packages/0f/9a/3342c7c05f879a6598f8bf7eee53a8d78128064667f84d636fa904f0a1d1/val-0.6-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "27515dd319949b48f34ea4f453dfa850", "sha256": "6a04b3936e128f3b75149058879434bf60e9b8de7e4ef09950cdcca9870fdb18" }, "downloads": -1, "filename": "val-0.6.tar.gz", "has_sig": false, "md5_digest": "27515dd319949b48f34ea4f453dfa850", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12125, "upload_time": "2015-02-16T21:13:51", "url": "https://files.pythonhosted.org/packages/85/db/9f404cb0b2ebbfbef3fd5fd0cb1cb7c57f483491661f3760e41b3ca49253/val-0.6.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "bd81f8fed4f0955ababf091ebd3c7fa0", "sha256": "ac1cbbd956d1215549e1ad81b91750020acb759ece97a190aea88f1ac260cc49" }, "downloads": -1, "filename": "val-0.6-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "bd81f8fed4f0955ababf091ebd3c7fa0", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 16734, "upload_time": "2015-02-16T21:13:49", "url": "https://files.pythonhosted.org/packages/0f/9a/3342c7c05f879a6598f8bf7eee53a8d78128064667f84d636fa904f0a1d1/val-0.6-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "27515dd319949b48f34ea4f453dfa850", "sha256": "6a04b3936e128f3b75149058879434bf60e9b8de7e4ef09950cdcca9870fdb18" }, "downloads": -1, "filename": "val-0.6.tar.gz", "has_sig": false, "md5_digest": "27515dd319949b48f34ea4f453dfa850", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12125, "upload_time": "2015-02-16T21:13:51", "url": "https://files.pythonhosted.org/packages/85/db/9f404cb0b2ebbfbef3fd5fd0cb1cb7c57f483491661f3760e41b3ca49253/val-0.6.tar.gz" } ] }