Skip to content

API Reference

cwtch.cwtch

is_cwtch_model(cls) -> bool

Check if class or instance is a cwtch model.

Source code in cwtch/cwtch.py
def is_cwtch_model(cls) -> bool:
    """Check if class or instance is a cwtch model."""

    return bool(getattr(cls, "__cwtch_model__", None) and not getattr(cls, "__cwtch_view__", None))

is_cwtch_view(cls) -> bool

Check if class or instance is a cwtch view.

Source code in cwtch/cwtch.py
def is_cwtch_view(cls) -> bool:
    """Check if class or instance is a cwtch view."""

    return bool(getattr(cls, "__cwtch_model__", None) and getattr(cls, "__cwtch_view__", None))

field(default: Any = _MISSING, *, default_factory: _Missing[Callable] = _MISSING, init: bool = True, init_alias: Unset[str] = UNSET, asdict_alias: Unset[str] = UNSET, repr: Unset[Literal[False]] = UNSET, compare: Unset[bool] = UNSET, property: Unset[Literal[True]] = UNSET, validate: Unset[bool] = UNSET, metadata: Unset[dict] = UNSET, kw_only: Unset[dict] = UNSET) -> Any

Return an object to identify dataclass fields.

Parameters:

Name Type Description Default
default Any

The default value of the field.

_MISSING
default_factory _Missing[Callable]

A 0-argument function called to initialize a field's value.

_MISSING
init bool

If init is true, the field will be a parameter to the class's __init__() function.

True
init_alias Unset[str]

Field alias for init.

UNSET
asdict_alias Unset[str]

Field alis for asdict.

UNSET
repr Unset[Literal[False]]

If repr is true, the field will be included in the object's repr().

UNSET
compare Unset[bool]

If compare is true, the field will be used in comparison functions.

UNSET
property Unset[Literal[True]]

If true fiels will became a property.

UNSET
validate Unset[bool]

Validate or not.

UNSET
metadata Unset[dict]

If specified, must be a mapping which is stored but not otherwise examined by dataclass.

UNSET
kw_only Unset[dict]

If kw_only true, the field will become a keyword-only parameter to __init__().

UNSET

It is an error to specify both default and default_factory.

Source code in cwtch/cwtch.py
def field(
    default: Any = _MISSING,
    *,
    default_factory: _Missing[Callable] = _MISSING,
    init: bool = True,
    init_alias: Unset[str] = UNSET,
    asdict_alias: Unset[str] = UNSET,
    repr: Unset[Literal[False]] = UNSET,
    compare: Unset[bool] = UNSET,
    property: Unset[Literal[True]] = UNSET,
    validate: Unset[bool] = UNSET,
    metadata: Unset[dict] = UNSET,
    kw_only: Unset[dict] = UNSET,
) -> Any:
    """
    Return an object to identify dataclass fields.

    Args:
        default: The default value of the field.
        default_factory: A 0-argument function called to initialize a field's value.
        init: If init is true, the field will be a parameter to the class's `__init__()` function.
        init_alias: Field alias for __init__.
        asdict_alias: Field alis for asdict.
        repr: If repr is true, the field will be included in the object's repr().
        compare: If compare is true, the field will be used in comparison functions.
        property: If true fiels will became a property.
        validate: Validate or not.
        metadata: If specified, must be a mapping which is stored but not otherwise examined by dataclass.
        kw_only: If kw_only true, the field will become a keyword-only parameter to `__init__()`.

    It is an error to specify both default and default_factory.
    """
    return Field(
        default=default,
        default_factory=default_factory,
        init=init,
        init_alias=init_alias,
        asdict_alias=asdict_alias,
        repr=repr,
        compare=compare,
        property=property,
        validate=validate,
        metadata=metadata,
        kw_only=kw_only,
    )

dataclass(cls=None, *, slots: Unset[bool] = UNSET, kw_only: Unset[bool] = UNSET, env_prefix: Unset[str | Sequence[str]] = UNSET, env_source: Unset[Callable] = UNSET, validate: Unset[bool] = UNSET, add_disable_validation_to_init: Unset[bool] = UNSET, show_input_value_on_error: Unset[bool] = UNSET, extra: Unset[Literal['ignore', 'forbid']] = UNSET, repr: Unset[bool] = UNSET, eq: Unset[bool] = UNSET, recursive: Unset[bool | Sequence[str]] = UNSET, handle_circular_refs: Unset[bool] = UNSET) -> Callable[[Type[T]], Type[T]]

Parameters:

Name Type Description Default
slots Unset[bool]

If true, __slots__ attribute will be generated and new class will be returned instead of the original one. If __slots__ is already defined in the class, then TypeError is raised.

