Skip to content

pane.classes

pane.classes

Pane dataclasses.

PaneBaseT = t.TypeVar('PaneBaseT', bound='PaneBase') module-attribute

ClassLayout = t.Literal['tuple', 'struct'] module-attribute

Set of known class layouts for 'in_formats' and 'out_format'.

PANE_INFO = '__pane_info__' module-attribute

Name of dunder attribute holding PaneInfo

PANE_SET_FIELDS = '__pane_set__' module-attribute

Name of dunder attribute holding a set of fields which have been set/modified

PANE_BOUNDVARS = '__pane_boundvars__' module-attribute

Name of dunder attribute holding a dictionary of bound type variables (for generic subclasses only).

POST_INIT = '__post_init__' module-attribute

Name of post-init method

Field dataclass

Represents a materialized dataclass field.

Typically instantiated from a FieldSpec.

Source code in pane/field.py
@dataclasses.dataclass
class Field:
    """
    Represents a materialized dataclass field.

    Typically instantiated from a [`FieldSpec`][pane.field.FieldSpec].
    """

    _: KW_ONLY = dataclasses.field(init=False, repr=False, compare=False)
    name: str
    """Name of field"""
    type: t.Any
    """Type of field. Must be [`Convertible`][pane.convert.Convertible]."""
    in_names: t.Sequence[str]
    """List of names which convert to this field."""
    out_name: str
    """Name this field converts into."""
    init: bool = True
    """Whether to add this field to __init__ methods (and conversion from other types)"""
    exclude: bool = False
    """Whether to exclude this field when converting to other types"""
    repr: bool = True
    """Whether to include this field in __repr__"""
    hash: bool = True
    """Whether to include this field in the generated __hash__ method"""
    compare: bool = True
    """Whether to include this field in generated comparison methods (__eq__, __gt__, etc.)"""
    default: t.Union[t.Any, _Missing] = _MISSING
    """Default value for field"""
    default_factory: t.Optional[t.Callable[[], t.Any]] = None
    """Default value factory for field"""
    kw_only: bool = False
    """Whether field is keyword only"""
    converter: t.Optional[Converter[t.Any]] = None
    """Custom converter to use for this field."""

    @classmethod
    def make(cls, name: str, ty: type,
             in_rename: t.Optional[t.Sequence[RenameStyle]] = None,
             out_rename: t.Optional[RenameStyle] = None) -> Field:
        in_names = tuple(rename_field(name, style) for style in in_rename) if in_rename is not None else (name,)
        out_name = rename_field(name, out_rename) if out_rename is not None else name
        return cls(name=name, type=ty, in_names=in_names, out_name=out_name)

    def has_default(self) -> bool:
        """Return whether this field has a default value"""
        return self.default is not _MISSING or self.default_factory is not None

name instance-attribute

Name of field

type instance-attribute

Type of field. Must be Convertible.

in_names instance-attribute

List of names which convert to this field.

out_name instance-attribute

Name this field converts into.

init = True class-attribute instance-attribute

Whether to add this field to init methods (and conversion from other types)

exclude = False class-attribute instance-attribute

Whether to exclude this field when converting to other types

repr = True class-attribute instance-attribute

Whether to include this field in repr

hash = True class-attribute instance-attribute

Whether to include this field in the generated hash method

compare = True class-attribute instance-attribute

Whether to include this field in generated comparison methods (eq, gt, etc.)

default = _MISSING class-attribute instance-attribute

Default value for field

default_factory = None class-attribute instance-attribute

Default value factory for field

kw_only = False class-attribute instance-attribute

Whether field is keyword only

converter = None class-attribute instance-attribute

Custom converter to use for this field.

make(name, ty, in_rename=None, out_rename=None) classmethod

Source code in pane/field.py
@classmethod
def make(cls, name: str, ty: type,
         in_rename: t.Optional[t.Sequence[RenameStyle]] = None,
         out_rename: t.Optional[RenameStyle] = None) -> Field:
    in_names = tuple(rename_field(name, style) for style in in_rename) if in_rename is not None else (name,)
    out_name = rename_field(name, out_rename) if out_rename is not None else name
    return cls(name=name, type=ty, in_names=in_names, out_name=out_name)

has_default()

Return whether this field has a default value

Source code in pane/field.py
def has_default(self) -> bool:
    """Return whether this field has a default value"""
    return self.default is not _MISSING or self.default_factory is not None

PaneBase

Base class for all pane dataclasses

