Typing and validation
Adding type hints with Generics¤
New in version 0.92
The Component
class optionally accepts type parameters that allow you to specify the types of args, kwargs, slots, and data:
Args
- Must be aTuple
orAny
Kwargs
- Must be aTypedDict
orAny
Data
- Must be aTypedDict
orAny
Slots
- Must be aTypedDict
orAny
Here's a full example:
from typing import NotRequired, Tuple, TypedDict, SlotContent, SlotFunc
# Positional inputs
Args = Tuple[int, str]
# Kwargs inputs
class Kwargs(TypedDict):
variable: str
another: int
maybe_var: NotRequired[int] # May be ommited
# Data returned from `get_context_data`
class Data(TypedDict):
variable: str
# The data available to the `my_slot` scoped slot
class MySlotData(TypedDict):
value: int
# Slots
class Slots(TypedDict):
# Use SlotFunc for slot functions.
# The generic specifies the `data` dictionary
my_slot: NotRequired[SlotFunc[MySlotData]]
# SlotContent == Union[str, SafeString]
another_slot: SlotContent
class Button(Component[Args, Kwargs, Slots, Data, JsData, CssData]):
def get_context_data(self, variable, another):
return {
"variable": variable,
}
When you then call Component.render
or Component.render_to_response
, you will get type hints:
Button.render(
# Error: First arg must be `int`, got `float`
args=(1.25, "abc"),
# Error: Key "another" is missing
kwargs={
"variable": "text",
},
)
Usage for Python <3.11¤
On Python 3.8-3.10, use typing_extensions
Additionally on Python 3.8-3.9, also import annotations
:
Moreover, on 3.10 and less, you may not be able to use NotRequired
, and instead you will need to mark either all keys are required, or all keys as optional, using TypeDict's total
kwarg.
See PEP-655 for more info.
Passing additional args or kwargs¤
You may have a function that supports any number of args or kwargs:
This is not supported with the typed components.
As a workaround:
- For
*args
, set a positional argument that accepts a list of values:
- For
*kwargs
, set a keyword argument that accepts a dictionary of values:
class Kwargs(TypedDict):
variable: str
another: int
# Pass any extra keys under `extra`
extra: Dict[str, any]
Handling no args or no kwargs¤
To declare that a component accepts no Args, Kwargs, etc, you can use EmptyTuple
and EmptyDict
types:
from django_components import Component, EmptyDict, EmptyTuple
Args = EmptyTuple
Kwargs = Data = Slots = EmptyDict
class Button(Component[Args, Kwargs, Slots, Data, JsData, CssData]):
...
Runtime input validation with types¤
New in version 0.96
NOTE: Kwargs, slots, and data validation is supported only for Python >=3.11
In Python 3.11 and later, when you specify the component types, you will get also runtime validation of the inputs you pass to Component.render
or Component.render_to_response
.
So, using the example from before, if you ignored the type errors and still ran the following code:
Button.render(
# Error: First arg must be `int`, got `float`
args=(1.25, "abc"),
# Error: Key "another" is missing
kwargs={
"variable": "text",
},
)
This would raise a TypeError
:
Component 'Button' expected positional argument at index 0 to be <class 'int'>, got 1.25 of type <class 'float'>
In case you need to skip these errors, you can either set the faulty member to Any
, e.g.:
Or you can replace Args
with Any
altogether, to skip the validation of args:
# Replaced `Args` with `Any`
class Button(Component[Any, Kwargs, Slots, Data, JsData, CssData]):
...
Same applies to kwargs, data, and slots.