UNSET
kw_only Unset[bool]

If kw_only is true, then by default all fields are keyword-only.

UNSET
env_prefix Unset[str | Sequence[str]]

Prefix(or list of prefixes) for environment variables.

UNSET
env_source Unset[Callable]

Environment variables source factory. By default os.environ.

UNSET
validate Unset[bool]

If false, validation will be disabled for the entire class.

UNSET
add_disable_validation_to_init Unset[bool]

Add disable_validation keywoard argument to __init__() method to disable validation.

UNSET
extra Unset[Literal['ignore', 'forbid']]

Ignore or forbid extra arguments passed to init.

UNSET
repr Unset[bool]

If true, a __rich_repr__() method will be generated and rich.repr.auto decorator applied to the class.

UNSET
eq Unset[bool]

If true, an __eq__() method will be generated. This method compares the class as if it were a tuple of its fields, in order. Both instances in the comparison must be of the identical type.

UNSET
recursive Unset[bool | Sequence[str]]

...

UNSET
handle_circular_refs Unset[bool]

If true, cwtch will handle circular references..

UNSET
Source code in cwtch/cwtch.py
@dataclass_transform(field_specifiers=(field,))
def dataclass(
    cls=None,
    *,
    slots: Unset[bool] = UNSET,
    kw_only: Unset[bool] = UNSET,
    env_prefix: Unset[str | Sequence[str]] = UNSET,
    env_source: Unset[Callable] = UNSET,
    validate: Unset[bool] = UNSET,
    add_disable_validation_to_init: Unset[bool] = UNSET,
    show_input_value_on_error: Unset[bool] = UNSET,
    extra: Unset[Literal["ignore", "forbid"]] = UNSET,
    repr: Unset[bool] = UNSET,
    eq: Unset[bool] = UNSET,
    recursive: Unset[bool | Sequence[str]] = UNSET,
    handle_circular_refs: Unset[bool] = UNSET,
) -> Callable[[Type[T]], Type[T]]:
    """
    Args:
        slots: If true, `__slots__` attribute will be generated
            and new class will be returned instead of the original one.
            If `__slots__` is already defined in the class, then TypeError is raised.
        kw_only: If kw_only is true, then by default all fields are keyword-only.
        env_prefix: Prefix(or list of prefixes) for environment variables.
        env_source: Environment variables source factory. By default os.environ.
        validate: If false, validation will be disabled for the entire class.
        add_disable_validation_to_init: Add disable_validation keywoard argument to `__init__()` method
            to disable validation.
        extra: Ignore or forbid extra arguments passed to init.
        repr: If true, a `__rich_repr__()` method will be generated and rich.repr.auto decorator applied to the class.
        eq: If true, an `__eq__()` method will be generated.
            This method compares the class as if it were a tuple of its fields, in order.
            Both instances in the comparison must be of the identical type.
        recursive: ...
        handle_circular_refs: If true, cwtch will handle circular references..
    """

    if slots is UNSET:
        slots = SLOTS
    if kw_only is UNSET:
        kw_only = KW_ONLY
    if validate is UNSET:
        validate = VALIDATE
    if add_disable_validation_to_init is UNSET:
        add_disable_validation_to_init = ADD_DISABLE_VALIDATION_TO_INIT
    if show_input_value_on_error is UNSET:
        show_input_value_on_error = SHOW_INPUT_VALUE_ON_ERROR
    if extra is UNSET:
        extra = EXTRA
    if repr is UNSET:
        repr = REPR
    if eq is UNSET:
        eq = EQ
    if recursive is UNSET:
        recursive = RECURSIVE
    if handle_circular_refs is UNSET:
        handle_circular_refs = HANDLE_CIRCULAR_REFS

    def wrapper(
        cls,
        slots=slots,
        kw_only=kw_only,
        env_prefix=env_prefix,
        env_source=env_source,
        validate=validate,
        add_disable_validation_to_init=add_disable_validation_to_init,
        extra=extra,
        repr=repr,
        eq=eq,
        recursive=recursive,
        handle_circular_refs=handle_circular_refs,
    ):
        return _build(
            cls,
            cast(bool, slots),
            cast(bool, kw_only),
            cast(
                Unset[Sequence[str]],
                env_prefix if env_prefix is UNSET or isinstance(env_prefix, (list, tuple, set)) else [env_prefix],
            ),
            env_source,
            cast(bool, validate),
            cast(bool, add_disable_validation_to_init),
            cast(Literal["ignore", "forbid"], extra),
            cast(bool, repr),
            cast(bool, eq),
            cast(bool, recursive),
            cast(bool, handle_circular_refs),
        )

    if cls is None:
        return wrapper

    return wrapper(cls)

