click-type-test
Table of Contents
Overview
click-type-test allows you to test that your
click options 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 match
Installation
click-type-test only works on Python 3.10+ .
On supported python versions, it should be installed with
pip install click-type-test
Usage
Install the package and then use click_type_test to extract annotation data
and check it against your commands.
from click_type_test import check_param_annotations
from foopkg import mycommand
def test_mycommand_annotations():
check_param_annotations(mycommand)
check_param_annotations raises a
click_type_test.BadAnnotationError if an annotation does not match.
Version Guarding
Just because click-type-test only 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 (under pytest):
import pytest
import sys
from foopkg import mycommand
@pytest.mark.skipif(
sys.version_info < (3, 10),
reason="click-type-test requires py3.10+",
)
def test_mycommand_annotations():
from click_type_test import check_param_annotations
check_param_annotations(mycommand)
Type Determination Logic
click-type-test makes its best effort to determine what type will be passed
to the command at runtime, based on the available information.
-
If the parameter implements
AnnotatedParameterand has an explicit annotation, that value will always be used.This makes this value the highest precedence override.
-
If there is a
callbackfunction 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:
-
annotate
convertwith a return type annotation (this will be used if available) -
implement
AnnotatedOptionand 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-test is able to handle the following comma
delimited list type definition correctly correctly:
class CommaDelimitedList(click.ParamType):
def get_metavar(self, param: click.Parameter) -> str:
return "TEXT,TEXT,..."
def convert(
self, value: str, param: click.Parameter | None, ctx: click.Context | None
) -> list[str]:
value = super().convert(value, param, ctx)
return value.split(",") if value else []
Extending And Adjusting With AnnotatedParamType and AnnotatedOption
The type deductions made by click-type-test are 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 with click-type-test by implementing
the AnnotatedParamType protocol.
Similarly, custom click.Option subclasses can support specialized usage by
implementing the AnnotatedOption protocol.
The path you take will depend a bit on the precise needs of your CLI, but it
generally should be possible to tune click-type-test to correctly understand
your CLI.
AnnotatedParamType
If you have a custom ParamType, extend it to implement the
AnnotatedParamType protocol and it will have first-class support in
click-type-test.
This requires that there be a method, get_type_annotation, which takes the
click.Parameter which was used and returns the type which should be expected
as an annotation.
You can check that a ParamType implements AnnotatedParamType with
a simple isinstance check:
import click_type_test
isinstance(myparamtype, click_type_test.AnnotatedParamType)
AnnotatedParameter
If you have a subclass of Option or Argument which produces specialized
values, it may be necessary to provide type information from that class.
To handle this case, just have your parameter class implement the
AnnotatedParameter protocol.
This requires a method, has_explicit_annotation, and a property
type_annotation.
has_explicit_annotation takes no arguments and returns a bool.
type_annotation returns a type.
See
examples/explicitly_annotation_option.py for an example.
You can check that a Parameter implements AnnotatedParameter with
a simple isinstance check:
import click_type_test
isinstance(myparam, click_type_test.AnnotatedParameter)
API
The following values are the consumable API for click-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.
License
click-type-test is distributed under the terms of the MIT license.
Release files for click-type-test 1.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| click_type_test-1.4.0.tar.gz | 13.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| click_type_test-1.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 22.6 kB
Release files / click_type_test-1.4.0.tar.gz
| Download URL | click_type_test-1.4.0.tar.gz |
|---|---|
| Size | 13.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d8a411cc3898df82c6eac10df80bcd972272e09e61c17675cbbf320cee915727
|
|
BLAKE2b-256 checksum How to use checksums |
151f0089d7b72e89e69b25844c1a92a0be682144686c78b0e98bae88dca574a4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency logRelease files / click_type_test-1.4.0-py3-none-any.whl
| Download URL | click_type_test-1.4.0-py3-none-any.whl |
|---|---|
| Size | 8.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
31629244399080827a8ec7475b7347e7c60f73015b3c4f7542f13630b72a517e
|
|
BLAKE2b-256 checksum How to use checksums |
ece6169633e171e4272fca0824647129c1d93398800916e34b11740870769a0f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency log