Utility Classes :: Function
Function() is used to make assertions about functions and methods that get passed in and out of Python code.
Positional Parameters
Your garden variety assertions are going be something like, "does the function take X number of parameters of types Y and Z?" As a contrived example, say you wanted to make sure that a passed-in function takes three integers as arguments:
@accepts(Function(int, int, int))
Note that even if the passed-in function is defined like
def foo(a, b, c, d=6):
...
that is, three integers are valid -- but so are four -- the Function() will reject the callable.
The callable signature must match maximally.
Keyword Parameters
If you'll be passing certain arguments by keyword, the Function() instance can be used to ensure that the function has parameters with certain names.
Function(int, int, c=int)
This will check to make sure that the function takes three integers and that one parameter is named c.
Excess Parameters
Let's say you want to assert that a function has either a *vargs or **kwargs parameter defined.
Now, even though you use positional arguments to Function() to cover positional parameters and keyword arguments to make assertions about keyword parameters, you have to do something different for these excess parameters.
To verify that a function has *vargs or **kwargs parameters, use the Function class's star() and double_star() methods, respectively.
A function like
def foo(a, b, *vargs, **kwargs):
...
can be covered by
@accepts(Function(int, int).star(int).double_star(int))
Note that star() and double_star() return the invocant instance so that they can be used "inside" the decorator (as illustrated above).
Return Types
Using a mechanism similar to that used to assert the presence of excess parameters, an invocant-returning method can be used to verify that a function returns objects of the proper type:
@accepts(Function(int, int).returns(int, int))
will ensure that the passed-in function takes two integers and returns a two integers.
Note that if you don't specify a return type, the Function instance won't just guess.
Non-typechecked Functions
Since Function objects work by analysis the type information from typecheck's accepts and returns decorators, the question naturally arises: what to do about non-typechecked callables?
By default, passing in a callable with insufficient type information (no type information, or e.g. @returns wasn't applied and the Function expected that it was) will cause the Function instance to reject the callable.
If this behaviour is undesirable, you can have non-typechecked functions automatically approved in one of two ways:
-
It's possible to make all
Functioninstances non-strict (i.e., they allow non-typechecked functions) by settingFunction.is_stricttoFalse. This applies to allFunctioninstances created after this assignment. -
Functioninstances can also be made non-strict on an individual basis by passingFalseto the invocant-returningFunction.strict()instance method. Since this method returns the invocant (likereturns()andstar()), it can be used "inside" the decorator.
Details
-
The
Function()constructor accepts any number of positional and keyword arguments. -
If only positional arguments are passed to the constructor, no assertions will be made about the presence of certain parameter names in checked functions.
Likewise, if only keyword arguments are passed to the constructor, no assertions will be made about positional parameters; that is, the
Functioninstance will only look for the specified parameter names, nothing more. -
The current implementation (as of
typecheck0.4.0) does not take subtypes into account when checking the target function. That is, thisFunctioninstanceFunction(int, IsOneOf(IsCallable(), IsIterable()))
will reject this function because
IsIterable() != IsOneOf(...).@accepts(int, IsIterable()) def foo(a, b): ...Where IsOneOf, IsCallable and IsIterable are all other utility classes.
-
Instances of
Functionwill compare (==) and hash equally if they approve the same callables. Subtypes are not considered. -
If the checked object is not a callable, a
_TC_TypeErrorinternal exception will be raised. Thewrongattribute will be the type of the rejected object, and therightattribute will be the string"a callable". -
When checking a callable's return type, if the return type does not match that specified to the
Functioninstance, an internal_TC_FunctionErrorwill be raised. Thechecking_whatattribute will be the string"return type"and theinnerattribute will be an instance of_TC_TypeError. -
When checking a callable's return type, if typechecking information is not available for the return type and the
Functioninstance is in strict mode, a_TC_TypeErrorexception will be raised. Thewrongattribute will be the type of the offending callable and therightattribute will be the string"a return-typechecked callable".