view(base_cls, name: Unset[str] = UNSET, *, base: Unset[Type] = UNSET, attach: Unset[bool | Type] = UNSET, include: Unset[Sequence[str]] = UNSET, exclude: Unset[Sequence[str]] = UNSET, slots: Unset[bool] = UNSET, kw_only: Unset[bool] = UNSET, env_prefix: Unset[str | Sequence[str]] = UNSET, env_source: Unset[Callable] = UNSET, validate: Unset[bool] = UNSET, add_disable_validation_to_init: Unset[bool] = UNSET, extra: Unset[Literal['ignore', 'forbid']] = UNSET, repr: Unset[bool] = UNSET, eq: Unset[bool] = UNSET, recursive: Unset[bool | Sequence[str]] = UNSET, handle_circular_refs: Unset[bool] = UNSET) -> Callable[[Type[T]], Type[T]]

Parameters:

Name Type Description Default
name Unset[str]

View name.

UNSET
base Unset[Type]

Class to use as source.

UNSET
attach Unset[bool | Type]

If true, view will be attached to base cls.

UNSET
include Unset[Sequence[str]]

List of fields to include in view.

UNSET
exclude Unset[Sequence[str]]

List of fields to exclude from view.

UNSET
slots Unset[bool]

If true, __slots__ attribute will be generated and new class will be returned instead of the original one. If __slots__ is already defined in the class, then TypeError is raised. If UNSET value from base view model will be used.

UNSET
kw_only Unset[bool]

If kw_only is true, then by default all fields are keyword-only.

UNSET
env_prefix Unset[str | Sequence[str]]

Prefix(or list of prefixes) for environment variables. If UNSET value from base view model will be used.

UNSET
env_source Unset[Callable]

Environment variables source factory. If UNSET value from base view model will be used.

UNSET
validate Unset[bool]

Validate or not fields. If UNSET value from base view model will be used.

UNSET
add_disable_validation_to_init Unset[bool]

Add disable_validation keywoard argument to __init__() method to disable validation. If UNSET value from base view model will be used.

UNSET
extra Unset[Literal['ignore', 'forbid']]

Ignore or forbid extra arguments passed to init. If UNSET value from base view model will be used.

UNSET
repr Unset[bool]

If true, a __rich_repr__() method will be generated and rich.repr.auto decorator applied to the class. If UNSET value from base view model will be used.

UNSET
eq Unset[bool]

If true, an __eq__() method will be generated. This method compares the class as if it were a tuple of its fields, in order. Both instances in the comparison must be of the identical type. If UNSET value from base view model will be used.

UNSET
recursive Unset[bool | Sequence[str]]

...

UNSET
handle_circular_refs Unset[bool]

Handle or not circular refs. If UNSET value from base view model will be used.