Source code in pane/classes.py
@dataclass_transform(
    eq_default=True,
    order_default=True,
    frozen_default=True,
    kw_only_default=False,
    field_specifiers=(FieldSpec, field),
)
class PaneBase:
    """
    Base class for all `pane` dataclasses
    """
    __slots__ = ('__pane_set__',)

    __pane_info__: PaneInfo
    """Dunder attribute holding [`PaneInfo`][pane.classes.PaneInfo]"""
    __pane_set__: t.Set[str]
    """Dunder attribute holding a set of fields which have been set/modified"""

    def __init_subclass__(
        cls,
        *args: t.Any,
        name: t.Optional[str] = None,
        out_format: t.Optional[ClassLayout] = None,
        in_format: t.Optional[t.Sequence[ClassLayout]] = None,
        eq: t.Optional[bool] = None,
        order: t.Optional[bool] = None,
        frozen: t.Optional[bool] = None,
        kw_only: t.Optional[bool] = None,
        rename: t.Optional[RenameStyle] = None,
        in_rename: t.Optional[t.Union[RenameStyle, t.Sequence[RenameStyle]]] = None,
        out_rename: t.Optional[RenameStyle] = None,
        allow_extra: t.Optional[bool] = None,
        custom: t.Optional[IntoConverterHandlers] = None,
        **kwargs: t.Any,
    ):
        old_params = getattr(cls, '__parameters__', ())
        super().__init_subclass__(*args, **kwargs)
        setattr(cls, '__parameters__', old_params + getattr(cls, '__parameters__', ()))

        if rename is not None:
            if in_rename is not None or out_rename is not None:
                raise ValueError("'rename' cannot be specified with 'in_rename' or 'out_rename'")
            in_rename = t.cast(t.Tuple[RenameStyle, ...], (rename,))
            out_rename = rename
        elif in_rename is not None and isinstance(in_rename, str):
            in_rename = t.cast(t.Tuple[RenameStyle, ...], (in_rename,))

        # handle option inheritance
        opts: PaneOptions = getattr(cls, PANE_INFO).opts if hasattr(cls, PANE_INFO) else PaneOptions()
        opts = opts.replace(
            name=name, out_format=out_format, in_format=in_format,
            eq=eq, order=order, frozen=frozen, allow_extra=allow_extra,
            kw_only=kw_only, in_rename=in_rename, out_rename=out_rename,
            class_handlers=ConverterHandlers._process(custom),
        )

        _process(cls, opts)

    def __class_getitem__(cls, params: t.Union[type, t.Tuple[type, ...]]):
        if not isinstance(params, tuple):
            params = (params,)
        return _make_subclass(cls, params)

    def __repr__(self) -> str:
        inside = ", ".join(
            f"{field.name}={getattr(self, field.name)!r}" for field in self.__pane_info__.fields
            if field.repr
        )
        return f"{self.__class__.__name__}({inside})"

    def __setattr__(self, name: str, value: t.Any) -> None:
        opts = self.__pane_info__.opts
        if opts.frozen:
            raise FrozenInstanceError(f"cannot assign to field {name!r}")
        super().__setattr__(name, value)
        set_fields: t.Set[str] = getattr(self, PANE_SET_FIELDS)
        set_fields.add(name)

    def __delattr__(self, name: str) -> None:
        raise AttributeError(f"cannot delete field {name!r}")

    def __copy__(self):
        return self.from_dict_unchecked(
            {field.name: getattr(self, field.name) for field in self.__pane_info__.fields},
            set_fields=getattr(self, PANE_SET_FIELDS),
        )

    def __deepcopy__(self, memo: t.Any):
        from copy import deepcopy
        return self.from_dict_unchecked(
            {field.name: deepcopy(getattr(self, field.name), memo) for field in self.__pane_info__.fields},
            set_fields=getattr(self, PANE_SET_FIELDS),
        )

    def __replace__(self, /, **changes: t.Any) -> Self:
        set_fields = getattr(self, PANE_SET_FIELDS)
        d = {
            field.name: getattr(self, field.name)
            for field in self.__pane_info__.fields if field.name in set_fields
        }
        d.update(**changes)
        return self.__class__(**d)

    @classmethod
    def _converter(cls: t.Type[PaneBaseT], *args: t.Type[Convertible],
                   handlers: ConverterHandlers) -> Converter[PaneBaseT]:
        if len(args) > 0:
            cls = t.cast(t.Type[PaneBaseT], cls[tuple(args)])  # type: ignore
        return PaneConverter(cls, handlers=handlers)

    @classmethod
    def make_unchecked(cls, *args: t.Any, **kwargs: t.Any) -> Self:
        ...

    @classmethod
    def from_dict_unchecked(cls, d: t.Dict[str, t.Any], *, set_fields: t.Optional[t.Set[str]] = None) -> Self:
        ...

    @classmethod
    def from_obj(cls, obj: Convertible, *,
                 custom: t.Optional[IntoConverterHandlers] = None) -> Self:
        """
        Convert `obj` into `cls`. Equivalent to `convert(obj, cls)`

        Parameters:
          obj: Object to convert. Must be convertible.
        """
        return convert(obj, cls, custom=custom)

    @classmethod
    def from_data(cls, data: DataType, *,
                  custom: t.Optional[IntoConverterHandlers] = None) -> Self:
        """
        Convert `data` into `cls`. Equivalent to `from_data(data, cls)`

        Parameters:
          data: Data to convert. Must be a data interchange type.
        """
        return from_data(data, cls, custom=custom)

    def into_data(self, *, custom: t.Optional[IntoConverterHandlers] = None) -> DataType:
        """Convert `self` into interchange data"""
        return into_data(self, self.__class__, custom=custom)

    def dict(self, *, set_only: bool = False, rename: t.Optional[RenameStyle] = None) -> t.Dict[str, t.Any]:
        """
        Return a dict of the fields in `self`

        Parameters:
          set_only: If `True`, return only the fields which have been set
          rename: Rename fields to match the given style
        """
        if set_only:
            return {
                rename_field(k, rename): getattr(self, k) for k in getattr(self, PANE_SET_FIELDS)
            }
        return {
            rename_field(field.name, rename): getattr(self, field.name) for field in self.__pane_info__.fields
            if not field.exclude
        }

    @classmethod
    def from_json(cls, f: io.FileOrPath, *,
                  custom: t.Optional[IntoConverterHandlers] = None) -> Self:
        """
        Load `cls` from a JSON file `f`

        Parameters:
          f: File-like or path-like to load from
          custom: Custom converters to use
        """
        return io.from_json(f, cls, custom=custom)

    @classmethod
    def from_yaml(cls, f: io.FileOrPath, *,
                  custom: t.Optional[IntoConverterHandlers] = None) -> Self:
        """
        Load `cls` from a YAML file `f`

        Parameters:
          f: File-like or path-like to load from
          custom: Custom converters to use
        """
        return io.from_yaml(f, cls, custom=custom)

    @classmethod
    def from_yaml_all(cls, f: io.FileOrPath, *,
                  custom: t.Optional[IntoConverterHandlers] = None) -> t.List[Self]:
        """
        Load a list of `cls` from a YAML file `f`

        Parameters:
          f: File-like or path-like to load from
          custom: Custom converters to use
        """
        return io.from_yaml_all(f, cls, custom=custom)

    @classmethod
    def from_yamls(cls, s: str, *,
                   custom: t.Optional[IntoConverterHandlers] = None) -> Self:
        """
        Load `cls` from a YAML string `s`

        Parameters:
          s: YAML string to load from
          custom: Custom converters to use
        """
        from io import StringIO
        return io.from_yaml(StringIO(s), cls, custom=custom)

    @classmethod
    def from_jsons(cls, s: str, *,
                   custom: t.Optional[IntoConverterHandlers] = None) -> Self:
        """
        Load `cls` from a JSON string `s`

        Parameters:
          s: JSON string to load from
          custom: Custom converters to use
        """
        from io import StringIO
        return io.from_json(StringIO(s), cls, custom=custom)

    @t.overload
    def write_json(self, f: None = None, *,
                  indent: t.Union[str, int, None] = None,
                  sort_keys: bool = False,
                  custom: t.Optional[IntoConverterHandlers] = None) -> str:
        ...

    @t.overload
    def write_json(self, f: io.FileOrPath, *,
                  indent: t.Union[str, int, None] = None,
                  sort_keys: bool = False,
                  custom: t.Optional[IntoConverterHandlers] = None) -> None:
        ...

    def write_json(self, f: t.Optional[io.FileOrPath] = None, *,
                  indent: t.Union[str, int, None] = None,
                  sort_keys: bool = False,
                  custom: t.Optional[IntoConverterHandlers] = None) -> t.Optional[str]:
        """
        Write data to a JSON file or string. If given a file `f`, write to that.
        Otherwise, write to a string and return.

        Parameters:
          indent: Indent to format JSON with. Defaults to None (no indentation)
          sort_keys: Whether to sort keys prior to serialization.
          custom: Custom converters to use
        """
        from io import StringIO

        buf = StringIO() if f is None else f
        io.write_json(
            self, buf, ty=self.__class__,
            indent=indent, sort_keys=sort_keys, custom=custom
        )
        return buf.getvalue() if f is None else None  # type: ignore

    @t.overload
    def write_yaml(self, f: io.FileOrPath, *,
                  indent: t.Optional[int] = None, width: t.Optional[int] = None,
                  allow_unicode: bool = True,
                  explicit_start: bool = True, explicit_end: bool = False,
                  default_style: t.Optional[t.Literal['"', '|', '>']] = None,
                  default_flow_style: t.Optional[bool] = None,
                  sort_keys: bool = False,
                  custom: t.Optional[IntoConverterHandlers] = None) -> None:
        ...

    @t.overload
    def write_yaml(self, f: None = None, *,
                  indent: t.Optional[int] = None, width: t.Optional[int] = None,
                  allow_unicode: bool = True,
                  explicit_start: bool = True, explicit_end: bool = False,
                  default_style: t.Optional[t.Literal['"', '|', '>']] = None,
                  default_flow_style: t.Optional[bool] = None,
                  sort_keys: bool = False,
                  custom: t.Optional[IntoConverterHandlers] = None) -> str:
        ...

    def write_yaml(self, f: t.Optional[io.FileOrPath] = None, *,
                  indent: t.Optional[int] = None, width: t.Optional[int] = None,
                  allow_unicode: bool = True,
                  explicit_start: bool = True, explicit_end: bool = False,
                  default_style: t.Optional[t.Literal['"', '|', '>']] = None,
                  default_flow_style: t.Optional[bool] = None,
                  sort_keys: bool = False,
                  custom: t.Optional[IntoConverterHandlers] = None) -> t.Optional[str]:
        """
        Write data to a YAML file or string. If given a file `f`, write to that.
        Otherwise, write to a string and return.

        Parameters:
          indent: Number of spaces to indent blocks with
          width: Maximum width of file created
          allow_unicode: Whether to output unicode characters or escape them
          explicit_start: Whether to include a YAML document start "---"
          explicit_end: Whether to include a YAML document end "..."
          default_style: Default style to use for scalar nodes.
              See YAML documentation for more information.
          default_flow_style: Whether to default to flow style or block style for collections.
              See YAML documentation for more information.
          sort_keys: Whether to sort keys prior to serialization.
          custom: Custom converters to use
        """
        from io import StringIO

        buf = StringIO() if f is None else f
        io.write_yaml(
            self, buf, ty=self.__class__,
            indent=indent, width=width, allow_unicode=allow_unicode,
            explicit_start=explicit_start, explicit_end=explicit_end,
            default_style=default_style, default_flow_style=default_flow_style,
            sort_keys=sort_keys, custom=custom
        )
        return buf.getvalue() if f is None else None  # type: ignore

