at type.

###  Constrained types  ¶

This behavior is also exposed via the ` strict ` field of the constrained
types and can be combined with a multitude of complex validation rules. See
the individual type signatures for supported arguments.

  * [ ` conbytes() ` ](../../api/types/#pydantic.types.conbytes)
  * [ ` condate() ` ](../../api/types/#pydantic.types.condate)
  * [ ` condecimal() ` ](../../api/types/#pydantic.types.condecimal)
  * [ ` confloat() ` ](../../api/types/#pydantic.types.confloat)
  * [ ` confrozenset() ` ](../../api/types/#pydantic.types.confrozenset)
  * [ ` conint() ` ](../../api/types/#pydantic.types.conint)
  * [ ` conlist() ` ](../../api/types/#pydantic.types.conlist)
  * [ ` conset() ` ](../../api/types/#pydantic.types.conset)
  * [ ` constr() ` ](../../api/types/#pydantic.types.constr)

The following caveats apply:

  * ` StrictBytes ` (and the ` strict ` option of ` conbytes() ` ) will accept both ` bytes ` , and ` bytearray ` types. 
  * ` StrictInt ` (and the ` strict ` option of ` conint() ` ) will not accept ` bool ` types, even though ` bool ` is a subclass of ` int ` in Python. Other subclasses will work. 
  * ` StrictFloat ` (and the ` strict ` option of ` confloat() ` ) will not accept ` int ` . 

Besides the above, you can also have a [ ` FiniteFloat `
](../../api/types/#pydantic.types.FiniteFloat) type that will only accept
finite values (i.e. not ` inf ` , ` -inf ` or ` nan ` ).

##  Custom Types  ¶

You can also define your own custom data types. There are several ways to
achieve it.

###  Composing types via ` Annotated ` ¶

[ PEP 593 ](https://peps.python.org/pep-0593/) introduced ` Annotated ` as a
way to attach runtime metadata to types without changing how type checkers
interpret them. Pydantic takes advantage of this to allow you to create types
that are identical to the original type as far as type checkers are concerned,
but add validation, serialize differently, etc.

For example, to create a type representing a positive int:

    
    
    # or `from typing import Annotated` for Python 3.9+
    from typing_extensions import Annotated
    
    from pydantic import Field, TypeAdapter, ValidationError
    
    PositiveInt = Annotated[int, Field(gt=0)]
    
    ta = TypeAdapter(PositiveInt)
    
    print(ta.validate_python(1))
    #> 1
    
    try:
        ta.validate_python(-1)
    except ValidationError as exc:
        print(exc)
        """
        1 validation error for constrained-int
          Input should be greater than 0 [type=greater_than, input_value=-1, input_type=int]
        """
    

Note that you can also use constraints from [ annotated-types
](https://github.com/annotated-types/annotated-types) to make this Pydantic-
agnostic:

    
    
    from annotated_types import Gt
    from typing_extensions import Annotated
    
    from pydantic import TypeAdapter, ValidationError
    
    PositiveInt = Annotated[int, Gt(0)]
    
    ta = TypeAdapter(PositiveInt)
    
    print(ta.validate_python(1))
    #> 1
    
    try:
        ta.validate_python(-1)
    except ValidationError as exc:
        print(exc)
        """
        1 validation error for constrained-int
          Input should be greater than 0 [type=greater_than, input_value=-1, input_type=int]
        """
    

####  Adding validation and serialization  ¶

You can add or override validation, serialization, and JSON schemas to an
arbitrary type using the markers that Pydantic exports:

    
    
    from typing_extensions import Annotated
    
    from pydantic import (
        AfterValidator,
        PlainSerializer,
        TypeAdapter,
        WithJsonSchema,
    )
    
    TruncatedFloat = Annotated[
        float,
        AfterValidator(lambda x: round(x, 1)),
        PlainSerializer(lambda x: f'{x:.1e}', return_type=str),
        WithJsonSchema({'type': 'string'}, mode='serialization'),
    ]
    
    
    ta = TypeAdapter(TruncatedFloat)
    
    input = 1.02345
    assert input != 1.0
    
    assert