dataspecs package#

class Path(*segments: str | PathLike[str])[source]#

Bases: PurePosixPath

Path for data specs.

It is based on PurePosixPath, however, the differences are a path must start with the root (/) and the match method full-matches a regular expression.

Parameters:

*segments (str | PathLike[str]) – Segments to create a path.

Raises:

ValueError – Raised if it does not start with the root.

Return type:

Self

property children: Self#

Return the regular expression that matches the child paths.

property descendants: Self#

Return the regular expression that matches the descendant paths.

property regex: Self#

Return the regular expression that matches the path itself.

match(pattern: str | PathLike[str], /) bool[source]#

Check if the path full-matches a regular expression.

Parameters:

pattern (str | PathLike[str])

Return type:

bool

class Spec(path: ~dataspecs.core.specs.Path, name: ~typing.Hashable, tags: tuple[~dataspecs.core.typing.TagBase, ...], type: ~typing.Any, data: ~dataspecs.core.typing.TAny, anns: tuple[~typing.Any, ...] = <factory>, meta: dict[str, ~typing.Any] = <factory>, orig: ~typing.Any | None = None)[source]#

Bases: Generic[TAny]

Data specification (data spec).

Parameters:
  • path (Path) – Path of the data spec.

  • name (Hashable) – Name of the data spec.

  • tags (tuple[TagBase, ...]) – Tags of the data spec.

  • type (Any) – Type hint (unannotated) of the data spec.

  • data (TAny) – Default or final data of the data spec.

  • anns (tuple[Any, ...]) – Type hint annotations of the data spec.

  • meta (dict[str, Any]) – Metadata of the data spec.

  • orig (Any | None) – Origin of the data spec.

path: Path#

Path of the data spec.

name: Hashable#

Name of the data spec.

tags: tuple[TagBase, ...]#

Tags of the data spec.

type: Any#

Type hint (unannotated) of the data spec.

data: TAny#

Default or final data of the data spec.

anns: tuple[Any, ...]#

Type hint annotations of the data spec.

meta: dict[str, Any]#

Metadata of the data spec.

orig: Any | None = None#

Origin of the data spec.

__call__(type: Callable[[...], UAny], /) Spec[UAny][source]#

Dynamically cast the data of the data spec.

Parameters:

type (Callable[[...], UAny])

Return type:

Spec[UAny]

__getitem__(type: Callable[[...], UAny], /) Spec[UAny][source]#

Statically cast the data of the data spec.

Parameters:

type (Callable[[...], UAny])

Return type:

Spec[UAny]

class Specs(initlist=None)[source]#

Bases: UserList[TSpec]

Data specifications (data specs).

property first: TSpec | None#

Return the first data spec if it exists (None otherwise).

property last: TSpec | None#

Return the last data spec if it exists (None otherwise).

property unique: TSpec | None#

Return the data spec if it is unique (None otherwise).

groupby(attr: Literal['path', 'name', 'tags', 'type', 'data', 'anns', 'meta', 'orig'], /, *, method: Literal['eq', 'equality', 'id', 'identity'] = 'equality') list[Self][source]#

Group the data specs by their attributes.

Parameters:
  • attr (Literal['path', 'name', 'tags', 'type', 'data', 'anns', 'meta', 'orig']) – Name of the data spec attribute for grouping. Either 'path', 'name', 'tags', 'type', 'data', 'anns', 'meta', or 'orig' is accepted.

  • method (Literal['eq', 'equality', 'id', 'identity']) – Grouping method. Either 'equality' (or 'eq'; hash-based grouping), or 'identity' (or 'id'; id-based grouping) is accepted.

Returns:

List of data specs grouped by the selected data spec attribute.

Return type:

list[Self]

replace(old: TSpec, new: TSpec, /) Self[source]#

Return data specs with old data spec replaced by new one.

Parameters:
  • old (TSpec)

  • new (TSpec)

Return type:

Self

__call__(index: None | str | PathLike[str] | TagBase | type[Any] | slice | SupportsIndex, /) Self[source]#

Select data specs by given index.

Unlike __getitem__, it always returns data specs, even when given index selects a single data spec.

Parameters:

index (None | str | PathLike[str] | TagBase | type[Any] | slice | SupportsIndex) – Normal or extended index for the selection of the data specs.