UNSET
Source code in cwtch/cwtch.py
@dataclass_transform(field_specifiers=(field,))
def view(
    base_cls,
    name: Unset[str] = UNSET,
    *,
    base: Unset[Type] = UNSET,
    attach: Unset[bool | Type] = UNSET,
    include: Unset[Sequence[str]] = UNSET,
    exclude: Unset[Sequence[str]] = UNSET,
    slots: Unset[bool] = UNSET,
    kw_only: Unset[bool] = UNSET,
    env_prefix: Unset[str | Sequence[str]] = UNSET,
    env_source: Unset[Callable] = UNSET,
    validate: Unset[bool] = UNSET,
    add_disable_validation_to_init: Unset[bool] = UNSET,
    extra: Unset[Literal["ignore", "forbid"]] = UNSET,
    repr: Unset[bool] = UNSET,
    eq: Unset[bool] = UNSET,
    recursive: Unset[bool | Sequence[str]] = UNSET,
    handle_circular_refs: Unset[bool] = UNSET,
) -> Callable[[Type[T]], Type[T]]:
    """
    Args:
        name: View name.
        base: Class to use as source.
        attach: If true, view will be attached to base cls.
        include: List of fields to include in view.
        exclude: List of fields to exclude from view.
        slots: If true, `__slots__` attribute will be generated
            and new class will be returned instead of the original one.
            If `__slots__` is already defined in the class, then TypeError is raised.
            If UNSET value from base view model will be used.
        kw_only: If kw_only is true, then by default all fields are keyword-only.
        env_prefix: Prefix(or list of prefixes) for environment variables.
            If UNSET value from base view model will be used.
        env_source: Environment variables source factory.
            If UNSET value from base view model will be used.
        validate: Validate or not fields.
            If UNSET value from base view model will be used.
        add_disable_validation_to_init: Add disable_validation keywoard argument to `__init__()` method
            to disable validation.
            If UNSET value from base view model will be used.
        extra: Ignore or forbid extra arguments passed to init.
            If UNSET value from base view model will be used.
        repr: If true, a `__rich_repr__()` method will be generated and rich.repr.auto decorator applied to the class.
            If UNSET value from base view model will be used.
        eq: If true, an `__eq__()` method will be generated.
            This method compares the class as if it were a tuple of its fields, in order.
            Both instances in the comparison must be of the identical type.
            If UNSET value from base view model will be used.
        recursive: ...
        handle_circular_refs: Handle or not circular refs.
            If UNSET value from base view model will be used.
    """

    if not (is_cwtch_model(base_cls) or is_cwtch_view(base_cls)):
        raise TypeError(f"{base_cls} is not a valid cwtch model or view")

    def wrapper(
        view_cls,
        *,
        base_cls=base or base_cls,
        name=name,
        attach=attach,
        include=include,
        exclude=exclude,
        slots=slots,
        kw_only=kw_only,
        env_prefix=env_prefix,
        env_source=env_source,
        validate=validate,
        add_disable_validation_to_init=add_disable_validation_to_init,
        extra=extra,
        repr=repr,
        eq=eq,
        recursive=recursive,
        handle_circular_refs=handle_circular_refs,
    ):
        if exclude and set(exclude) & view_cls.__annotations__.keys():  # type: ignore
            raise ValueError(f"unable to exclude fields {list(set(exclude) & view_cls.__annotations__.keys())}")  # type: ignore

        return _build_view(
            base_cls,
            view_cls,
            name,
            attach,
            include,
            exclude,
            slots,
            kw_only,
            cast(
                Unset[Sequence[str]],
                env_prefix if env_prefix is UNSET or isinstance(env_prefix, (list, tuple, str)) else [env_prefix],
            ),
            env_source,
            validate,
            add_disable_validation_to_init,
            extra,
            repr,
            eq,
            recursive,
            handle_circular_refs,
        )

    return wrapper

from_attributes(cls, obj: Any, data: dict | None = None, exclude: Sequence | None = None, suffix: str | None = None, reset_circular_refs: bool | None = None)

Build model from attributes of other object.

Parameters:

Name Type Description Default
obj Any

Object from which to build.

required
data dict | None

Additional data to build.

None
exclude Sequence | None

List of fields to exclude.

None
suffix str | None

Fields suffix.

None
reset_circular_refs bool | None

Reset circular references to None.

None
Source code in cwtch/cwtch.py
def from_attributes(
    cls,
    obj: Any,
    data: dict | None = None,
    exclude: Sequence | None = None,
    suffix: str | None = None,
    reset_circular_refs: bool | None = None,
):
    """
    Build model from attributes of other object.

    Args:
      obj: Object from which to build.
      data: Additional data to build.
      exclude: List of fields to exclude.
      suffix: Fields suffix.
      reset_circular_refs: Reset circular references to None.
    """

    kwds = {
        f.name: getattr(obj, f"{f_name}{suffix}" if suffix else f_name)
        for f_name, f in cls.__dataclass_fields__.items()
        if (not exclude or f_name not in exclude) and hasattr(obj, f"{f.name}{suffix}" if suffix else f_name)
    }
    if data:
        kwds.update(data)
    if exclude:
        kwds = {k: v for k, v in kwds.items() if k not in exclude}

    cache = get_cache()
    cache["reset_circular_refs"] = reset_circular_refs

    try:
        return cls(__cwtch_cache_key=(cls, id(obj)), **kwds)
    finally:
        del cache["reset_circular_refs"]

asdict(inst, include: Sequence[str] | None = None, exclude: Sequence[str] | None = None, exclude_none: bool | None = None, exclude_unset: bool | None = None, context: dict | None = None) -> dict

Return cwtch model as dict.

Parameters:

Name Type Description Default
inst

cwtch model.

required
include Sequence[str] | None

List of field names to include.

None
exclude Sequence[str] | None

List of field names to exclude.

None
exclude_none bool | None

If true, fields with None value will be excluded.

None
exclude_unset bool | None

If true, unset fields will be excluded.

None
context dict | None

If specified, must be a mapping.