_converter(*args, handlers) classmethod

Source code in pane/classes.py
@classmethod
def _converter(cls: t.Type[PaneBaseT], *args: t.Type[Convertible],
               handlers: ConverterHandlers) -> Converter[PaneBaseT]:
    if len(args) > 0:
        cls = t.cast(t.Type[PaneBaseT], cls[tuple(args)])  # type: ignore
    return PaneConverter(cls, handlers=handlers)

make_unchecked(*args, **kwargs) classmethod

Source code in pane/classes.py
@classmethod
def make_unchecked(cls, *args: t.Any, **kwargs: t.Any) -> Self:
    ...

from_dict_unchecked(d, *, set_fields=None) classmethod

Source code in pane/classes.py
@classmethod
def from_dict_unchecked(cls, d: t.Dict[str, t.Any], *, set_fields: t.Optional[t.Set[str]] = None) -> Self:
    ...

from_obj(obj, *, custom=None) classmethod

Convert obj into cls. Equivalent to convert(obj, cls)

Parameters:

Name Type Description Default
obj Convertible

Object to convert. Must be convertible.

required
Source code in pane/classes.py
@classmethod
def from_obj(cls, obj: Convertible, *,
             custom: t.Optional[IntoConverterHandlers] = None) -> Self:
    """
    Convert `obj` into `cls`. Equivalent to `convert(obj, cls)`

    Parameters:
      obj: Object to convert. Must be convertible.
    """
    return convert(obj, cls, custom=custom)

from_data(data, *, custom=None) classmethod

Convert data into cls. Equivalent to from_data(data, cls)

Parameters:

Name Type Description Default
data DataType

Data to convert. Must be a data interchange type.

required
Source code in pane/classes.py
@classmethod
def from_data(cls, data: DataType, *,
              custom: t.Optional[IntoConverterHandlers] = None) -> Self:
    """
    Convert `data` into `cls`. Equivalent to `from_data(data, cls)`

    Parameters:
      data: Data to convert. Must be a data interchange type.
    """
    return from_data(data, cls, custom=custom)

into_data(*, custom=None)

Convert self into interchange data

Source code in pane/classes.py
def into_data(self, *, custom: t.Optional[IntoConverterHandlers] = None) -> DataType:
    """Convert `self` into interchange data"""
    return into_data(self, self.__class__, custom=custom)

dict(*, set_only=False, rename=None)

Return a dict of the fields in self

Parameters:

Name Type Description Default
set_only bool

If True, return only the fields which have been set

False
rename Optional[RenameStyle]

Rename fields to match the given style

None
Source code in pane/classes.py
def dict(self, *, set_only: bool = False, rename: t.Optional[RenameStyle] = None) -> t.Dict[str, t.Any]:
    """
    Return a dict of the fields in `self`

    Parameters:
      set_only: If `True`, return only the fields which have been set
      rename: Rename fields to match the given style
    """
    if set_only:
        return {
            rename_field(k, rename): getattr(self, k) for k in getattr(self, PANE_SET_FIELDS)
        }
    return {
        rename_field(field.name, rename): getattr(self, field.name) for field in self.__pane_info__.fields
        if not field.exclude
    }

from_json(f, *, custom=None) classmethod

Load cls from a JSON file f

Parameters:

Name Type Description Default
f FileOrPath

File-like or path-like to load from

required
custom Optional[IntoConverterHandlers]

Custom converters to use

None
Source code in pane/classes.py
@classmethod
def from_json(cls, f: io.FileOrPath, *,
              custom: t.Optional[IntoConverterHandlers] = None) -> Self:
    """
    Load `cls` from a JSON file `f`

    Parameters:
      f: File-like or path-like to load from
      custom: Custom converters to use
    """
    return io.from_json(f, cls, custom=custom)

from_yaml(f, *, custom=None) classmethod

Load cls from a YAML file f

Parameters:

Name Type Description Default
f FileOrPath

File-like or path-like to load from

required
custom Optional[IntoConverterHandlers]

Custom converters to use

None
Source code in pane/classes.py
@classmethod
def from_yaml(cls, f: io.FileOrPath, *,
              custom: t.Optional[IntoConverterHandlers] = None) -> Self:
    """
    Load `cls` from a YAML file `f`

    Parameters:
      f: File-like or path-like to load from
      custom: Custom converters to use
    """
    return io.from_yaml(f, cls, custom=custom)

from_yaml_all(f, *, custom=None) classmethod

Load a list of cls from a YAML file f

Parameters:

Name Type Description Default
f FileOrPath

File-like or path-like to load from

required
custom Optional[IntoConverterHandlers]

Custom converters to use

