Repository: astropenguin/xarray-dataclasses (python)

Issue:
Swap the order of dims and dtype in Coord[...] and Data[...]
Swap the order of dims and dtype s.t. ``Coord[dims, dtype]`` and ``Data[dims, dtype]``.
This is because their order in the printed format is (dims, dtype, value).

```
<xarray.DataArray (x: 3, y: 3)>
array([[0., 0., 0.],
       [0., 0., 0.],
       [0., 0., 0.]])
Coordinates:
  * x        (x) int64 0 0 0
  * y        (y) int64 0 0 0
```

Pull request description:
Swap the order of dims and dtype in Coord[...] and Data[...]
This PR closes #31.

Patch:
diff --git a/README.md b/README.md
index 3e9037e..474d90b 100644
--- a/README.md
+++ b/README.md
@@ -25,9 +25,9 @@ Y = Literal['y']
 class Image:
     """DataArray class to represent images."""
 
-    data: Data[float, tuple[X, Y])
-    x: Coord[int, X] = 0
-    y: Coord[int, Y] = 0
+    data: Data[tuple[X, Y], float)
+    x: Coord[X, int] = 0
+    y: Coord[Y, int] = 0
 
 ```
 
diff --git a/xarray_dataclasses/common.py b/xarray_dataclasses/common.py
index e4e1a51..12aee43 100644
--- a/xarray_dataclasses/common.py
+++ b/xarray_dataclasses/common.py
@@ -34,8 +34,8 @@ from .typing import (
 
 
 # type hints (internal)
-T = TypeVar("T")
 D = TypeVar("D")
+T = TypeVar("T")
 
 FieldValue = Tuple[Field, Any]
 
@@ -139,15 +139,15 @@ def _gen_fields(
 
 
 def _to_dataarray(
-    data: DataArrayLike[T, D],
-    type_: Type[DataArrayLike[T, D]],
+    data: DataArrayLike[D, T],
+    type_: Type[DataArrayLike[D, T]],
     sizes: Optional[Mapping[Hashable, int]] = None,
 ) -> xr.DataArray:
     """Create a DataArray instance from DataArrayLike object.
 
     Args:
         data: DataArrayLike object.
-        type_: Type of ``data``. Must be DataArrayLike[T, D].
+        type_: Type of ``data``. Must be DataArrayLike[D, T].
         sizes: If specified, it is used for broadcasting ``data``.
 
     Returns:
diff --git a/xarray_dataclasses/typing.py b/xarray_dataclasses/typing.py
index 27f95cb..0489e08 100644
--- a/xarray_dataclasses/typing.py
+++ b/xarray_dataclasses/typing.py
@@ -47,8 +47,8 @@ class Xarray(Enum):
 
 
 # type hints (internal)
-T = TypeVar("T", covariant=True)
 D = TypeVar("D", covariant=True)
+T = TypeVar("T", covariant=True)
 
 DTypeLike = Union[np.dtype, type, str, None]
 FieldDict = Dict[str, Field]
@@ -61,7 +61,7 @@ class ndarray(Protocol[T]):
     __array__: Callable[..., np.ndarray]
 
 
-class DataArray(Protocol[T, D]):
+class DataArray(Protocol[D, T]):
     """Protocol version of xarray.DataArray."""
 
     __array__: Callable[..., np.ndarray]
@@ -74,7 +74,7 @@ class DataClass(Protocol):
     __dataclass_fields__: FieldDict
 
 
-DataArrayLike = Union[DataArray[T, D], ndarray[T], Sequence[T], T]
+DataArrayLike = Union[DataArray[D, T], ndarray[T], Sequence[T], T]
 
 
 # type hints (public)
@@ -94,12 +94,12 @@ Examples:
 
         @dataarrayclass
         class Image:
-            data: Data[float, tuple[X, Y]]
+            data: Data[tuple[X, Y], float]
             dpi: Attr[int] = 300
 
 """
 
-Coord = Annotated[DataArrayLike[T, D], Xarray.COORD]
+Coord = Annotated[DataArrayLike[D, T], Xarray.COORD]
 """Type hint for a coordinate member of DataArray or Dataset.
 
 Examples:
@@ -115,14 +115,14 @@ Examples:
 
         @dataarrayclass
         class Image:
-            data: Data[float, tuple[X, Y]]
-            weight: Coord[float, tuple[X, Y]] = 1.0
-            x: Coord[int, X] = 0
-            y: Coord[int, Y] = 0
+            data: Data[tuple[X, Y], float]
+            weight: Coord[tuple[X, Y], float] = 1.0
+            x: Coord[X, int] = 0
+            y: Coord[Y, int] = 0
 
 """
 
-Data = Annotated[DataArrayLike[T, D], Xarray.DATA]
+Data = Annotated[DataArrayLike[D, T], Xarray.DATA]
 """Type hint for data of DataArray or variable of Dataset.
 
 Examples:
@@ -138,7 +138,7 @@ Examples:
 
         @dataarrayclass
         class Image:
-            data: Data[float, tuple[X, Y]]
+            data: Data[tuple[X, Y], float]
 
     ::
 
@@ -152,9 +152,9 @@ Examples:
 
         @datasetclass
         class Images:
-            red: Data[float, tuple[X, Y]]
-            green: Data[float, tuple[X, Y]]
-            blue: Data[float, tuple[X, Y]]
+            red: Data[tuple[X, Y], float]
+            green: Data[tuple[X, Y], float]
+            blue: Data[tuple[X, Y], float]
 
 """
 
@@ -174,7 +174,7 @@ Examples:
 
         @dataarrayclass
         class Image:
-            data: Data[float, tuple[X, Y]]
+            data: Data[tuple[X, Y], float]
             name: Name[str] = "default"
 
 """
@@ -187,12 +187,12 @@ def is_attr(type_: Any) -> bool:
 
 
 def is_coord(type_: Any) -> bool:
-    """Check if type is Coord[T, D]."""
+    """Check if type is Coord[D, T]."""
     return Xarray.COORD.annotates(type_)
 
 
 def is_data(type_: Any) -> bool:
-    """Check if type is Data[T, D]."""
+    """Check if type is Data[D, T]."""
     return Xarray.DATA.annotates(type_)
 
 
@@ -201,12 +201,12 @@ def is_name(type_: Any) -> bool:
     return Xarray.NAME.annotates(type_)
 
 
-def get_dims(type_: Type[DataArrayLike[T, D]]) -> Tuple[str, ...]:
-    """Extract dimensions (dims) from DataArrayLike[T, D]."""
+def get_dims(type_: Type[DataArrayLike[D, T]]) -> Tuple[str, ...]:
+    """Extract dimensions (dims) from DataArrayLike[D, T]."""
     if get_origin(type_) is Annotated:
         type_ = get_args(type_)[0]
 
-    dims_ = get_args(get_args(type_)[0])[1]
+    dims_ = get_args(get_args(type_)[0])[0]
 
     if get_origin(dims_) is tuple:
         dims_ = get_args(dims_)
@@ -232,12 +232,12 @@ def get_dims(type_: Type[DataArrayLike[T, D]]) -> Tuple[str, ...]:
     return tuple(dims)
 
 
-def get_dtype(type_: Type[DataArrayLike[T, D]]) -> DTypeLike:
-    """Extract a data type (dtype) from DataArrayLike[T, D]."""
+def get_dtype(type_: Type[DataArrayLike[D, T]]) -> DTypeLike:
+    """Extract a data type (dtype) from DataArrayLike[D, T]."""
     if get_origin(type_) is Annotated:
         type_ = get_args(type_)[0]
 
-    dtype_ = get_args(get_args(type_)[0])[0]
+    dtype_ = get_args(get_args(type_)[0])[1]
 
     if dtype_ is Any:
         return None


Test patch:
diff --git a/tests/test_dataarray.py b/tests/test_dataarray.py
index 4e48c8c..577086c 100644
--- a/tests/test_dataarray.py
+++ b/tests/test_dataarray.py
@@ -27,9 +27,9 @@ Y = Literal[DIMS[1]]
 # dataclasses
 @dataclass
 class Image(DataArrayMixin):
-    data: Data[float, Tuple[X, Y]]
-    x: Coord[int, X] = 0
-    y: Coord[int, Y] = 0
+    data: Data[Tuple[X, Y], float]
+    x: Coord[X, int] = 0
+    y: Coord[Y, int] = 0
     dpi: Attr[int] = 100
     name: Name[str] = "image"
 
diff --git a/tests/test_dataset.py b/tests/test_dataset.py
index b36968c..45d6b48 100644
--- a/tests/test_dataset.py
+++ b/tests/test_dataset.py
@@ -27,16 +27,16 @@ Y = Literal[DIMS[1]]
 # dataclasses
 @dataclass
 class Image(DataArrayMixin):
-    data: Data[float, Tuple[X, Y]]
+    data: Data[Tuple[X, Y], float]
 
 
 @dataclass
 class RGBImage(DatasetMixin):
-    red: Data[float, Tuple[X, Y]]
-    green: Data[float, Tuple[X, Y]]
-    blue: Data[float, Tuple[X, Y]]
-    x: Coord[int, X] = 0
-    y: Coord[int, Y] = 0
+    red: Data[Tuple[X, Y], float]
+    green: Data[Tuple[X, Y], float]
+    blue: Data[Tuple[X, Y], float]
+    x: Coord[X, int] = 0
+    y: Coord[Y, int] = 0
     dpi: Attr[int] = 100
 
 
diff --git a/tests/test_typing.py b/tests/test_typing.py
index f9dfd6b..8447c44 100644
--- a/tests/test_typing.py
+++ b/tests/test_typing.py
@@ -41,9 +41,9 @@ testdata_dtype = [
 # test functions
 @mark.parametrize("dims, expected", testdata_dims)
 def test_dims(dims: Any, expected: Any) -> None:
-    assert get_dims(DataArrayLike[Any, dims]) == expected
+    assert get_dims(DataArrayLike[dims, Any]) == expected
 
 
 @mark.parametrize("dtype, expected", testdata_dtype)
 def test_dtype(dtype: Any, expected: Any) -> None:
-    assert get_dtype(DataArrayLike[dtype, Any]) == expected
+    assert get_dtype(DataArrayLike[Any, dtype]) == expected