None
Source code in cwtch/cwtch.py
def asdict(
    inst,
    include: Sequence[str] | None = None,
    exclude: Sequence[str] | None = None,
    exclude_none: bool | None = None,
    exclude_unset: bool | None = None,
    context: dict | None = None,
) -> dict:
    """
    Return cwtch model as dict.

    Args:
        inst: cwtch model.
        include: List of field names to include.
        exclude: List of field names to exclude.
        exclude_none: If true, fields with None value will be excluded.
        exclude_unset: If true, unset fields will be excluded.
        context: If specified, must be a mapping.
    """

    return _asdict(
        inst,
        include_=include,
        exclude_=exclude,
        exclude_none=exclude_none,
        exclude_unset=exclude_unset,
        context=context,
    )

dumps_json(inst, encoder: Callable[[Any], Any] | None = None, context: dict | None = None)

Dump cwtch model to json.

Parameters:

Name Type Description Default
encoder Callable[[Any], Any] | None

Custom JSON encoder as callable.

None
context dict | None

If specified, must be a mapping.

None
Source code in cwtch/cwtch.py
def dumps_json(inst, encoder: Callable[[Any], Any] | None = None, context: dict | None = None):
    """
    Dump cwtch model to json.

    Args:
        encoder: Custom JSON encoder as callable.
        context: If specified, must be a mapping.
    """

    return _dumps_json(inst, encoder, context)

validate_args(fn: Callable, args: tuple, kwds: dict) -> tuple[tuple, dict]

Helper to convert and validate function arguments.

Parameters:

Name Type Description Default
args tuple

function positional arguments.

required
kwds dict

function keyword arguments.

required
Source code in cwtch/cwtch.py
def validate_args(fn: Callable, args: tuple, kwds: dict) -> tuple[tuple, dict]:
    """
    Helper to convert and validate function arguments.

    Args:
      args: function positional arguments.
      kwds: function keyword arguments.
    """

    annotations = {k: v.annotation for k, v in signature(fn).parameters.items()}

    validated_args = []

    for v, (arg_name, T) in zip(args, annotations.items()):
        if T != _empty:
            try:
                validated_args.append(validate_value(v, T))
            except ValidationError as e:
                raise TypeError(f"{fn.__name__}() expects {T} for argument {arg_name}") from e
        else:
            validated_args.append(v)

    validated_kwds = {}

    for arg_name, v in kwds.items():
        T = annotations[arg_name]
        if T != _empty:
            try:
                validated_kwds[arg_name] = validate_value(v, T)
            except ValidationError as e:
                raise TypeError(f"{fn.__name__}() expects {T} for argument {arg_name}") from e
        else:
            validated_kwds[arg_name] = v

    return tuple(validated_args), validated_kwds

validate_call(fn)

Decorator to convert and validate function arguments.

Source code in cwtch/cwtch.py
def validate_call(fn):
    """Decorator to convert and validate function arguments."""

    def wrapper(*args, **kwds):
        validate_args(fn, args, kwds)
        return fn(*args, **kwds)

    return wrapper

clone(base_cls, *, include: Unset[Sequence[str]] = UNSET, exclude: Unset[Sequence[str]] = UNSET, slots: Unset[bool] = UNSET, kw_only: Unset[bool] = UNSET, env_prefix: Unset[str | Sequence[str]] = UNSET, env_source: Unset[Callable] = UNSET, validate: Unset[bool] = UNSET, add_disable_validation_to_init: Unset[bool] = UNSET, extra: Unset[Literal['ignore', 'forbid']] = UNSET, repr: Unset[bool] = UNSET, eq: Unset[bool] = UNSET, handle_circular_refs: Unset[bool] = UNSET) -> Callable[[Type[T]], Type[T]]

TODO