Returns:

Selected data specs by given index.

Return type:

Self

__getitem__(index: None, /) Self[source]#
__getitem__(index: str | PathLike[str], /) Self
__getitem__(index: TagBase, /) Self
__getitem__(index: type[Any], /) Self
__getitem__(index: slice, /) Self
__getitem__(index: SupportsIndex, /) TSpec

Select data specs by given index.

In addition to a normal index (i.e. slice or __index__-implemented object), it also accepts the following extended index for the advanced selection: (1) None to select all data specs (i.e. shallow copy), (2) a string path to select data specs that match it, (3) a tag to select data specs that contain it, (4) a tag type to select data specs that contain its tags, or (5) an any type to select data specs that contain it.

Parameters:

index – Normal or extended index for the selection of the data specs.

Returns:

Selected data spec(s) by given index.

class TagBase(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]#

Bases: Enum

Base enum of tag for data specs.

Since TagBase itself does not have any members, users should create their own tags by inheriting it:

from enum import auto
from dataspecs import TagBase

class Tag(TagBase):
    ATTR = auto()
    DATA = auto()
    NAME = auto()
from_dataclass(obj: ~dataspecs.core.typing.DataClassObject | type[~dataspecs.core.typing.DataClassObject], /, *, factory: ~typing.Any = <class 'dataspecs.core.specs.Spec'>, path: str | ~os.PathLike[str] = Path('/')) Any[source]#

Create data specs from a dataclass (object).

Parameters:
  • obj (DataClassObject | type[DataClassObject]) – Dataclass (object) to be parsed.

  • factory (Any) – Factory for creating each data spec.

  • path (str | PathLike[str]) – Path of the parent data spec.

Returns:

Data specs created from the dataclass (object).

Return type:

Any

Examples

from enum import auto
from dataclasses import dataclass
from dataspecs import TagBase, from_dataclass
from typing import Annotated as Ann

class Tag(TagBase):
    ATTR = auto()
    DATA = auto()
    DTYPE = auto()

@dataclass
class Weather:
    temp: Ann[list[Ann[float, Tag.DTYPE]], Tag.DATA]
    humid: Ann[list[Ann[float, Tag.DTYPE]], Tag.DATA]
    location: Ann[str, Tag.ATTR]

from_dataclass(Weather([20.0, 25.0], [50.0, 55.0], "Tokyo"))
Specs([
    Spec(
        path=Path('/temp'),
        tags=(<Tag.DATA: 2>,),
        type=list[float],
        data=[20.0, 25.0],
    ),
    Spec(
        path=Path('/temp/0'),
        tags=(<Tag.DTYPE: 3>,),
        type=<class 'float'>,
        data=None,
    ),
    Spec(
        path=Path('/humid'),
        tags=(<Tag.DATA: 2>,),
        type=list[float],
        data=[50.0, 55.0],
    ),
    Spec(
        path=Path('/humid/0'),
        tags=(<Tag.DTYPE: 3>,),
        type=<class 'float'>,
        data=None,
    ),
    Spec(
        path=Path('/location'),
        tags=(<Tag.ATTR: 1>,),
        type=<class 'str'>,
        data='Tokyo',
    ),
])
from_typehint(obj: ~typing.Any, /, *, factory: ~typing.Any = <class 'dataspecs.core.specs.Spec'>, path: str | ~os.PathLike[str] = Path('/'), data: ~typing.Any = None, meta: dict[str, ~typing.Any] | None = None, orig: ~typing.Any | None = None) Any[source]#

Create data specs from a type hint.

Parameters:
  • obj (Any) – Type hint to be parsed.

  • factory (Any) – Factory for creating each data spec.

  • path (str | PathLike[str]) – Path of the parent data spec.

  • data (Any) – Data of the parent data spec.

  • meta (dict[str, Any] | None) – Metadata of the parent data spec.

  • orig (Any | None) – Origin of the parent data spec.

Returns:

Data specs created from the type hint.

Return type:

Any

Examples

from enum import auto
from dataspecs import TagBase, from_typehint
from typing import Annotated as Ann

class Tag(TagBase):
    DATA = auto()
    DTYPE = auto()