None
Source code in pane/classes.py
@classmethod
def from_yaml_all(cls, f: io.FileOrPath, *,
              custom: t.Optional[IntoConverterHandlers] = None) -> t.List[Self]:
    """
    Load a list of `cls` from a YAML file `f`

    Parameters:
      f: File-like or path-like to load from
      custom: Custom converters to use
    """
    return io.from_yaml_all(f, cls, custom=custom)

from_yamls(s, *, custom=None) classmethod

Load cls from a YAML string s

Parameters:

Name Type Description Default
s str

YAML string to load from

required
custom Optional[IntoConverterHandlers]

Custom converters to use

None
Source code in pane/classes.py
@classmethod
def from_yamls(cls, s: str, *,
               custom: t.Optional[IntoConverterHandlers] = None) -> Self:
    """
    Load `cls` from a YAML string `s`

    Parameters:
      s: YAML string to load from
      custom: Custom converters to use
    """
    from io import StringIO
    return io.from_yaml(StringIO(s), cls, custom=custom)

from_jsons(s, *, custom=None) classmethod

Load cls from a JSON string s

Parameters:

Name Type Description Default
s str

JSON string to load from

required
custom Optional[IntoConverterHandlers]

Custom converters to use

None
Source code in pane/classes.py
@classmethod
def from_jsons(cls, s: str, *,
               custom: t.Optional[IntoConverterHandlers] = None) -> Self:
    """
    Load `cls` from a JSON string `s`

    Parameters:
      s: JSON string to load from
      custom: Custom converters to use
    """
    from io import StringIO
    return io.from_json(StringIO(s), cls, custom=custom)

write_json(f=None, *, indent=None, sort_keys=False, custom=None)

write_json(f: None = None, *, indent: t.Union[str, int, None] = None, sort_keys: bool = False, custom: t.Optional[IntoConverterHandlers] = None) -> str
write_json(f: io.FileOrPath, *, indent: t.Union[str, int, None] = None, sort_keys: bool = False, custom: t.Optional[IntoConverterHandlers] = None) -> None

Write data to a JSON file or string. If given a file f, write to that. Otherwise, write to a string and return.

Parameters:

Name Type Description Default
indent Union[str, int, None]

Indent to format JSON with. Defaults to None (no indentation)

None
sort_keys bool

Whether to sort keys prior to serialization.

False
custom Optional[IntoConverterHandlers]

Custom converters to use

None
Source code in pane/classes.py
def write_json(self, f: t.Optional[io.FileOrPath] = None, *,
              indent: t.Union[str, int, None] = None,
              sort_keys: bool = False,
              custom: t.Optional[IntoConverterHandlers] = None) -> t.Optional[str]:
    """
    Write data to a JSON file or string. If given a file `f`, write to that.
    Otherwise, write to a string and return.

    Parameters:
      indent: Indent to format JSON with. Defaults to None (no indentation)
      sort_keys: Whether to sort keys prior to serialization.
      custom: Custom converters to use
    """
    from io import StringIO

    buf = StringIO() if f is None else f
    io.write_json(
        self, buf, ty=self.__class__,
        indent=indent, sort_keys=sort_keys, custom=custom
    )
    return buf.getvalue() if f is None else None  # type: ignore

write_yaml(f=None, *, indent=None, width=None, allow_unicode=True, explicit_start=True, explicit_end=False, default_style=None, default_flow_style=None, sort_keys=False, custom=None)

write_yaml(f: io.FileOrPath, *, indent: t.Optional[int] = None, width: t.Optional[int] = None, allow_unicode: bool = True, explicit_start: bool = True, explicit_end: bool = False, default_style: t.Optional[t.Literal['"', '|', '>']] = None, default_flow_style: t.Optional[bool] = None, sort_keys: bool = False, custom: t.Optional[IntoConverterHandlers] = None) -> None
write_yaml(f: None = None, *, indent: t.Optional[int] = None, width: t.Optional[int] = None, allow_unicode: bool = True, explicit_start: bool = True, explicit_end: bool = False, default_style: t.Optional[t.Literal['"', '|', '>']] = None, default_flow_style: t.Optional[bool] = None, sort_keys: bool = False, custom: t.Optional[IntoConverterHandlers] = None) -> str

Write data to a YAML file or string. If given a file f, write to that. Otherwise, write to a string and return.

Parameters:

Name Type Description Default
indent Optional[int]

Number of spaces to indent blocks with

None
width Optional[int]

Maximum width of file created

None
allow_unicode bool

Whether to output unicode characters or escape them

True
explicit_start bool

Whether to include a YAML document start "---"

True
explicit_end bool

Whether to include a YAML document end "..."

False
default_style Optional[Literal['"', '|', '>']]

Default style to use for scalar nodes. See YAML documentation for more information.

None
default_flow_style Optional[bool]

Whether to default to flow style or block style for collections. See YAML documentation for more information.

None
sort_keys bool

Whether to sort keys prior to serialization.

False
custom Optional[IntoConverterHandlers]

Custom converters to use

None
Source code in pane/classes.py
def write_yaml(self, f: t.Optional[io.FileOrPath] = None, *,
              indent: t.Optional[int] = None, width: t.Optional[int] = None,
              allow_unicode: bool = True,
              explicit_start: bool = True, explicit_end: bool = False,
              default_style: t.Optional[t.Literal['"', '|', '>']] = None,
              default_flow_style: t.Optional[bool] = None,
              sort_keys: bool = False,
              custom: t.Optional[IntoConverterHandlers] = None) -> t.Optional[str]:
    """
    Write data to a YAML file or string. If given a file `f`, write to that.
    Otherwise, write to a string and return.

    Parameters:
      indent: Number of spaces to indent blocks with
      width: Maximum width of file created
      allow_unicode: Whether to output unicode characters or escape them
      explicit_start: Whether to include a YAML document start "---"
      explicit_end: Whether to include a YAML document end "..."
      default_style: Default style to use for scalar nodes.
          See YAML documentation for more information.
      default_flow_style: Whether to default to flow style or block style for collections.
          See YAML documentation for more information.
      sort_keys: Whether to sort keys prior to serialization.
      custom: Custom converters to use
    """
    from io import StringIO

    buf = StringIO() if f is None else f
    io.write_yaml(
        self, buf, ty=self.__class__,
        indent=indent, width=width, allow_unicode=allow_unicode,
        explicit_start=explicit_start, explicit_end=explicit_end,
        default_style=default_style, default_flow_style=default_flow_style,
        sort_keys=sort_keys, custom=custom
    )
    return buf.getvalue() if f is None else None  # type: ignore

PaneInfo dataclass

Structure holding internal information about a pane dataclass

Source code in pane/classes.py
@dataclasses.dataclass
class PaneInfo:
    """Structure holding internal information about a `pane` dataclass"""
    opts: PaneOptions
    """Dataclass options"""
    specs: t.Dict[str, FieldSpec]
    """
    Dict of raw field specifications

    This is used by subclasses to build [`Field`][pane.field.Field]s
    """
    fields: t.Tuple[Field, ...]
    """
    Tuple of processed [`Field`][pane.field.Field]s
    """
    pos_args: t.Tuple[int, int]
    """
    Range of allowed positional argument numbers, `[min, max]` inclusive
    """