Source code in cwtch/cwtch.py
@dataclass_transform(field_specifiers=(field,))
def clone(
    base_cls,
    *,
    include: Unset[Sequence[str]] = UNSET,
    exclude: Unset[Sequence[str]] = UNSET,
    slots: Unset[bool] = UNSET,
    kw_only: Unset[bool] = UNSET,
    env_prefix: Unset[str | Sequence[str]] = UNSET,
    env_source: Unset[Callable] = UNSET,
    validate: Unset[bool] = UNSET,
    add_disable_validation_to_init: Unset[bool] = UNSET,
    extra: Unset[Literal["ignore", "forbid"]] = UNSET,
    repr: Unset[bool] = UNSET,
    eq: Unset[bool] = UNSET,
    handle_circular_refs: Unset[bool] = UNSET,
) -> Callable[[Type[T]], Type[T]]:
    """
    TODO
    """

    if not (is_cwtch_model(base_cls) or is_cwtch_view(base_cls)):
        raise TypeError(f"{base_cls} is not a valid cwtch model or view")

    if is_cwtch_view(base_cls):
        name = base_cls.__cwtch_view_name__
    else:
        name = UNSET

    def wrapper(
        view_cls,
        *,
        base_cls=base_cls,
        name=name,
        attach=False,
        include=include,
        exclude=exclude,
        slots=slots,
        kw_only=kw_only,
        env_prefix=env_prefix,
        env_source=env_source,
        validate=validate,
        add_disable_validation_to_init=add_disable_validation_to_init,
        extra=extra,
        repr=repr,
        eq=eq,
        recursive=False,
        handle_circular_refs=handle_circular_refs,
    ):
        if exclude and set(exclude) & view_cls.__annotations__.keys():  # type: ignore
            raise ValueError(f"unable to exclude fields {list(set(exclude) & view_cls.__annotations__.keys())}")  # type: ignore

        clone = _build_view(
            base_cls,
            view_cls,
            name,
            attach,
            include,
            exclude,
            slots,
            kw_only,
            cast(
                Unset[Sequence[str]],
                env_prefix if env_prefix is UNSET or isinstance(env_prefix, (list, tuple, str)) else [env_prefix],
            ),
            env_source,
            validate,
            add_disable_validation_to_init,
            extra,
            repr,
            eq,
            recursive,
            handle_circular_refs,
        )

        def view(
            base_cls,
            name: Unset[str] = UNSET,
            *,
            base: Unset[Type] = UNSET,
            include: Unset[Sequence[str]] = UNSET,
            exclude: Unset[Sequence[str]] = UNSET,
            slots: Unset[bool] = UNSET,
            kw_only: Unset[bool] = UNSET,
            env_prefix: Unset[str | Sequence[str]] = UNSET,
            env_source: Unset[Callable] = UNSET,
            validate: Unset[bool] = UNSET,
            add_disable_validation_to_init: Unset[bool] = UNSET,
            extra: Unset[Literal["ignore", "forbid"]] = UNSET,
            repr: Unset[bool] = UNSET,
            eq: Unset[bool] = UNSET,
            recursive: Unset[bool | Sequence[str]] = UNSET,
            handle_circular_refs: Unset[bool] = UNSET,
        ):
            return globals()["view"](
                base_cls,
                name=name,
                base=base,
                attach=base_cls,
                include=include,
                exclude=exclude,
                slots=slots,
                kw_only=kw_only,
                env_prefix=env_prefix,
                env_source=env_source,
                validate=validate,
                add_disable_validation_to_init=add_disable_validation_to_init,
                extra=extra,
                repr=repr,
                eq=eq,
                recursive=recursive,
                handle_circular_refs=handle_circular_refs,
            )

        clone.view = classmethod(view)

        return clone

    return wrapper

cwtch.metadata

Validator

Bases: ValidatorBefore, ValidatorAfter

Validator class.

Attributes:

Name Type Description
json_schema dict

Additional custom JSON schema.

before Callable

Validator to validate input data before base validation.

after Callable

Validator to validate value after base validation.

Ge

Bases: _Ge

Validator to check that the input data is greater than or equal to the specified value.

Example:

Annotated[int, Ge(1)]

Gt

Bases: _Gt

Validator to check if input is greater than specified value.

Example:

Annotated[int, Gt(1)]

Le

Bases: _Le

Validator to check that the input data is less than or equal to the specified value.

Example:

Annotated[int, Le(1)]

Lt

Bases: _Lt

Validator to check if input is less than specified value.

Example:

Annotated[int, Lt(1)]

MinLen

Bases: _MinLen

Validator to check that the length of the input data is greater than or equal to the specified value.

Example:

Annotated[str, MinLen(1)]

MaxLen

Bases: _MaxLen

Validator to check that the length of the input data is less than or equal to the specified value.

Example:

Annotated[str, MaxLen(1)]

Len

Bases: _Len

Validator to check that the input length is within the specified range.

Example:

Annotated[str, Len(1, 10)]

MinItems

Bases: _MinItems

Validator to check that the number of elements in the input is greater than or equal to the specified value.

Example:

Annotated[list, MinItems(1)]

MaxItems

Bases: _MaxItems

Validator to check that the number of elements in the input is less than or equal to the specified value.

Example:

Annotated[list, MaxItems(1)]

Match

Bases: ValidatorAfter

Validator to check that an input value matches a regular expression.

Example:

Annotated[str, Match(r".*")]

ToLower

Bases: _ToLowerA, _ToLowerB

Convert input to lower case.

Attributes:

Name Type Description
mode Literal['before', 'after']

Validation mode, before or after base validation. Default: after.

Example:

Annotated[str, ToLower()]

ToUpper

Bases: _ToUpperA, _ToUpperB

Convert input to upper case.

Attributes:

Name Type Description
mode Literal['before', 'after']

Validation mode, before or after base validation. Default: after.

Example:

