dataspecs#
Data specifications by data classes
Installation#
pip install dataspecs
Basic usage#
Simple specifications#
@dataclass
class Weather:
temp: list[float]
humid: list[float]
location: str
specs = from_dataclass(Weather([20.0, 25.0], [50.0, 55.0], "Tokyo"))
print(specs)
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('/humid'), name='humid', tags=(), type=list[float], data=[50.0, 55.0]),
Spec(path=Path('/humid/0'), name='0', tags=(), type=<class 'float'>, data=None),
Spec(path=Path('/location'), name='location', tags=(), type=<class 'str'>, data='Tokyo'),
])
Selecting specifications#
specs[Tag.DATA]
Specs([
Spec(path=Path('/temp'), name='temp', tags=(<Tag.DATA: 2>,), type=list[float], data=[20.0, 25.0]),
Spec(path=Path('/humid'), name='humid', tags=(<Tag.DATA: 2>,), type=list[float], data=[50.0, 55.0]),
])
specs[Tag]
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 'float'>, data=None),
Spec(path=Path('/temp/units'), name='units', tags=(<Tag.ATTR: 1>,), type=<class 'str'>, data='K'),
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 'float'>, data=None),
Spec(path=Path('/humid/units'), name='units', tags=(<Tag.ATTR: 1>,), type=<class 'str'>, data='%'),
])
specs[str]
Specs([
Spec(path=Path('/temp/units'), name='units', tags=(<Tag.ATTR: 1>,), type=<class 'str'>, data='K'),
Spec(path=Path('/humid/units'), name='units', tags=(<Tag.ATTR: 1>,), type=<class 'str'>, data='%'),
Spec(path=Path('/location'), name='location', tags=(), type=<class 'str'>, data='Tokyo'),
])
specs["/temp/[a-z]+"]
Specs([
Spec(path=Path('/temp/units'), name='units', tags=(<Tag.ATTR: 1>,), type=<class 'str'>, data='K'),
])
Grouping specifications#
specs.groupby("tags")
[
Specs([
Spec(path=Path('/temp'), name='temp', tags=(<Tag.DATA: 2>,), type=list[float], data=[20.0, 25.0]),
Spec(path=Path('/humid'), name='humid', tags=(<Tag.DATA: 2>,), type=list[float], data=[50.0, 55.0]),
]),
Specs([
Spec(path=Path('/temp/0'), name='0', tags=(<Tag.DTYPE: 3>,), type=<class 'float'>, data=None),
Spec(path=Path('/humid/0'), name='0', tags=(<Tag.DTYPE: 3>,), type=<class 'float'>, data=None),
]),
Specs([
Spec(path=Path('/temp/units'), name='units', tags=(<Tag.ATTR: 1>,), type=<class 'str'>, data='K'),
Spec(path=Path('/humid/units'), name='units', tags=(<Tag.ATTR: 1>,), type=<class 'str'>, data='%'),
]),
Specs([
Spec(path=Path('/location'), name='location', tags=(), type=<class 'str'>, data='Tokyo'),
]),
]
Advanced usage#
Formatting specifications#
from dataspecs import Format, format
@dataclass
class Meta:
units: Ann[str, Tag.ATTR]
@dataclass
class Weather:
temp: Ann[float, Meta("{0}")]
humid: Ann[float, Meta("{0}")]
temp_units: Ann[str, Format("/temp/units")]
humid_units: Ann[str, Format("/humid/units")]
format(from_dataclass(Weather(20.0, 50.0, "K", "%")))
Specs([
Spec(path=Path('/temp'), name='temp', tags=(), type=<class 'float'>, data=20.0),
Spec(path=Path('/temp/units'), name='units', tags=(<Tag.ATTR: 1>,), type=<class 'str'>, data='K'), # <- data formatted
Spec(path=Path('/humid'), name='humid', tags=(), type=<class 'float'>, data=55.0),
Spec(path=Path('/humid/units'), name='units', tags=(<Tag.ATTR: 1>,), type=<class 'str'>, data='%'), # <- data formatted
Spec(path=Path('/temp_units'), name='temp_units', tags=(), type=<class 'str'>, data='K'),
Spec(path=Path('/humid_units'), name='humid_units', tags=(), type=<class 'str'>, data='%'),
])
Naming specifications#
from dataspecs import Name, name
@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', tags=(), type=<class 'float'>, data=20.0), # <- name replaced
Spec(path=Path('/humid'), name='Relative humidity', tags=(), type=<class 'float'>, data=50.0), # <- name replaced
])
Replacing specifications#
from dataspecs import Replace, replace
@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")]
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'>, data=None), # <- type replaced
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'>, data=None), # <- type replaced
Spec(path=Path('/dtype'), name='dtype', tags=(), type=<class 'type'>, data=<class 'int'>),
])
Specification rules#
First union type as representative type#
@dataclass
class Weather:
temp: list[int | float] | (int | float)
from_dataclass(Weather(0.0))
Specs([
Spec(path=Path('/temp'), name='temp', tags=(), type=list[int | float], data=0.0),
Spec(path=Path('/temp/0'), name='0', tags=(), type=<class 'int'>, data=None),
])