opts instance-attribute

Dataclass options

specs instance-attribute

Dict of raw field specifications

This is used by subclasses to build Fields

fields instance-attribute

Tuple of processed Fields

pos_args instance-attribute

Range of allowed positional argument numbers, [min, max] inclusive

PaneOptions dataclass

Source code in pane/classes.py
@dataclasses.dataclass(frozen=True)
class PaneOptions:
    name: t.Optional[str] = None
    """Dataclass name"""
    _: KW_ONLY = dataclasses.field(init=False, repr=False, compare=False)
    eq: bool = True
    """Whether to generate `__eq__`/`__ne__` methods"""
    order: bool = True
    """Whether to generate `__gt__`/`__ge__`/`__lt__`/`__le__` methods"""
    frozen: bool = True
    """Whether dataclass fields are frozen"""
    unsafe_hash: bool = False
    """Whether to generate a hash method """
    kw_only: bool = False
    """Whether all fields should be keyword-only"""
    out_format: ClassLayout = 'struct'
    """Data format to convert class into"""
    in_format: t.Sequence[ClassLayout] = ('struct',)
    """Set of data formats class is convertible from"""
    in_rename: t.Optional[t.Sequence[RenameStyle]] = None
    """Set of rename styles class is convertible from"""
    out_rename: t.Optional[RenameStyle] = None
    """Rename style to convert class into"""
    allow_extra: bool = False
    """Whether extra fields are allowed in conversion"""
    class_handlers: t.Tuple[ConverterHandler, ...] = ()
    """Custom converters to use for field datatypes"""

    def replace(self, **changes: t.Any):
        """Return `self` with the given changes applied"""
        changes['name'] = changes.get('name', None)
        return dataclasses.replace(self, **{k: v for (k, v) in changes.items() if v is not None})

name = None class-attribute instance-attribute

Dataclass name

eq = True class-attribute instance-attribute

Whether to generate __eq__/__ne__ methods

order = True class-attribute instance-attribute

Whether to generate __gt__/__ge__/__lt__/__le__ methods

frozen = True class-attribute instance-attribute

Whether dataclass fields are frozen

unsafe_hash = False class-attribute instance-attribute

Whether to generate a hash method

kw_only = False class-attribute instance-attribute

Whether all fields should be keyword-only

out_format = 'struct' class-attribute instance-attribute

Data format to convert class into

in_format = ('struct',) class-attribute instance-attribute

Set of data formats class is convertible from

in_rename = None class-attribute instance-attribute

Set of rename styles class is convertible from

out_rename = None class-attribute instance-attribute

Rename style to convert class into

allow_extra = False class-attribute instance-attribute

Whether extra fields are allowed in conversion

class_handlers = () class-attribute instance-attribute

Custom converters to use for field datatypes

replace(**changes)

Return self with the given changes applied

Source code in pane/classes.py
def replace(self, **changes: t.Any):
    """Return `self` with the given changes applied"""
    changes['name'] = changes.get('name', None)
    return dataclasses.replace(self, **{k: v for (k, v) in changes.items() if v is not None})

PaneConverter

Bases: Converter[PaneBaseT]

Converter for pane dataclasses