Annotated[str, ToUpper()]

UrlConstraints

Bases: ValidatorAfter

URL constraints.

Attributes:

Name Type Description
schemes list[str] | None

List of valid schemes.

ports list[int] | None

list of valid ports.

Example:

Annotated[Url, UrlConstraints(schemes=["http", "https"])]

JsonLoads

Bases: ValidatorBefore

Validator to try load value from json.

Example:

Annotated[list[int], JsonLoads()]

Strict

Bases: ValidatorBefore

Validator to strict input type.

Example:

Annotated[int, Strict(int)]

EmailValidator

Bases: ValidatorAfter

Email address validator.

cwtch.types

UNSET = UNSET module-attribute

Type to mark value as unset.

Number = int | float module-attribute

Number type. Example:

i: Number = 1
f: Number = 1.1

Positive = Annotated[T, Ge(1)] module-attribute

Positive type(Generic). Example:

i: Positive[int] = 1
n: Positive[Number] = 1.1

NonNegative = Annotated[T, Ge(0)] module-attribute

Non negative type(Generic). Example:

i: NonNegative[int] = 0
n: NonNegative[Number] = 0.0

NonEmpty = Annotated[T, MinItems(1)] module-attribute

Non empty container. Example:

l: NonEmpty[list] = [1]

NonZeroLen = Annotated[T, MinLen(1)] module-attribute

Non zero length object. Example:

l: NonZeroLen[str] = "a"

LowerStr = Annotated[str, ToLower()] module-attribute

Lower case string. Example:

s: LowerStr = "a"

UpperStr = Annotated[str, ToUpper()] module-attribute

Upper case string. Example:

s: LowerStr = "A"

HttpUrl = Annotated[Url, UrlConstraints(schemes=['http', 'https'])] module-attribute

Type for HTTP URL.

SecretHttpUrl = Annotated[SecretUrl, UrlConstraints(schemes=['http', 'https'])] module-attribute

Type for secret HTTP URL.

WebsocketpUrl = Annotated[Url, UrlConstraints(schemes=['ws', 'wss'])] module-attribute

Type for websocket URL.

FileUrl = Annotated[Url, UrlConstraints(schemes=['file'])] module-attribute

Type for file URL.

FtpUrl = Annotated[Url, UrlConstraints(schemes=['ftp'])] module-attribute

Type for FTP URL.

Strict

Bases: Generic[T]

Example:

b: Strict[bool] = True
Source code in cwtch/types.py
class Strict(Generic[T]):
    """
    Example:

        b: Strict[bool] = True
    """

    def __class_getitem__(cls, tp):
        if __args__ := getattr(tp, "__args__", None):
            if tp.__class__ == typing._AnnotatedAlias:
                return Annotated[tp, StrictMetadata(__args__[0])]
            if tp.__class__ in [types.UnionType, typing._UnionGenericAlias]:  # type: ignore
                return Union[*[Annotated[arg, StrictMetadata(arg)] for arg in __args__]]
            raise ValueError(f"{tp} is unsupported by {cls}")
        return Annotated[tp, StrictMetadata(tp)]

SecretBytes

Bases: bytes

Type to represent secret bytes.

Source code in cwtch/types.py
class SecretBytes(bytes):
    """Type to represent secret bytes."""

    __cwtch_type_config__ = {"strict_validation": False}

    if TYPE_CHECKING:
        _value: bytes

    def __new__(cls, value):
        try:
            if not isinstance(value, bytes):
                if isinstance(value, str) and not cls.__cwtch_type_config__["strict_validation"]:
                    value = value.encode()
                else:
                    raise ValueError(f"value is not a valid {bytes}")
        except Exception:
            raise ValueError(f"value is not a valid {bytes}")
        obj = super().__new__(cls, b"***")
        obj._value = value
        return obj

    def __repr__(self):
        return f"{self.__class__.__name__}(***)"

    def __hash__(self):
        return hash(self._value)

    def __eq__(self, other):
        if not isinstance(other, SecretBytes):
            return False
        return self._value == other._value

    def __ne__(self, other):
        if not isinstance(other, SecretBytes):
            return True
        return self._value != other._value

    def __len__(self):
        return len(self._value)

    def __cwtch_asdict__(self, handler, kwds: AsDictKwds):
        if (kwds.context or {}).get("show_secrets"):
            return self.get_secret_value()
        return self

    def get_secret_value(self) -> bytes:
        return self._value

SecretStr

Bases: str

Type to represent secret string.

