Welcome to canonical_args’s documentation!¶
canonical_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:
{
"args": [
{
"name": "argument1",
"type": int,
"values": "range(0, 15)"
},
{
"name": "argument2",
"type": "one([int, float, str])",
"values": {
"int": ">0",
"float": ">0",
"str": ["A", "B", "C"]
}
}
],
"kwargs": {
"loss_function": {
"type": str,
"values": ["quadratic", "0-1"]
}
}
}
We can associate this spec with a method, either by registering it (if we do not control the method source):
from canonical_args import register_spec
# associates the spec to the method
register_spec(somemethod, spec)
# method instance method returns the registered spec
print somemethod.get_spec()
or by decorating a method, if we do control it (let’s say for a dynamically imported method handler sub-method).
from canonical_args import argspec
@arg_spec(spec, register=True)
def ourmethod(argument1, argument2, loss_function="quadratic"):
pass
print ourmethod.get_spec()
This 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:
from canonical_args import checkspec
import pymongo
conn = pymongo.MongoClient("localhost", 27017)
def handle(message_type, *args, **kwargs):
spec = conn.somedatabase.arg_specs.find_one(
{"message_type": message_type})
subhandler = conn.somedatabase.handlers.find_one(
{"message_type": message_type})
# use canonical_args to check the unknown arguments
# against the retrieved spec. will raise AssertionError
# if fails.
check_args(spec, *args, **kwargs)
# if no errors raised, fire the retrieved handler method
return subhandler(*args, **kwargs)
def get_handler_spec(message_type):
"""
get the arg spec without executing the function. can
be used at front end (eg. HTML) for generating an
appropriate form for method calls.
"""
return conn.somedatabase.handlers.find_one(
{"message_type": message_type})
The 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.