Source code in pane/classes.py
class PaneConverter(Converter[PaneBaseT]):
    """
    [`Converter`][pane.converters.Converter] for `pane` dataclasses
    """
    def __init__(self, cls: t.Type[PaneBaseT], *,
                 handlers: ConverterHandlers):
        super().__init__()

        self.cls = cls
        self.name = self.cls.__name__
        self.cls_info: PaneInfo = getattr(self.cls, PANE_INFO)
        self.opts: PaneOptions = self.cls_info.opts
        self.fields: t.Sequence[Field] = self.cls_info.fields

        # prioritize:
        # - field converter
        # - custom passed to make_converter (handlers.globals)
        # - custom passed to this class (which inherits from superclasses) (self.opts.class_handlers)
        # - custom passed to parent (by composition) class (handlers.opts.class_handlers)
        handlers = ConverterHandlers(handlers.globals, (*self.opts.class_handlers, *handlers.class_local))

        self.field_converters: t.Sequence[Converter[t.Any]] = [
            field.converter if field.converter is not None else make_converter(field.type, handlers)
            for field in self.fields
        ]
        self.field_map: t.Dict[str, int] = {}

        for (i, f) in enumerate(self.fields):
            if not f.init:
                continue
            self.field_map[f.name] = i
            for alias in f.in_names:
                self.field_map[alias] = i

    def into_data(self, val: t.Any) -> DataType:
        """Convert dataclass `val` into data interchange, using the correct 'out_format'"""
        assert isinstance(val, PaneBase)
        if self.opts.out_format == 'tuple':
            return tuple(
                conv.into_data(getattr(val, field.name))
                for (field, conv) in zip(self.fields, self.field_converters)
                if not field.exclude
            )
        elif self.opts.out_format == 'struct':
            return {
                field.out_name: conv.into_data(getattr(val, field.name))
                for (field, conv) in zip(self.fields, self.field_converters)
                if not field.exclude
            }
        raise ValueError(f"Unknown 'out_format' '{self.opts.out_format}'")

    def expected(self, plural: bool = False) -> str:
        """Expected value for this converter"""
        return f"{list_phrase(self.opts.in_format)} {self.name}"

    def try_convert(self, val: t.Any) -> PaneBaseT:
        """
        See [`Converter.try_convert`][pane.converters.Converter.try_convert]

        Dispatches to [`try_convert_tuple`][pane.classes.PaneConverter.try_convert_tuple]
        and [`try_convert_struct`][pane.classes.PaneConverter.try_convert_struct]
        """
        # based on type, try to delegate to try_convert_tuple or try_convert_struct
        if isinstance(val, (list, tuple, t.Sequence)):
            val = t.cast(t.Sequence[t.Any], val)
            if 'tuple' not in self.opts.in_format:
                raise ParseInterrupt()

            return self.try_convert_tuple(t.cast(t.Sequence[t.Any], val))

        elif isinstance(val, (dict, t.Mapping)):
            if 'struct' not in self.opts.in_format:
                raise ParseInterrupt()

            return self.try_convert_struct(t.cast(t.Mapping[str, t.Any], val))

        raise ParseInterrupt()

    def collect_errors(self, val: t.Any) -> t.Union[WrongTypeError, WrongLenError, ProductErrorNode, None]:
        """
        See [`Converter.collect_errors`][pane.converters.Converter.collect_errors]

        Dispatches to [`collect_errors_tuple`][pane.classes.PaneConverter.collect_errors_tuple]
        and [`collect_errors_struct`][pane.classes.PaneConverter.collect_errors_struct]
        """
        # based on type, try to delegate to collect_errors_tuple or collect_errors_struct
        if isinstance(val, (list, tuple, t.Sequence)):
            if 'tuple' not in self.opts.in_format:
                return WrongTypeError(self.expected_struct(), val)

            return self.collect_errors_tuple(t.cast(t.Sequence[t.Any], val))

        elif isinstance(val, (dict, t.Mapping)):
            val = t.cast(t.Mapping[str, t.Any], val)
            if 'struct' not in self.opts.in_format:
                return WrongTypeError(f'tuple {self.name}', val)

            return self.collect_errors_struct(t.cast(t.Mapping[str, t.Any], val))

        return WrongTypeError(self.name, val)

    def expected_struct(self, plural: bool = False) -> str:
        """Expected value for the 'struct' data format"""
        return f"struct {self.name}"

    def try_convert_struct(self, val: t.Mapping[str, t.Any]) -> PaneBaseT:
        """[`Converter.try_convert`][pane.converters.Converter.try_convert] for the 'struct' data format"""
        # loop through values, and handle accordingly
        values: t.Dict[str, t.Any] = {}
        for (k, v) in t.cast(t.Dict[str, t.Any], val).items():
            if k not in self.field_map:
                if not self.opts.allow_extra:
                    raise ParseInterrupt()  # extra key
                continue
            field = self.fields[self.field_map[k]]
            conv = self.field_converters[self.field_map[k]]

            if field.name in values:
                raise ParseInterrupt()  # multiple values for key
            values[field.name] = conv.try_convert(v)

        set_fields = set(values.keys())

        for field in filter(lambda field: field.init and field.name not in values, self.fields):
            if field.default is not _MISSING:
                values[field.name] = field.default
            elif field.default_factory is not None:
                values[field.name] = field.default_factory
            else:
                raise ParseInterrupt()  # missing field

        try:
            return self.cls.from_dict_unchecked(values, set_fields=set_fields)
        except Exception:  # error in __post_init__
            raise ParseInterrupt()

    def collect_errors_struct(self, val: t.Mapping[str, t.Any]) -> t.Union[WrongTypeError, ProductErrorNode, None]:
        """[`Converter.collect_errors`][pane.converters.Converter.collect_errors] for the 'struct' data format"""
        values: t.Dict[str, t.Any] = {}  # converted field values. Required to check for __post_init__ errors
        children: t.Dict[t.Union[str, int], ErrorNode] = {}  # errors in converting fields
        extra: t.Set[str] = set()  # extra fields found
        seen: t.Set[str] = set()   # fields seen already (used to find dupes)
        for (k, v) in val.items():
            if k not in self.field_map:
                if not self.opts.allow_extra:
                    extra.add(k)  # unknown key
                continue

            field = self.fields[self.field_map[k]]
            conv = self.field_converters[self.field_map[k]]
            if field.name in seen:
                children[k] = DuplicateKeyError(k, field.in_names)
                continue
            seen.add(field.name)

            # this is a little tricky. we need to call convert() rather
            # than collect_errors to grab a successful value
            try:
                values[field.name] = conv.convert(v)
            except ConvertError as e:
                # then we can collect errors if that fails.
                children[k] = e.tree

        missing: t.Set[str] = set()
        for field in self.fields:
            if field.init and field.name not in seen and not field.has_default():
                missing.add(field.name)

        if len(missing) or len(children) or len(extra):
            # return field errors
            return ProductErrorNode(self.expected_struct(), children, val, missing, extra)
        try:
            self.cls.make_unchecked(**values)
            return None
        except Exception as e:  # error in __post_init__
            tb = e.__traceback__.tb_next  # type: ignore
            tb = traceback.TracebackException(type(e), e, tb)
            return WrongTypeError(f'struct {self.name}', val, tb)

    def expected_tuple(self, plural: bool = False) -> str:
        """Expected value for the 'tuple' data format"""
        return f"tuple {self.name}"

    def try_convert_tuple(self, val: t.Sequence[t.Any]) -> PaneBaseT:
        """[`Converter.try_convert`][pane.converters.Converter.try_convert] for the 'tuple' data format"""
        (min_len, max_len) = self.cls_info.pos_args
        if not (min_len <= len(val) <= max_len):
            raise ParseInterrupt()

        vals: t.List[t.Any] = []
        for (conv, v) in zip((conv for (f, conv) in zip(self.fields, self.field_converters) if f.init), val):
            vals.append(conv.try_convert(v))

        try:
            return self.cls.make_unchecked(*vals)
        except Exception:  # error in __post_init__
            raise ParseInterrupt()

    def collect_errors_tuple(self, val: t.Sequence[t.Any]) -> t.Union[WrongTypeError, ProductErrorNode, WrongLenError, None]:
        """[`Converter.collect_errors`][pane.converters.Converter.collect_errors] for the 'tuple' data format"""
        (min_len, max_len) = self.cls_info.pos_args
        if not (min_len <= len(val) <= max_len):
            return WrongLenError(f'tuple {self.name}', (min_len, max_len), val, len(val))

        vals: t.List[t.Any] = []
        children: t.Dict[t.Union[str, int], ErrorNode] = {}
        for (i, (conv, v)) in enumerate(zip((conv for (f, conv) in zip(self.fields, self.field_converters) if f.init), val)):
            # this is a little tricky. we need to call convert() rather
            # than collect_errors to grab a successful value
            try:
                vals.append(conv.convert(v))
            except ConvertError as e:
                # then we can collect errors if that fails.
                children[i] = e.tree

        if len(children):
            # return field errors
            return ProductErrorNode(self.expected_tuple(), children, val)

        try:
            self.cls.make_unchecked(*vals)
            return None
        except Exception as e:  # error in __post_init__
            tb = e.__traceback__.tb_next  # type: ignore
            tb = traceback.TracebackException(type(e), e, tb)
            return WrongTypeError(f'tuple {self.name}', val, tb)

cls = cls instance-attribute

name = self.cls.__name__ instance-attribute

cls_info = getattr(self.cls, PANE_INFO) instance-attribute

opts = self.cls_info.opts instance-attribute

fields = self.cls_info.fields instance-attribute

field_converters = [field.converter if field.converter is not None else make_converter(field.type, handlers) for field in self.fields] instance-attribute

field_map = {} instance-attribute

convert(val)

Convert val to T_co. Raises a ConvertError on failure.

Source code in pane/converters.py
def convert(self, val: t.Any) -> T_co:
    """Convert ``val`` to ``T_co``. Raises a ``ConvertError`` on failure."""
    try:
        return self.try_convert(val)
    except ParseInterrupt:
        pass
    node = self.collect_errors(val)
    if node is None:
        raise RuntimeError("convert() raised but ``collect_errors`` returned ``None``."
                           " This is a bug of the ``Converter`` implementation.")
    raise ConvertError(node)

into_data(val)

Convert dataclass val into data interchange, using the correct 'out_format'