from_typehint(Ann[list[Ann[float, Tag.DTYPE]], Tag.DATA])
Specs([
    Spec(
        path=Path('/'),
        tags=(<Tag.DATA: 1>,),
        type=list[float],
        data=None,
    ),
    Spec(
        path=Path('/0'),
        tags=(<Tag.DTYPE: 2>,),
        type=<class 'float'>,
        data=None,
    ),
])
class Format(_format_index: ~typing.Annotated[None | str | ~os.PathLike[str] | ~dataspecs.core.typing.TagBase | type[~typing.Any] | slice | ~typing.SupportsIndex, <FormatTag.INDEX: 2>], _format_attr: ~typing.Annotated[~typing.Literal['path', 'name', 'tags', 'type', 'data', 'anns', 'meta', 'orig'], <FormatTag.ATTR: 1>] = 'data', _format_skipif: ~typing.Annotated[~typing.Any, <FormatTag.SKIPIF: 3>] = None)[source]#

Bases: object

Annotation for formatter specs.

Parameters:
  • _format_index (Annotated[None | str | PathLike[str] | TagBase | type[Any] | slice | SupportsIndex, <FormatTag.INDEX: 2>]) – Index of data spec(s) to be formatted.

  • _format_attr (Annotated[Literal['path', 'name', 'tags', 'type', 'data', 'anns', 'meta', 'orig'], <FormatTag.ATTR: 1>]) – Name of data spec attribute to be formatted.

  • _format_skipif (Annotated[Any, <FormatTag.SKIPIF: 3>]) – Sentinel value for which formatting is skipped.

class FormatTag(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]#

Bases: TagBase

Collection of tags for formatter specs.

ATTR = 1#

Tag for name of data spec attribute to be formatted.

INDEX = 2#

Tag for index of data spec(s) to be formatted.

SKIPIF = 3#

Tag for sentinel value for which formatting is skipped.

class Name(_name: ~typing.Annotated[~collections.abc.Hashable, <NameTag.NAME: 1>])[source]#

Bases: object

Annotation for namer specs.

Parameters:

_name (Annotated[Hashable, <NameTag.NAME: 1>]) – New name of the data spec to be replaced.

class NameTag(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]#

Bases: TagBase

Collection of tags for namer specs.

NAME = 1#

Tag for new name of the data spec to be replaced.

class Replace(_replace_index: ~typing.Annotated[None | str | ~os.PathLike[str] | ~dataspecs.core.typing.TagBase | type[~typing.Any] | slice | ~typing.SupportsIndex, <ReplaceTag.INDEX: 2>], _replace_attr: ~typing.Annotated[~typing.Literal['path', 'name', 'tags', 'type', 'data', 'anns', 'meta', 'orig'], <ReplaceTag.ATTR: 1>] = 'data', _replace_skipif: ~typing.Annotated[~typing.Any, <ReplaceTag.SKIPIF: 3>] = None)[source]#

Bases: object

Annotation for replacer specs.

Parameters:
  • _replace_index (Annotated[None | str | PathLike[str] | TagBase | type[Any] | slice | SupportsIndex, <ReplaceTag.INDEX: 2>]) – Index of data spec(s) to be replaced.

  • _replace_attr (Annotated[Literal['path', 'name', 'tags', 'type', 'data', 'anns', 'meta', 'orig'], <ReplaceTag.ATTR: 1>]) – Name of data spec attribute to be replaced.

  • _replace_skipif (Annotated[Any, <ReplaceTag.SKIPIF: 3>]) – Sentinel value for which replacing is skipped.

class ReplaceTag(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]#

Bases: TagBase

Collection of tags for replacer specs.

ATTR = 1#

Tag for name of data spec attribute to be replaced.

INDEX = 2#

Tag for index of data spec(s) to be replaced.

SKIPIF = 3#

Tag for sentinel value for which replacing is skipped.

format(specs: Specs[TSpec], /, *, leave: bool = False) Specs[TSpec][source]#

Format data spec attributes by formatter specs.

Parameters:
  • specs (Specs[TSpec]) – Input data specs.

  • leave (bool) – Whether to leave the formatter specs.

Returns:

Data specs whose attributes are formatted.

Return type:

Specs[TSpec]

Examples

from enum import auto
from dataclasses import dataclass
from dataspecs import TagBase, Format, from_dataclass, format
from typing import Annotated as Ann

