{ "info": { "author": "Shonte Amato-Grill", "author_email": "shonte.amatogrill@gmail.com", "bugtrack_url": null, "classifiers": [ "Intended Audience :: Developers", "Programming Language :: Python :: 2.7", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "canonical\\_args\n===============\n\n.. image:: https://travis-ci.org/shonteag/canonical_args.svg?branch=master\n :target: https://travis-ci.org/shonteag/canonical_args\n\ncanonical_args is a package designed to provide some certainty around abstract method calls. Consider, for instance, that we need to call one of many possible methods for a package we do not control. Each of these methods has the same arguments, but the potential values change depending on the function. We can write ``canonical_args`` arg specs for each of these methods, allowing us some clarity as to what each argument needs to be (types, values, etc.) when we execute dynamically: ::\n\n\t{\n\t\t\"args\": [\n\t\t\t{\n\t\t\t\t\"name\": \"argument1\",\n\t\t\t\t\"type\": int,\n\t\t\t\t\"values\": \"range(0, 15)\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"name\": \"argument2\",\n\t\t\t\t\"type\": \"one([int, float, str])\",\n\t\t\t\t\"values\": {\n\t\t\t\t\t\"int\": \">0\",\n\t\t\t\t\t\"float\": \">0\",\n\t\t\t\t\t\"str\": [\"A\", \"B\", \"C\"]\n\t\t\t\t}\n\t\t\t}\n\t\t],\n\t\t\"kwargs\": {\n\t\t\t\"loss_function\": {\n\t\t\t\t\"type\": str,\n\t\t\t\t\"values\": [\"quadratic\", \"0-1\"]\n\t\t\t}\n\t\t}\n\t}\n\nWe can associate this spec with a method, either by registering it (if we do not control the method source): ::\n\n\tfrom canonical_args import register_spec\n\n\t# associates the spec to the method\n\tregister_spec(somemethod, spec)\n\n\t# method instance method returns the registered spec\n\tprint somemethod.get_spec()\n\nor by decorating a method, if we do control it (let's say for a dynamically imported method handler sub-method). ::\n\n\tfrom canonical_args import argspec\n\n\t@arg_spec(spec, register=True)\n\tdef ourmethod(argument1, argument2, loss_function=\"quadratic\"):\n\t\tpass\n\n\tprint ourmethod.get_spec()\n\nThis could potentially be of great use to dynamically generate frontend code with type and value-checking code. The specs themselves could be stored in a file or database, allowing for fully dynamic method calls: ::\n\n\tfrom canonical_args import check_args\n\timport pymongo\n\n\tconn = pymongo.MongoClient(\"localhost\", 27017)\n\n\tdef handle(message_type, *args, **kwargs):\n\t\tspec = conn.somedatabase.arg_specs.find_one(\n\t\t\t{\"message_type\": message_type})\n\t\tsubhandler = conn.somedatabase.handlers.find_one(\n\t\t\t{\"message_type\": message_type})\n\n\t\t# use canonical_args to check the unknown arguments\n\t\t# against the retrieved spec. will raise AssertionError\n\t\t# if fails.\n\t\tcheck_args(spec, *args, **kwargs)\n\n\t\t# if no errors raised, fire the retrieved handler method\n\t\treturn subhandler(*args, **kwargs)\n\n\tdef get_handler_spec(message_type):\n\t\t\"\"\"\n\t\tget the arg spec without executing the function. can\n\t\tbe used at front end (eg. HTML) for generating an\n\t\tappropriate form for method calls.\n\t\t\"\"\"\n\t\treturn conn.somedatabase.handlers.find_one(\n\t\t\t{\"message_type\": message_type})\n\nThe code above **does not** register the spec directly to the ``subhandler`` method, as it may not always be desirable to do so. The choice is yours.\n\nFull Documentation\n------------------\nhttps://shonteag.github.io/canonical_args/\n\nFuture Work\n-----------\nI aim to provide frontend code generation directly within the module, probably in a subpackage. At least to handle HTML ``