Source code in pane/classes.py
def into_data(self, val: t.Any) -> DataType:
    """Convert dataclass `val` into data interchange, using the correct 'out_format'"""
    assert isinstance(val, PaneBase)
    if self.opts.out_format == 'tuple':
        return tuple(
            conv.into_data(getattr(val, field.name))
            for (field, conv) in zip(self.fields, self.field_converters)
            if not field.exclude
        )
    elif self.opts.out_format == 'struct':
        return {
            field.out_name: conv.into_data(getattr(val, field.name))
            for (field, conv) in zip(self.fields, self.field_converters)
            if not field.exclude
        }
    raise ValueError(f"Unknown 'out_format' '{self.opts.out_format}'")

expected(plural=False)

Expected value for this converter

Source code in pane/classes.py
def expected(self, plural: bool = False) -> str:
    """Expected value for this converter"""
    return f"{list_phrase(self.opts.in_format)} {self.name}"

try_convert(val)

See Converter.try_convert

Dispatches to try_convert_tuple and try_convert_struct

Source code in pane/classes.py
def try_convert(self, val: t.Any) -> PaneBaseT:
    """
    See [`Converter.try_convert`][pane.converters.Converter.try_convert]

    Dispatches to [`try_convert_tuple`][pane.classes.PaneConverter.try_convert_tuple]
    and [`try_convert_struct`][pane.classes.PaneConverter.try_convert_struct]
    """
    # based on type, try to delegate to try_convert_tuple or try_convert_struct
    if isinstance(val, (list, tuple, t.Sequence)):
        val = t.cast(t.Sequence[t.Any], val)
        if 'tuple' not in self.opts.in_format:
            raise ParseInterrupt()

        return self.try_convert_tuple(t.cast(t.Sequence[t.Any], val))

    elif isinstance(val, (dict, t.Mapping)):
        if 'struct' not in self.opts.in_format:
            raise ParseInterrupt()

        return self.try_convert_struct(t.cast(t.Mapping[str, t.Any], val))

    raise ParseInterrupt()

collect_errors(val)

See Converter.collect_errors

Dispatches to collect_errors_tuple and collect_errors_struct

Source code in pane/classes.py
def collect_errors(self, val: t.Any) -> t.Union[WrongTypeError, WrongLenError, ProductErrorNode, None]:
    """
    See [`Converter.collect_errors`][pane.converters.Converter.collect_errors]

    Dispatches to [`collect_errors_tuple`][pane.classes.PaneConverter.collect_errors_tuple]
    and [`collect_errors_struct`][pane.classes.PaneConverter.collect_errors_struct]
    """
    # based on type, try to delegate to collect_errors_tuple or collect_errors_struct
    if isinstance(val, (list, tuple, t.Sequence)):
        if 'tuple' not in self.opts.in_format:
            return WrongTypeError(self.expected_struct(), val)

        return self.collect_errors_tuple(t.cast(t.Sequence[t.Any], val))

    elif isinstance(val, (dict, t.Mapping)):
        val = t.cast(t.Mapping[str, t.Any], val)
        if 'struct' not in self.opts.in_format:
            return WrongTypeError(f'tuple {self.name}', val)

        return self.collect_errors_struct(t.cast(t.Mapping[str, t.Any], val))

    return WrongTypeError(self.name, val)

expected_struct(plural=False)

Expected value for the 'struct' data format

Source code in pane/classes.py
def expected_struct(self, plural: bool = False) -> str:
    """Expected value for the 'struct' data format"""
    return f"struct {self.name}"

try_convert_struct(val)

Converter.try_convert for the 'struct' data format

Source code in pane/classes.py
def try_convert_struct(self, val: t.Mapping[str, t.Any]) -> PaneBaseT:
    """[`Converter.try_convert`][pane.converters.Converter.try_convert] for the 'struct' data format"""
    # loop through values, and handle accordingly
    values: t.Dict[str, t.Any] = {}
    for (k, v) in t.cast(t.Dict[str, t.Any], val).items():
        if k not in self.field_map:
            if not self.opts.allow_extra:
                raise ParseInterrupt()  # extra key
            continue
        field = self.fields[self.field_map[k]]
        conv = self.field_converters[self.field_map[k]]

        if field.name in values:
            raise ParseInterrupt()  # multiple values for key
        values[field.name] = conv.try_convert(v)

    set_fields = set(values.keys())

    for field in filter(lambda field: field.init and field.name not in values, self.fields):
        if field.default is not _MISSING:
            values[field.name] = field.default
        elif field.default_factory is not None:
            values[field.name] = field.default_factory
        else:
            raise ParseInterrupt()  # missing field

    try:
        return self.cls.from_dict_unchecked(values, set_fields=set_fields)
    except Exception:  # error in __post_init__
        raise ParseInterrupt()

collect_errors_struct(val)

Converter.collect_errors for the 'struct' data format

Source code in pane/classes.py
def collect_errors_struct(self, val: t.Mapping[str, t.Any]) -> t.Union[WrongTypeError, ProductErrorNode, None]:
    """[`Converter.collect_errors`][pane.converters.Converter.collect_errors] for the 'struct' data format"""
    values: t.Dict[str, t.Any] = {}  # converted field values. Required to check for __post_init__ errors
    children: t.Dict[t.Union[str, int], ErrorNode] = {}  # errors in converting fields
    extra: t.Set[str] = set()  # extra fields found
    seen: t.Set[str] = set()   # fields seen already (used to find dupes)
    for (k, v) in val.items():
        if k not in self.field_map:
            if not self.opts.allow_extra:
                extra.add(k)  # unknown key
            continue

        field = self.fields[self.field_map[k]]
        conv = self.field_converters[self.field_map[k]]
        if field.name in seen:
            children[k] = DuplicateKeyError(k, field.in_names)
            continue
        seen.add(field.name)

        # this is a little tricky. we need to call convert() rather
        # than collect_errors to grab a successful value
        try:
            values[field.name] = conv.convert(v)
        except ConvertError as e:
            # then we can collect errors if that fails.
            children[k] = e.tree

    missing: t.Set[str] = set()
    for field in self.fields:
        if field.init and field.name not in seen and not field.has_default():
            missing.add(field.name)

    if len(missing) or len(children) or len(extra):
        # return field errors
        return ProductErrorNode(self.expected_struct(), children, val, missing, extra)
    try:
        self.cls.make_unchecked(**values)
        return None
    except Exception as e:  # error in __post_init__
        tb = e.__traceback__.tb_next  # type: ignore
        tb = traceback.TracebackException(type(e), e, tb)
        return WrongTypeError(f'struct {self.name}', val, tb)

expected_tuple(plural=False)

Expected value for the 'tuple' data format

Source code in pane/classes.py
def expected_tuple(self, plural: bool = False) -> str:
    """Expected value for the 'tuple' data format"""
    return f"tuple {self.name}"

try_convert_tuple(val)

Converter.try_convert for the 'tuple' data format

