Package: click-type-test
click-type-testTable of ContentsOverviewInstallationUsageAPILicenseOverviewclick-type-testallows you to test that yourclickoptions and arguments
match your type annotations.It is named by the trio of things which it supports:click: build a CLItype: add type annotationstest: test that the first two matchInstallationclick-type-testonly works on Python 3.10+ .On supported python versions, it should be installed withpip install click-type-testUsageInstall the package and then useclick_type_testto extract annotation data
and check it against your commands.fromclick_type_testimportcheck_param_annotationsfromfoopkgimportmycommanddeftest_mycommand_annotations():check_param_annotations(mycommand)check_param_annotationsraises aclick_type_test.BadAnnotationErrorif an annotation does not match.Version GuardingJust becauseclick-type-testonly works on certain pythons does not mean that
your application, tested with it, is also restricted to those python versions.You can guard your usage like so (underpytest):importpytestimportsysfromfoopkgimportmycommand@pytest.mark.skipif(sys.version_info<(3,10),reason="click-type-test requires py3.10+",)deftest_mycommand_annotations():fromclick_type_testimportcheck_param_annotationscheck_param_annotations(mycommand)Type Determination Logicclick-type-testmakes its best effort to determine what type will be passed
to the command at runtime, based on the available information.If the parameter implementsAnnotatedParameterand has an explicit
annotation, that value will always be used.This makes this value the highest precedence override.If there is acallbackfunction with a return type annotation, the return
type of thecallbackwill be used.
This makes thecallbackreturn type the second highest precedence value.After this,click-type-testmust inspect the parameter type which has been
used, anydefaultvalue which has been set,multiple=Truefor options andnargs=-1for arguments, and generally try to infer the type correctly.For parameter type evaluation, users can control the behavior of custom types
in two significant ways:annotateconvertwith a return type annotation (this will be used if
available)implementAnnotatedOptionand define a type annotation (this is used as the
highest precedence value for a parameter type, so it can be used as an
override)As a simple example,click-type-testis able to handle the following comma
delimited list type definition correctly correctly:classCommaDelimitedList(click.ParamType):defget_metavar(self,param:click.Parameter)->str:return"TEXT,TEXT,..."defconvert(self,value:str,param:click.Parameter|None,ctx:click.Context|None)->list[str]:value=super().convert(value,param,ctx)returnvalue.split(",")ifvalueelse[]Extending And Adjusting With AnnotatedParamType and AnnotatedOptionThe type deductions made byclick-type-testare not always going to be
correct. But rather than skipping options or parameters, it's better to
pass along the information needed if possible.Custom parameter types can support usage withclick-type-testby implementing
theAnnotatedParamTypeprotocol.Similarly, customclick.Optionsubclasses can support specialized usage by
implementing theAnnotatedOptionprotocol.The path you take will depend a bit on the precise needs of your CLI, but it
generally should be possible to tuneclick-type-testto correctly understand
your CLI.AnnotatedParamTypeIf you have a customParamType, extend it to implement theAnnotatedParamTypeprotocol and it will have first-class support inclick-type-test.This requires that there be a method,get_type_annotation, which takes theclick.Parameterwhich was used and returns the type which should be expected
as an annotation.You can check that aParamTypeimplementsAnnotatedParamTypewith
a simpleisinstancecheck:importclick_type_testisinstance(myparamtype,click_type_test.AnnotatedParamType)AnnotatedParameterIf you have a subclass ofOptionorArgumentwhich produces specialized
values, it may be necessary to provide type information from that class.
To handle this case, just have your parameter class implement theAnnotatedParameterprotocol.This requires a method,has_explicit_annotation, and a propertytype_annotation.has_explicit_annotationtakes no arguments and returns a bool.type_annotationreturns atype.Seeexamples/explicitly_annotation_option.pyfor an example.You can check that aParameterimplementsAnnotatedParameterwith
a simpleisinstancecheck:importclick_type_testisinstance(myparam,click_type_test.AnnotatedParameter)APIThe following values are the consumable API forclick-type-test.
No other values are part of the interface.AnnotatedParamType: a protocol forclick.ParamTypesubclasses which
provide explicit type information. It is runtime checkable.AnnotatedParameter: a protocol forclick.Parametersubclasses which
provide explicit type information. It is runtime checkable.deduce_type_from_parameter: a function which takes aclick.Parameterand
returns a type. Used internally but useful for unit testing custom classes.check_param_annotations: a function which takes aclick.Commandand
checks the type annotations on its callback against its parameter list.BadAnnotationError: the error type raised if checking annotations fails.Licenseclick-type-testis distributed under the terms of theMITlicense.