# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['xarray_dataclasses']

package_data = \
{'': ['*']}

install_requires = \
['numpy>=1.19,<2.0', 'typing-extensions>=3.10,<4.0', 'xarray>=0.15,<1.0']

setup_kwargs = {
    'name': 'xarray-dataclasses',
    'version': '0.5.1',
    'description': 'xarray extension for typed DataArray and Dataset creation',
    'long_description': '# xarray-dataclasses\n\n[![PyPI](https://img.shields.io/pypi/v/xarray-dataclasses.svg?label=PyPI&style=flat-square)](https://pypi.org/project/xarray-dataclasses/)\n[![Python](https://img.shields.io/pypi/pyversions/xarray-dataclasses.svg?label=Python&color=yellow&style=flat-square)](https://pypi.org/project/xarray-dataclasses/)\n[![Test](https://img.shields.io/github/workflow/status/astropenguin/xarray-dataclasses/Test?logo=github&label=Test&style=flat-square)](https://github.com/astropenguin/xarray-dataclasses/actions)\n[![License](https://img.shields.io/badge/license-MIT-blue.svg?label=License&style=flat-square)](LICENSE)\n[![DOI](https://img.shields.io/badge/DOI-10.5281/zenodo.4624819-blue?style=flat-square)](https://doi.org/10.5281/zenodo.4624819)\n\nxarray extension for typed DataArray and Dataset creation\n\n\n## TL;DR\n\nxarray-dataclasses is a Python package for creating typed DataArray and Dataset objects of [xarray] using [the Python\'s dataclass].\nHere is an example code of what the package provides:\n\n```python\nfrom dataclasses import dataclass\nfrom xarray_dataclasses import AsDataArray, Coord, Data\n\n\n@dataclass\nclass Image(AsDataArray):\n    """DataArray that represents a 2D image."""\n\n    data: Data[tuple[\'x\', \'y\'], float]\n    x: Coord[\'x\', int] = 0\n    y: Coord[\'y\', int] = 0\n\n\n# create a DataArray object\nimage = Image.new([[0, 1], [2, 3]], x=[0, 1], y=[0, 1])\n\n\n# create a DataArray object filled with ones\nones = Image.ones((2, 2), x=[0, 1], y=[0, 1])\n```\n\n### Features\n\n- DataArray or Dataset objects with fixed dimensions, data type, and coordinates can easily be created.\n- NumPy-like special functions such as ``ones()`` are provided as class methods.\n- Compatible with [the Python\'s dataclass].\n- Compatible with static type check by [Pyright].\n\n### Installation\n\n```shell\n$ pip install xarray-dataclasses\n```\n\n\n## Introduction\n\n[xarray] is useful for handling labeled multi-dimensional data, but it is a bit troublesome to create a DataArray or Dataset object with fixed dimensions, data type, or coordinates (referred to as typed DataArray or typed Dataset, hereafter).\nFor example, let us think about the following specifications of DataArray objects:\n\n- Dimensions of data must be `(\'x\', \'y\')`.\n- Data type of data must be `float`.\n- Data type of dimensions must be `int`.\n- Default value of dimensions must be `0`.\n\nThen a function to create a typed DataArray object is something like this:\n\n```python\nimport numpy as np\nimport xarray as xr\n\n\ndef specs(data, x=None, y=None):\n    data = np.array(data)\n\n    if x is None:\n        x = np.zeros(data.shape[0])\n    else:\n        x = np.array(x)\n\n    if y is None:\n        y = np.zeros(data.shape[1])\n    else:\n        y = np.array(y)\n\n    return xr.DataArray(\n        data=data.astype(float),\n        dims=(\'x\', \'y\'),\n        coords={\n            \'x\': (\'x\', x.astype(int)),\n            \'y\': (\'y\', y.astype(int)),\n        },\n    )\n\n\ndataarray = specs([[0, 1], [2, 3]])\n```\n\nThe issues are (1) it is not easy to figure out the specs from the code and (2) it is not easy to reuse the code, for example, to add a new coordinate to the original specs.\n\n[xarray-dataclasses](#xarray-dataclasses) resolves them by defining the specs as a dataclass with dedicated type hints:\n\n```python\nfrom dataclasses import dataclass\nfrom xarray_dataclasses import AsDataArray, Coord, Data\n\n\n@dataclass\nclass Specs(AsDataArray):\n    data: Data[tuple[\'x\', \'y\'], float]\n    x: Coord[\'x\', int] = 0\n    y: Coord[\'y\', int] = 0\n\n\ndataarray = Specs.new([[0, 1], [2, 3]])\n```\n\nNow the specs become much easier to read:\nThe type hints, `Data[TDims, TDtype]` and `Coord[TDims, TDtype]`, have complete information of DataArray creation.\nThe default values are given as class variables.\n\n`AsDataArray` is a mix-in class that provides class methods such as `new()`.\nThe extension of the specs is then easy by class inheritance.\n\n## Basic usage\n\nxarray-dataclasses uses [the Python\'s dataclass] (please learn how to use it before proceeding).\nData (or data variables), coordinates, attribute members, and name of a DataArray or Dataset object are defined as dataclass fields with the following dedicated type hints.\n\n### `Data` type\n\n`Data[TDims, TDtype]` specifies the field whose value will become the data of a DataArray object or a member of the data variables of a Dataset object.\nIt accepts two type variables, `TDims` and `TDtype`, for fixing dimensions and data type, respectively.\nFor example:\n\n| Type hint | Inferred dims | Inferred dtype |\n| --- | --- | --- |\n| `Data[\'x\', typing.Any]` | `(\'x\',)` | `None` (no type casting) |\n| `Data[\'x\', int]` | `(\'x\',)` | `numpy.dtype(\'int64\')` |\n| `Data[\'x\', float]` | `(\'x\',)` | `numpy.dtype(\'float64\')` |\n| `Data[tuple[\'x\', \'y\'], float]` | `(\'x\', \'y\')` | `numpy.dtype(\'float64\')` |\n\nNote: for Python 3.7 and 3.8, use `typing.Tuple` instead of `tuple`.\n\n### `Coord` type\n\n`Coord[TDims, TDtype]` specifies the field whose value will become a coordinate of a DataArray or Dataset object.\nSimilar to `Data`, it accepts two type variables, `TDims` and `TDtype`, for fixing dimensions and data type, respectively.\n\n### `Attr` type\n\n`Attr[T]` specifies the field whose value will become a member of the attributes (attrs) of a DataArray or Dataset object.\nIt accepts a type variable, `T`, for specifying the type of the value.\nNote that the value will not be cast to the type.\n\n### `Name` type\n\n`Name[T]` specifies the field whose value will become the name of a DataArray.\nIt accepts a type variable, `T`, for specifying the type of the value.\nNote that the value will not be cast to the type.\n\n### DataArray class\n\nDataArray class is a dataclass that defines typed DataArray creation.\nFor example:\n\n```python\nfrom dataclasses import dataclass\nfrom xarray_dataclasses import AsDataArray, Attr, Coord, Data, Name\n\n\n@dataclass\nclass Image(AsDataArray):\n    """DataArray that represents a 2D image."""\n\n    data: Data[tuple[\'x\', \'y\'], float]\n    x: Coord[\'x\', int] = 0\n    y: Coord[\'y\', int] = 0\n    units: Attr[str] = \'dimensionless\'\n    name: Name[str] = \'default\'\n```\n\nwhere exactly one `Data`-type field is allowed.\nIf more than two `Data`-type fields exist, the second and subsequent fields are ignored.\nA typed DataArray object is created by a shorthand method, `new()`:\n\n```python\nImage.new([[0, 1], [2, 3]], x=[0, 1], y=[0, 1])\n\n<xarray.DataArray \'default\' (x: 2, y: 2)>\narray([[0., 1.],\n       [2., 3.]])\nCoordinates:\n  * x        (x) int64 0 1\n  * y        (y) int64 0 1\nAttributes:\n    units:    dimensionless\n```\n\nDataArray class has NumPy-like `empty()`, `zeros()`, `ones()`, `full()` methods:\n\n```python\nImage.ones((3, 3), name=\'flat\')\n\n<xarray.DataArray \'flat\' (x: 3, y: 3)>\narray([[1., 1., 1.],\n       [1., 1., 1.],\n       [1., 1., 1.]])\nCoordinates:\n  * x        (x) int64 0 0 0\n  * y        (y) int64 0 0 0\nAttributes:\n    units:    dimensionless\n```\n\n### Dataset class\n\nDataset class is a dataclass that defines typed Dataset creation.\nFor example:\n\n```python\nfrom dataclasses import dataclass\nfrom xarray_dataclasses import AsDataset, Attr, Coord, Data\n\n\n@dataclass\nclass ColorImage(AsDataset):\n    """Dataset that represents a 2D color image."""\n\n    red: Data[tuple[\'x\', \'y\'], float]\n    green: Data[tuple[\'x\', \'y\'], float]\n    blue: Data[tuple[\'x\', \'y\'], float]\n    x: Coord[\'x\', int] = 0\n    y: Coord[\'y\', int] = 0\n    units: Attr[str] = \'dimensionless\'\n```\n\nwhere multiple `Data`-type fields are allowed.\nA typed Dataset object is created by a shorthand method, `new()`:\n\n```python\nColorImage.new(\n    [[0, 0], [0, 0]],  # red\n    [[1, 1], [1, 1]],  # green\n    [[2, 2], [2, 2]],  # blue\n)\n\n<xarray.Dataset>\nDimensions:  (x: 2, y: 2)\nCoordinates:\n  * x        (x) int64 0 0\n  * y        (y) int64 0 0\nData variables:\n    red      (x, y) float64 0.0 0.0 0.0 0.0\n    green    (x, y) float64 1.0 1.0 1.0 1.0\n    blue     (x, y) float64 2.0 2.0 2.0 2.0\nAttributes:\n    units:    dimensionless\n```\n\n## Advanced usage\n\n### `Dataof` and `Coordof` types\n\nxarray-dataclasses provides advanced type hints, `Dataof[T]` and `Coordof[T]`.\nUnlike `Data` and `Coord`, they accept a dataclass that defines a DataArray class.\nThis is useful, for example, when users want to add metadata to dimensions for [plotting].\nFor example:\n\n```python\nfrom dataclasses import dataclass\nfrom xarray_dataclasses import AsDataset, Attr, Coordof, Data, Dataof\n\n\n@dataclass\nclass XAxis:\n    data: Data[\'x\', int]\n    long_name: Attr[str] = \'x axis\'\n    units: Attr[str] = \'pixel\'\n\n\n@dataclass\nclass YAxis:\n    data: Data[\'y\', int]\n    long_name: Attr[str] = \'y axis\'\n    units: Attr[str] = \'pixel\'\n\n\n@dataclass\nclass Image:\n    data: Data[tuple[\'x\', \'y\'], float]\n    x: Coordof[XAxis] = 0\n    y: Coordof[YAxis] = 0\n\n\n@dataclass\nclass ColorImage(AsDataset):\n    red: Dataof[Image]\n    green: Dataof[Image]\n    blue: Dataof[Image]\n```\n\n### Custom DataArray or Dataset factory\n\nUsers can use a custom DataArray or Dataset factory by defining a special class attribute, `__dataarray_factory__`, or `__dataset_factory__`.\nFor example:\n\n```python\nimport xarray as xr\nfrom dataclasses import dataclass\nfrom xarray_dataclasses import AsDataArray, Coord, Data\n\n\nclass Custom(xr.DataArray):\n    __slots__ = ()\n\n    def custom_method(self) -> None:\n        print(\'Custom method!\')\n\n\n@dataclass\nclass Image(AsDataArray):\n    data: Data[tuple[\'x\', \'y\'], float]\n    x: Coord[\'x\', int] = 0\n    y: Coord[\'y\', int] = 0\n    __dataarray_factory__ = Custom\n\n\nimage = Image.ones([3, 3])\nimage.custom_method() # Custom method!\n```\n\n### DataArray or Dataset creation without shorthands\n\nxarray-dataclasses provides functions, `asdataarray` and `asdataset`, for DataArray or Dataset creation without shorthand methods.\nThis is useful, for example, users do not want to inherit the mix-in class (`AsDataArray` or `AsDataset`) in their codes.\nFor example:\n\n```python\nfrom dataclasses import dataclass\nfrom xarray_dataclasses import asdataarray, Coord, Data\n\n\n@dataclass\nclass Image:\n    data: Data[tuple[\'x\', \'y\'], float]\n    x: Coord[\'x\', int] = 0\n    y: Coord[\'y\', int] = 0\n\n\nimage = asdataarray(Image([[0, 1], [2, 3]], x=[0, 1], y=[0, 1]))\n```\n\n### Static type check by [Pyright]\n\nIf users want to make your code compatible with [Pyright], please use the literal type for defining dimensions.\nFor example:\n\n```python\nfrom dataclasses import dataclass\nfrom typing import Literal\nfrom xarray_dataclasses import AsDataArray, Coord, Data\n\n\nX = Literal[\'x\']\nY = Literal[\'y\']\n\n\n@dataclass\nclass Image(AsDataArray):\n    data: Data[tuple[X, Y], float]\n    x: Coord[X, int] = 0\n    y: Coord[Y, int] = 0\n```\n\nNote: for Python 3.7, use `typing_extension.Literal` instead of `typing.Literal`.\n\n<!-- References -->\n[Pyright]: https://github.com/microsoft/pyright\n[the Python\'s dataclass]: https://docs.python.org/3/library/dataclasses.html\n[xarray]: https://xarray.pydata.org/en/stable/index.html\n[plotting]: https://xarray.pydata.org/en/stable/user-guide/plotting.html#simple-example\n',
    'author': 'Akio Taniguchi',
    'author_email': 'taniguchi@a.phys.nagoya-u.ac.jp',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/astropenguin/xarray-dataclasses/',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'python_requires': '>=3.7,<3.10',
}


setup(**setup_kwargs)