Source code in pane/classes.py
def try_convert_tuple(self, val: t.Sequence[t.Any]) -> PaneBaseT:
    """[`Converter.try_convert`][pane.converters.Converter.try_convert] for the 'tuple' data format"""
    (min_len, max_len) = self.cls_info.pos_args
    if not (min_len <= len(val) <= max_len):
        raise ParseInterrupt()

    vals: t.List[t.Any] = []
    for (conv, v) in zip((conv for (f, conv) in zip(self.fields, self.field_converters) if f.init), val):
        vals.append(conv.try_convert(v))

    try:
        return self.cls.make_unchecked(*vals)
    except Exception:  # error in __post_init__
        raise ParseInterrupt()

collect_errors_tuple(val)

Converter.collect_errors for the 'tuple' data format

Source code in pane/classes.py
def collect_errors_tuple(self, val: t.Sequence[t.Any]) -> t.Union[WrongTypeError, ProductErrorNode, WrongLenError, None]:
    """[`Converter.collect_errors`][pane.converters.Converter.collect_errors] for the 'tuple' data format"""
    (min_len, max_len) = self.cls_info.pos_args
    if not (min_len <= len(val) <= max_len):
        return WrongLenError(f'tuple {self.name}', (min_len, max_len), val, len(val))

    vals: t.List[t.Any] = []
    children: t.Dict[t.Union[str, int], ErrorNode] = {}
    for (i, (conv, v)) in enumerate(zip((conv for (f, conv) in zip(self.fields, self.field_converters) if f.init), val)):
        # this is a little tricky. we need to call convert() rather
        # than collect_errors to grab a successful value
        try:
            vals.append(conv.convert(v))
        except ConvertError as e:
            # then we can collect errors if that fails.
            children[i] = e.tree

    if len(children):
        # return field errors
        return ProductErrorNode(self.expected_tuple(), children, val)

    try:
        self.cls.make_unchecked(*vals)
        return None
    except Exception as e:  # error in __post_init__
        tb = e.__traceback__.tb_next  # type: ignore
        tb = traceback.TracebackException(type(e), e, tb)
        return WrongTypeError(f'tuple {self.name}', val, tb)

field(*, rename=None, in_names=None, aliases=None, out_name=None, init=True, exclude=False, repr=True, hash=None, compare=True, default=_MISSING, default_factory=None, kw_only=False, converter=None)

field(*, rename: t.Optional[str] = None, in_names: None = None, aliases: None = None, out_name: t.Optional[str] = None, init: bool = True, exclude: bool = False, repr: bool = True, hash: t.Optional[bool] = None, compare: bool = True, default: t.Union[T, _Missing] = _MISSING, default_factory: t.Optional[t.Callable[[], T]] = None, kw_only: bool = False, converter: t.Optional[Converter[T]] = None) -> t.Any
field(*, rename: None = None, in_names: t.Sequence[str], aliases: None = None, out_name: t.Optional[str] = None, init: bool = True, exclude: bool = False, repr: bool = True, hash: t.Optional[bool] = None, compare: bool = True, default: t.Union[T, _Missing] = _MISSING, default_factory: t.Optional[t.Callable[[], T]] = None, kw_only: bool = False, converter: t.Optional[Converter[T]] = None) -> t.Any
field(*, rename: None = None, in_names: None = None, aliases: t.Sequence[str], out_name: t.Optional[str] = None, init: bool = True, exclude: bool = False, repr: bool = True, hash: t.Optional[bool] = None, compare: bool = True, default: t.Union[T, _Missing] = _MISSING, default_factory: t.Optional[t.Callable[[], T]] = None, kw_only: bool = False, converter: t.Optional[Converter[T]] = None) -> t.Any
field(*, rename: t.Optional[str] = None, in_names: t.Optional[t.Sequence[str]] = None, aliases: t.Optional[t.Sequence[str]] = None, out_name: t.Optional[str] = None, init: bool = True, exclude: bool = False, repr: bool = True, hash: t.Optional[bool] = None, compare: bool = True, default: t.Union[T, _Missing] = _MISSING, default_factory: t.Optional[t.Callable[[], T]] = None, kw_only: bool = False, converter: t.Optional[Converter[T]] = None) -> t.Any

Annotate a dataclass field.

Parameters:

Name Type Description Default
rename Optional[str]

Name to rename this field as. Used for both input and output. Useful when a field name should be different inside vs. outside of Python.

None
in_names Optional[Sequence[str]]

List of names which should convert into this field. If specified, the field name inside Python will be excluded (unlike aliases).

None
aliases Optional[Sequence[str]]

List of aliases (additional names) for this field. Includes the field name inside Python (unlike in_names).

None
out_name Optional[str]

Name which this field should convert into.

None
init bool

If False, this field won't be touched by pane, and it's up to the class to initialize it in __post_init__.

True
exclude bool

If False, this field is excluded from serialization and conversion to other datatypes (into_data, dict, write_json, etc.).

False
repr bool

Whether to include this field in the generated repr method.

True
hash Optional[bool]

Whether to include this field in the generated hash method. Defaults to compare.

None
compare bool

Whether to include this field in generated comparison methods (__eq__, __gt__, etc.).

True
default Union[T, _Missing]

Default value for field

_MISSING
default_factory Optional[Callable[[], T]]

Default value factory for field

None
kw_only bool

Whether the field is keyword-only.

False
Source code in pane/field.py
def field(*,
    rename: t.Optional[str] = None,
    in_names: t.Optional[t.Sequence[str]] = None,
    aliases: t.Optional[t.Sequence[str]] = None,
    out_name: t.Optional[str] = None,
    init: bool = True,
    exclude: bool = False,
    repr: bool = True,
    hash: t.Optional[bool] = None,
    compare: bool = True,
    default: t.Union[T, _Missing] = _MISSING,
    default_factory: t.Optional[t.Callable[[], T]] = None,
    kw_only: bool = False,
    converter: t.Optional[Converter[T]] = None,
) -> t.Any:
    """
    Annotate a dataclass field.

    Parameters:
      rename: Name to rename this field as. Used for both input and output. Useful when a field name should be different inside vs. outside of Python.
      in_names: List of names which should convert into this field. If specified, the field name inside Python will be excluded (unlike `aliases`).
      aliases: List of aliases (additional names) for this field. Includes the field name inside Python (unlike `in_names`).
      out_name: Name which this field should convert into.
      init: If `False`, this field won't be touched by `pane`, and it's up to the class to initialize it in `__post_init__`.
      exclude: If `False`, this field is excluded from serialization and conversion to other datatypes (into_data, dict, write_json, etc.).
      repr: Whether to include this field in the generated __repr__ method.
      hash: Whether to include this field in the generated __hash__ method. Defaults to `compare`.
      compare: Whether to include this field in generated comparison methods (`__eq__`, `__gt__`, etc.).
      default: Default value for field
      default_factory: Default value factory for field
      kw_only: Whether the field is keyword-only.
    """
    return FieldSpec(
        rename=rename, in_names=in_names, aliases=aliases, out_name=out_name,
        init=init, repr=repr, hash=hash if hash is not None else compare, compare=compare,
        exclude=exclude, default=default, default_factory=default_factory,
        kw_only=kw_only, converter=converter
    )