Skip to main content
`Ctrl`+`K`

# Defining new trait types

To define a new trait type, subclass from `TraitType`. You can define the following things:

class traitlets.MyTrait
  info_text

    A short string describing what this trait should hold.

  default_value

    A default value, if one makes sense for this trait type. If there is no obvious default, don’t provide this.

  validate(obj, value)

    Check whether a given value is valid. If it is, it should return the value (coerced to the desired type, if necessary). If not, it should raise `TraitError`. `TraitType.error()` is a convenient way to raise an descriptive error saying that the given value is not of the required type.

    `obj` is the object to which the trait belongs.

For instance, here’s the definition of the `TCPAddress` trait:

    class TCPAddress(TraitType[G, S]):
        """A trait for an (ip, port) tuple.

        This allows for both IPv4 IP addresses as well as hostnames.
        """

        default_value = ("127.0.0.1", 0)
        info_text = "an (ip, port) tuple"

        if t.TYPE_CHECKING:

            @t.overload
            def __init__(
                self: TCPAddress[tuple[str, int], tuple[str, int]],
                default_value: bool | Sentinel = ...,
                allow_none: Literal[False] = ...,
                read_only: bool | None = ...,
                help: str | None = ...,
                config: t.Any = ...,
                **kwargs: t.Any,
            ) -> None:
                ...

            @t.overload
            def __init__(
                self: TCPAddress[tuple[str, int] | None, tuple[str, int] | None],
                default_value: bool | None | Sentinel = ...,
                allow_none: Literal[True] = ...,
                read_only: bool | None = ...,
                help: str | None = ...,
                config: t.Any = ...,
                **kwargs: t.Any,
            ) -> None:
                ...

            def __init__(
                self: TCPAddress[tuple[str, int] | None, tuple[str, int] | None]
                | TCPAddress[tuple[str, int], tuple[str, int]],
                default_value: bool | None | Sentinel = Undefined,
                allow_none: Literal[True, False] = False,
                read_only: bool | None = None,
                help: str | None = None,
                config: t.Any = None,
                **kwargs: t.Any,
            ) -> None:
                ...

        def validate(self, obj: t.Any, value: t.Any) -> G:
            if isinstance(value, tuple):
                if len(value) == 2:
                    if isinstance(value[0], str) and isinstance(value[1], int):
                        port = value[1]
                        if port >= 0 and port <= 65535:
                            return t.cast(G, value)
            self.error(obj, value)

        def from_string(self, s: str) -> G:
            if self.allow_none and s == "None":
                return t.cast(G, None)
            if ":" not in s:
                raise ValueError("Require `ip:port`, got %r" % s)
            ip, port_str = s.split(":", 1)
            port = int(port_str)
            return t.cast(G, (ip, port))