{ "info": { "author": "William Edwards", "author_email": "willvarfar@gmail.com", "bugtrack_url": null, "classifiers": [], "description": "Obiwan.py\n---------\n\nwhat is obiwan?\n===============\n\n[blogpost]\nhttp://williamedwardscoder.tumblr.com/post/33185451698/obiwan-typescript-for-python\n\nObiwan is a Python type-checker. You place descriptive type constraints\nin your function declarations and obiwan can check them for you at\nruntime.\n\nA function can look like:\n\n::\n\n def example(a: int, b: float) -> number:\n return a/b\n\nObiwan is also exemplary for describing and checking external data e.g.\nJSON and msgpack, and has a json parser that does this.\n\nObiwan machinary can also be used for checking contracts, constraints\nand expectations in normal code rather as an assert.\n\nMy ambition is that this Obiwan syntax is widely adopted and eventually\nPython static type checkers support it and IDEs can do auto-complete ala\nTypescript.\n\nTo enable obiwan, you just call it:\n\n::\n\n from obiwan import *; install_obiwan_runtime_check()\n\n(Obiwan attaches to the Python VM using ``settrace()``. You need to call\nthe installer in each thread you want checked)\n\nyou are now running obiwan! Runtime execution will be slower, but\nannotated functions will be checked for parameter correctness!\n\nAll strings in your function annotations are ignored; you can place\ndocumentation in annotations without impacting obiwan.\n\nmaturity\n========\n\nThe dictionary and list checking code is based upon a tried-and-tested\nJSON validator.\n\nThe integration with Python 3 function annotations is new and the\n``function`` and ``duck`` type checking is new. Improvements and patches\nwelcome!\n\nvalidating dictionaries and lists\n=================================\n\nYou can also describe dictionary parameters and what their expected\nattributes are:\n\n::\n\n def example(obj: {\"a\":int, \"b\": float}) -> {\"ret\": number}:\n return {\"ret\": a/b}\n \n\nChecking can support the checking of *optional* and *noneable*\nattributes:\n\n::\n\n def example(obj: {\"a\":int, optional(\"b\"): float}):\n ...\n \n\nChecks can contain dictionary and other attributes too:\n\n::\n\n def example(person: {\"name\":str, \"phone\": {\"type\":str, \"number\":str}}):\n ...\n \n\nDictionaries can be checked for key and value *types*, as well as by key\nname. E.g. to ensure that a function returns only dictionaries mapping\nstrings to integers:\n\n::\n\n def example() -> {str: int}:\n ...\n \n\nYou can specify alternative constraint types using sets:\n\n::\n\n def example(x: {int,float}):\n ...\n \n\nIn fact, *number* type is just a set of int and float. And *noneable* is\njust a way of saying ``{...,None}``\n\nLists mean that the attribute must be an array where each element\nmatches the constraint e.g.:\n\n::\n\n def example(numbers: [int]):\n ...\n \n\nAnd sets which must be all of one type can be specified with a set\ncontaining a single element:\n\n::\n\n def example(x: {str}):\n ...\n \n\nTuples must map to lists or tuples (no destructive iterators!) with the\nappropriate types in each slot:\n\n::\n\n def nearest_point_on_line(line:((int,int),(int,int)),pt:(int,int)) -> (int,int):\n\nWithin tuples you can use ``any`` to indicate that a type needs not be\nchecked, and you can use ellipsis as the last element in the\ntype-defintion tuple to indicate that additional parameters are allowed:\n\n::\n\n def decode_data(data: str) -> (str,any,int,...):\n \n\nIt aids readability to use variables to hold definitions e.g.:\n\n::\n\n Point = (int,int)\n def nearest_point_on_line(line:(Point,Point),pt:Point) -> Point:\n\nand:\n\n::\n\n api_add_user = {\n \"name\": str,\n \"admin\": bool,\n }\n def add_user(user: api_add_user) -> int:\n ...\n \n\nDict templates can have a special *options* key which is a list of\noptions. Options include *strict* and *subtype*:\n\n::\n\n api_base = {\n \"user_id\": int,\n }\n api_set_name = {\n options: [strict, subtype(api_base)],\n \"name\": str,\n }\n\n*Strict* will complain if the dictionary being validated contains any\nkeys *not* in the template dictionary, and *subtype* will combine\nparameters specified in other dictionary templates with this template.\nIn this example, dictionaries validated against ``api_set_name`` must\nhave both user\\_id and name specified, and no other keys.\n\nYou can specify multiple parent templates in the subtype arguments, and\nhave multiple subtype options, and nest template inheritence arbitrarily\ndeep.\n\nvalidating JSON\n===============\n\nUtility functions to load and dump JSON are provided. These support a\nnew *template* parameter and validate the input/output matches the\nconstraint e.g.:\n\n::\n\n json.loads(tainted, template=[api_add_user])\n\n json.loads(tainted, template={\"type\": str, \"data\": { ....\n\nif it quacks like a duck...\n===========================\n\nIn Python 3 everything is an object, even ``int`` and ``None``. So you\ncan't generically say that an argument or attribute must be an *object*.\nYou have to say what its attributes should be. This follows the same\nstyle as validating dictionaries, but uses the *duck* type and keyword\narguments to define:\n\n::\n\n def example(a: duck(name=str,get_name=function)):\n ...\n \n\nThis means that ``a`` must be something with a name attribute of type\nstring, and a function attribute called get\\_name.\n\nYou can of course use classes to:\n\n::\n\n class Person:\n def get_name(self):\n ...\n\n def example(person: Person):\n ...\n \n\n*duck* instances can *extend* other duck instances using positional\nparameters:\n\n::\n\n api_base = duck(user_id=int)\n api_change_name = duck(api_base, name=str)\n def change_name(user: api_change_name):\n ...\n \n\nvalidating callbacks\n====================\n\nYou can say that a parameter is callable using function:\n\n::\n\n def example(callback: function):\n ...\n \n\nIf you want, you can describe the parameters that the function should\ntake:\n\n::\n\n def example(callback: function(int,str)):\n ...\n \n\nHowever, all the functions passed to example8 must now be properly\nannotated with a matching annotation.\n\nThe special type any can be used if you do not want to check the type:\n\n::\n\n def example(callback: function(int,any,number)):\n ...\n \n\nYou can also specify that a function should support further arguments\nusing ellipsis:\n\n::\n\n def example(callback: function(int,any,...)):\n ...\n \n\nThis will ensure that all callbacks have at least two parameters, the\nfirst being an int.\n\nusing lambdas as checkers\n=========================\n\nYou can use lambdas as checkers; they should return a boolean condition\ne.g.\n\n::\n\n template = {\n 'month': lambda x: x in [\"jan\",\"feb\",\"mar\",...],\n ...\n }\n\nwriting your own custom checkers\n================================\n\nYou can provide your own complex custom constraint checkers by\nsubclassing the ObiwanCheck class; look at obiwan.StringCheck for\ninspiration.", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/williame/obiwan", "keywords": null, "license": "UNKNOWN", "maintainer": null, "maintainer_email": null, "name": "obiwan", "package_url": "https://pypi.org/project/obiwan/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/obiwan/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/williame/obiwan" }, "release_url": "https://pypi.org/project/obiwan/1.0.8/", "requires_dist": null, "requires_python": null, "summary": "A runtime type checker (contract system) and JSON validator", "version": "1.0.8" }, "last_serial": 1247581, "releases": { "1.0": [ { "comment_text": "", "digests": { "md5": "ccaeeed30b9db616cfaf0e0c4492b523", "sha256": "8d1ce7d67ad17fd7564971d0d13707a0af602211c0960aca20901956a2a8f946" }, "downloads": -1, "filename": "obiwan-1.0.tar.gz", "has_sig": false, "md5_digest": "ccaeeed30b9db616cfaf0e0c4492b523", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6584, "upload_time": "2014-02-17T12:09:57", "url": "https://files.pythonhosted.org/packages/97/6a/aaaff109e37f06f8f2a26dac711ce9fdea68ccf9aafa4dbbf8c24b9737e9/obiwan-1.0.tar.gz" } ], "1.0.1": [ { "comment_text": "", "digests": { "md5": "61eeada70447136990dc524bfba06dba", "sha256": "64aa9d80d09ecff8aaa7eb3140c9e1e9048c4c6d8866323c1388f86021f91df6" }, "downloads": -1, "filename": "obiwan-1.0.1.tar.gz", "has_sig": false, "md5_digest": "61eeada70447136990dc524bfba06dba", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6831, "upload_time": "2014-02-17T13:42:21", "url": "https://files.pythonhosted.org/packages/5f/21/708ecb658a801c2a26789685862ab1af66377f04b3215c1059d41c7fcccd/obiwan-1.0.1.tar.gz" } ], "1.0.2": [ { "comment_text": "", "digests": { "md5": "b12499069a8dee069ce1e67777bec11b", "sha256": "4c655d3ba9522e03c8641a0fac67104161fc0b2ed9ba1be92a99aa4cb0586855" }, "downloads": -1, "filename": "obiwan-1.0.2.tar.gz", "has_sig": false, "md5_digest": "b12499069a8dee069ce1e67777bec11b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6911, "upload_time": "2014-02-17T13:55:59", "url": "https://files.pythonhosted.org/packages/4c/25/b0a643f168f6b861ec0d446c80a818e64d7371237ff6411f1c42b6fdafca/obiwan-1.0.2.tar.gz" } ], "1.0.3": [ { "comment_text": "", "digests": { "md5": "ab2c8cbceb0b9f3c3d94195c71f6a168", "sha256": "8047d90f5ed3d71961b2b39c3da40524daacf0731161d977b62127e9aa8c312e" }, "downloads": -1, "filename": "obiwan-1.0.3.tar.gz", "has_sig": false, "md5_digest": "ab2c8cbceb0b9f3c3d94195c71f6a168", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6998, "upload_time": "2014-02-26T10:42:53", "url": "https://files.pythonhosted.org/packages/e7/97/cb3170d7301f85fcb7eeb1888c8eff33150a5af8404755d53e5635e266da/obiwan-1.0.3.tar.gz" } ], "1.0.4": [ { "comment_text": "", "digests": { "md5": "559b8eddc7ceffdf97f1465b1ef9c6ca", "sha256": "d0ec42ac9f1126f50caa062334dc22074eb6a734ea5a58dd7ff03407fa679e31" }, "downloads": -1, "filename": "obiwan-1.0.4.tar.gz", "has_sig": false, "md5_digest": "559b8eddc7ceffdf97f1465b1ef9c6ca", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7331, "upload_time": "2014-03-10T13:38:22", "url": "https://files.pythonhosted.org/packages/cf/43/a0daeb1a5019c022c98931ee4e315cdfb3403a8bb97f99db604920187f7b/obiwan-1.0.4.tar.gz" } ], "1.0.5": [ { "comment_text": "", "digests": { "md5": "64d5d007493c8f5d24275d56b1bbc7e4", "sha256": "d7222d1b919a8d2449456b6d8806422be771f38a3bca8831a6a2be5994b7295f" }, "downloads": -1, "filename": "obiwan-1.0.5.tar.gz", "has_sig": false, "md5_digest": "64d5d007493c8f5d24275d56b1bbc7e4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7453, "upload_time": "2014-08-14T10:49:00", "url": "https://files.pythonhosted.org/packages/b1/b6/7cd9c927cdc69e3d658fdd434a84cea22962d16288157bde2618f8dc6869/obiwan-1.0.5.tar.gz" } ], "1.0.6": [ { "comment_text": "", "digests": { "md5": "f167a1e3ec45f87c0011c095e8a99033", "sha256": "2b14cf72cfcbd708a093bef8c97e114a119a597736f63d11783160653f028d99" }, "downloads": -1, "filename": "obiwan-1.0.6.tar.gz", "has_sig": false, "md5_digest": "f167a1e3ec45f87c0011c095e8a99033", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8683, "upload_time": "2014-08-20T08:09:02", "url": "https://files.pythonhosted.org/packages/df/b6/a7365adde14fea7f23cac75b04ca51bd30010e77f7d201139fc3caa68aca/obiwan-1.0.6.tar.gz" } ], "1.0.7": [ { "comment_text": "", "digests": { "md5": "afac39dbe23167dc347476314f5a41c1", "sha256": "6aca77dea537b752c5778723e4402a35645e53fc8e2327265ef1a4a02ca740b5" }, "downloads": -1, "filename": "obiwan-1.0.7.tar.gz", "has_sig": false, "md5_digest": "afac39dbe23167dc347476314f5a41c1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8736, "upload_time": "2014-08-20T08:16:46", "url": "https://files.pythonhosted.org/packages/0e/65/75d5455c7ad344059d1f6d8835a31969a18c77877dec110cd1d4853dbe61/obiwan-1.0.7.tar.gz" } ], "1.0.8": [ { "comment_text": "", "digests": { "md5": "613a05b7d1276011ed4a7c924f4419e9", "sha256": "0b29065ec521627dfe8a7dcc591ee013fc8cb4dbbdd5294704ffdec808f209ab" }, "downloads": -1, "filename": "obiwan-1.0.8.tar.gz", "has_sig": false, "md5_digest": "613a05b7d1276011ed4a7c924f4419e9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8962, "upload_time": "2014-10-04T08:08:43", "url": "https://files.pythonhosted.org/packages/f9/fa/ff0af7304b7f82ac97b119612490e60520efc8dda85da7c800990fe01198/obiwan-1.0.8.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "613a05b7d1276011ed4a7c924f4419e9", "sha256": "0b29065ec521627dfe8a7dcc591ee013fc8cb4dbbdd5294704ffdec808f209ab" }, "downloads": -1, "filename": "obiwan-1.0.8.tar.gz", "has_sig": false, "md5_digest": "613a05b7d1276011ed4a7c924f4419e9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8962, "upload_time": "2014-10-04T08:08:43", "url": "https://files.pythonhosted.org/packages/f9/fa/ff0af7304b7f82ac97b119612490e60520efc8dda85da7c800990fe01198/obiwan-1.0.8.tar.gz" } ] }