class Tag(TagBase):
    ATTR = auto()

@dataclass
class Attrs:
    name: Ann[str, Tag.ATTR]
    units: Ann[str, Tag.ATTR]

@dataclass
class Weather:
    temp: Ann[list[float], Attrs("Temperature ({0})", "{0}")]
    units: Ann[str, Format("/temp/(name|units)")] = "degC"

format(from_dataclass(Weather([20.0, 25.0], "K")))
Specs([
    Spec(
        path=Path('/temp'),
        name='temp',
        tags=(),
        type=list[float],
        data=[20.0, 25.0],
    ),
    Spec(
        path=Path('/temp/0'),
        name='0',
        tags=(),
        type=<class 'float'>,
        data=None,
    ),
    Spec(
        path=Path('/temp/name'),
        name='name',
        tags=(<Tag.ATTR: 1>,),
        type=<class 'str'>,
        data='Temperature (K)', # <- formatted
    ),
    Spec(
        path=Path('/temp/units'),
        name='units',
        tags=(<Tag.ATTR: 1>,),
        type=<class 'str'>, data='K', # <- formatted
    ),
    Spec(
        path=Path('/units'),
        name='units',
        tags=(),
        type=<class 'str'>,
        data='K',
    ),
])
name(specs: Specs[TSpec], /, *, leave: bool = False) Specs[TSpec][source]#

Replace data spec names by corresponding namer specs.

Parameters:
  • specs (Specs[TSpec]) – Input data specs.

  • leave (bool) – Whether to leave the namer specs.

Returns:

Data specs whose names are replaced.

Return type:

Specs[TSpec]

Examples

from dataclasses import dataclass
from dataspecs import Name, name, from_dataclass
from typing import Annotated as Ann

@dataclass
class Weather:
    temp: Ann[float, Name("Ground temperature")]
    humid: Ann[float, Name("Relative humidity")]

name(from_dataclass(Weather(20.0, 50.0)))
Specs([
    Spec(
        path=Path('/temp'),
        name='Ground temperature', # <- named
        tags=(),
        type=<class 'float'>,
        data=20.0,
    ),
    Spec(
        path=Path('/humid'), # <- named
        name='Relative humidity',
        tags=(),
        type=<class 'float'>,
        data=50.0,
    ),
])
replace(specs: Specs[TSpec], /, *, leave: bool = False) Specs[TSpec][source]#

Replace data spec attributes by replacer specs.

Parameters:
  • specs (Specs[TSpec]) – Input data specs.

  • leave (bool) – Whether to leave the replacer specs.

Returns:

Data specs whose attributes are replaced.

Return type:

Specs[TSpec]

Examples

from enum import auto
from dataclasses import dataclass
from dataspecs import Replace, TagBase, from_dataclass, replace
from typing import Annotated as Ann

class Tag(TagBase):
    ATTR = auto()
    DATA = auto()
    DTYPE = auto()

@dataclass
class Weather:
    temp: Ann[list[Ann[float, Tag.DTYPE]], Tag.DATA]
    humid: Ann[list[Ann[float, Tag.DTYPE]], Tag.DATA]
    dtype: Ann[type, Replace("/[a-z]+/0", "type")] = None

replace(from_dataclass(Weather([20.0, 25.0], [50.0, 55.0], int)))
Specs([
    Spec(
        path=Path('/temp'),
        name='temp',
        tags=(<Tag.DATA: 2>,),
        type=list[float],
        data=[20.0, 25.0],
    ),
    Spec(
        path=Path('/temp/0'),
        name='0',
        tags=(<Tag.DTYPE: 3>,),
        type=<class 'int'>, # <- replaced
        data=None,
    ),
    Spec(
        path=Path('/humid'),
        name='humid',
        tags=(<Tag.DATA: 2>,),
        type=list[float],
        data=[50.0, 55.0],
    ),
    Spec(
        path=Path('/humid/0'),
        name='0',
        tags=(<Tag.DTYPE: 3>,),
        type=<class 'int'>, # <- replaced
        data=None,
    ),
    Spec(
        path=Path('/dtype'),
        name='dtype',
        tags=(),
        type=<class 'type'>,
        data=<class 'int'>,
    ),
])

Subpackages#