Source code in cwtch/types.py
class SecretStr(str):
    """Type to represent secret string."""

    __slots__ = ("_value",)

    __cwtch_type_config__ = {"strict_validation": False}

    if TYPE_CHECKING:
        _value: str

    def __new__(cls, value):
        try:
            if not isinstance(value, str):
                if not cls.__cwtch_type_config__["strict_validation"]:
                    value = super().__new__(str, value)
                else:
                    raise ValueError(f"value is not a valid {str}")
        except Exception:
            raise ValueError(f"value is not a valid {str}")
        obj = super().__new__(cls, "***")
        obj._value = value
        return obj

    def __repr__(self):
        return f"{self.__class__.__name__}(***)"

    def __hash__(self):
        return hash(self._value)

    def __eq__(self, other):
        if not isinstance(other, SecretStr):
            return False
        return self._value == other._value

    def __ne__(self, other):
        if not isinstance(other, SecretStr):
            return True
        return self._value != other._value

    def __len__(self):
        return len(self._value)

    @classmethod
    def __cwtch_json_schema__(cls, **kwds) -> dict:
        return {"type": "string"}

    def __cwtch_asdict__(self, handler, kwds: AsDictKwds):
        if (kwds.context or {}).get("show_secrets"):
            return self.get_secret_value()
        return self

    def __cwtch_asjson__(self, context: dict | None = None):
        if (context or {}).get("show_secrets"):
            return self.get_secret_value()
        return f"{self}"

    def get_secret_value(self) -> str:
        return self._value

Url

Bases: str, _UrlMixIn

Type to represent URL.

Source code in cwtch/types.py
class Url(str, _UrlMixIn):
    """Type to represent URL."""

    __slots__ = ("_parsed",)

    def __new__(cls, value):
        try:
            if not isinstance(value, str):
                raise ValueError(f"value is not a valid {str}")
        except Exception:
            raise ValueError(f"value is not a valid {str}")
        try:
            parsed = urlparse(value)
        except Exception as e:
            raise ValueError(e)
        if parsed.hostname:
            _validate_hostname(parsed.hostname)

        obj = super().__new__(cls, parsed.geturl())
        obj._parsed = parsed
        return obj

    def __repr__(self):
        return f"{self.__class__.__name__}({self})"

    @classmethod
    def __cwtch_json_schema__(cls, **kwds) -> dict:
        return {"type": "string", "format": "uri"}

    def __cwtch_asjson__(self, context: dict | None = None):
        return f"{self}"

SecretUrl

Bases: str, _UrlMixIn

Type to represent secret URL.

Source code in cwtch/types.py
class SecretUrl(str, _UrlMixIn):
    """Type to represent secret URL."""

    __slots__ = ("_parsed", "_value")

    def __new__(cls, value):
        try:
            if not isinstance(value, str):
                raise ValueError(f"value is not a valid {str}")
        except Exception:
            raise ValueError(f"value is not a valid {str}")
        try:
            parsed = urlparse(value)
        except Exception as e:
            raise ValueError(e)
        if parsed.hostname:
            _validate_hostname(parsed.hostname)

        obj = super().__new__(
            cls,
            (
                parsed._replace(
                    netloc=f"***:***@{parsed.hostname}" + (f":{parsed.port}" if parsed.port is not None else "")
                ).geturl()
                if parsed.scheme
                else parsed.geturl()
            ),
        )
        obj._parsed = parsed
        obj._value = parsed.geturl()
        return obj

    def __repr__(self):
        parsed = self._parsed
        value = (
            parsed._replace(
                netloc=f"***:***@{parsed.hostname}" + (f":{parsed.port}" if parsed.port is not None else "")
            ).geturl()
            if parsed.scheme
            else parsed.geturl()
        )
        return f"{self.__class__.__name__}({value})"

    def __hash__(self):
        return hash(self._value)

    def __eq__(self, other):
        if not isinstance(other, SecretUrl):
            return False
        return self._value == other._value

    def __ne__(self, other):
        if not isinstance(other, SecretUrl):
            return True
        return self._value != other._value

    def __len__(self):
        return len(self._value)

    @property
    def username(self) -> Optional[str]:
        return "***" if self._parsed.username else None

    @property
    def password(self) -> Optional[str]:
        return "***" if self._parsed.password else None

    @classmethod
    def __cwtch_json_schema__(cls, **kwds) -> dict:
        return {"type": "string", "format": "uri"}

    def __cwtch_asdict__(self, handler, kwds: AsDictKwds):
        if (kwds.context or {}).get("show_secrets"):
            return self.get_secret_value()
        return self

    def __cwtch_asjson__(self, context: dict | None = None):
        if (context or {}).get("show_secrets"):
            return self.get_secret_value()
        return f"{self}"

    def get_secret_value(self) -> str:
        return self._value