uxarray 2026.8.1__tar.gz → 2026.9.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. {uxarray-2026.8.1 → uxarray-2026.9.1}/PKG-INFO +20 -18
  2. {uxarray-2026.8.1 → uxarray-2026.9.1}/pyproject.toml +32 -18
  3. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/constants.py +10 -0
  4. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/core/api.py +56 -19
  5. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/core/dataarray.py +229 -56
  6. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/core/dataset.py +217 -60
  7. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/core/gradient.py +258 -85
  8. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/core/utils.py +82 -4
  9. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/cross_sections/sample.py +3 -0
  10. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/errors.py +7 -0
  11. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/grid/angles.py +41 -3
  12. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/grid/arcs.py +11 -16
  13. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/grid/area.py +121 -132
  14. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/grid/bounds.py +6 -5
  15. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/grid/connectivity.py +305 -99
  16. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/grid/coordinates.py +7 -5
  17. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/grid/dual.py +1 -1
  18. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/grid/geometry.py +49 -16
  19. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/grid/grid.py +176 -59
  20. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/grid/integrate.py +8 -4
  21. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/grid/intersections.py +200 -238
  22. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/grid/neighbors.py +130 -116
  23. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/grid/point_in_face.py +1 -1
  24. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/grid/slice.py +46 -51
  25. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/grid/utils.py +259 -3
  26. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/io/_esmf.py +10 -1
  27. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/io/_fesom2.py +8 -2
  28. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/io/_geopandas.py +33 -12
  29. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/io/_healpix.py +3 -0
  30. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/io/_scrip.py +323 -28
  31. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/io/_ugrid.py +61 -2
  32. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/io/utils.py +6 -6
  33. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/plot/accessor.py +10 -2
  34. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/plot/matplotlib.py +2 -0
  35. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/plot/utils.py +6 -0
  36. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/remap/bilinear.py +1 -1
  37. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/remap/utils.py +5 -4
  38. uxarray-2026.9.1/uxarray/utils/coords.py +212 -0
  39. uxarray-2026.9.1/uxarray/utils/imports.py +366 -0
  40. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/utils/numba_math.py +20 -0
  41. uxarray-2026.9.1/uxarray/utils/warnings.py +41 -0
  42. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray.egg-info/PKG-INFO +20 -18
  43. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray.egg-info/SOURCES.txt +3 -1
  44. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray.egg-info/requires.txt +21 -15
  45. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray.egg-info/scm_file_list.json +14 -1
  46. uxarray-2026.9.1/uxarray.egg-info/scm_version.json +8 -0
  47. uxarray-2026.8.1/uxarray/utils/coords.py +0 -54
  48. uxarray-2026.8.1/uxarray.egg-info/scm_version.json +0 -8
  49. {uxarray-2026.8.1 → uxarray-2026.9.1}/.codecov.yml +0 -0
  50. {uxarray-2026.8.1 → uxarray-2026.9.1}/.git_archival.txt +0 -0
  51. {uxarray-2026.8.1 → uxarray-2026.9.1}/.gitattributes +0 -0
  52. {uxarray-2026.8.1 → uxarray-2026.9.1}/CITATION.cff +0 -0
  53. {uxarray-2026.8.1 → uxarray-2026.9.1}/CODE_OF_CONDUCT.md +0 -0
  54. {uxarray-2026.8.1 → uxarray-2026.9.1}/CONTRIBUTING.md +0 -0
  55. {uxarray-2026.8.1 → uxarray-2026.9.1}/INSTALLATION.md +0 -0
  56. {uxarray-2026.8.1 → uxarray-2026.9.1}/LICENSE +0 -0
  57. {uxarray-2026.8.1 → uxarray-2026.9.1}/MANIFEST.in +0 -0
  58. {uxarray-2026.8.1 → uxarray-2026.9.1}/README.md +0 -0
  59. {uxarray-2026.8.1 → uxarray-2026.9.1}/build.sh +0 -0
  60. {uxarray-2026.8.1 → uxarray-2026.9.1}/setup.cfg +0 -0
  61. {uxarray-2026.8.1 → uxarray-2026.9.1}/setup.py +0 -0
  62. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/__init__.py +0 -0
  63. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/conventions/__init__.py +0 -0
  64. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/conventions/descriptors.py +0 -0
  65. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/conventions/ugrid.py +0 -0
  66. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/core/__init__.py +0 -0
  67. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/core/accessors.py +0 -0
  68. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/core/aggregation.py +0 -0
  69. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/core/zonal.py +0 -0
  70. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/cross_sections/__init__.py +0 -0
  71. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/cross_sections/dataarray_accessor.py +0 -0
  72. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/cross_sections/grid_accessor.py +0 -0
  73. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/formatting_html.py +0 -0
  74. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/grid/__init__.py +0 -0
  75. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/grid/validation.py +0 -0
  76. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/io/__init__.py +0 -0
  77. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/io/_delaunay.py +0 -0
  78. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/io/_exodus.py +0 -0
  79. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/io/_geos.py +0 -0
  80. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/io/_icon.py +0 -0
  81. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/io/_mpas.py +0 -0
  82. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/io/_structured.py +0 -0
  83. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/io/_topology.py +0 -0
  84. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/io/_vertices.py +0 -0
  85. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/io/_voronoi.py +0 -0
  86. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/plot/__init__.py +0 -0
  87. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/plot/constants.py +0 -0
  88. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/remap/__init__.py +0 -0
  89. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/remap/accessor.py +0 -0
  90. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/remap/apply_weights.py +0 -0
  91. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/remap/inverse_distance_weighted.py +0 -0
  92. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/remap/nearest_neighbor.py +0 -0
  93. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/remap/spatial_coords_remap.py +0 -0
  94. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/remap/structured.py +0 -0
  95. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/remap/weights.py +0 -0
  96. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/remap/yac.py +0 -0
  97. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/subset/__init__.py +0 -0
  98. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/subset/dataarray_accessor.py +0 -0
  99. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/subset/grid_accessor.py +0 -0
  100. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/tutorial/__init__.py +0 -0
  101. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/tutorial/registry.py +0 -0
  102. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/utils/__init__.py +0 -0
  103. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray/utils/computing.py +0 -0
  104. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray.egg-info/dependency_links.txt +0 -0
  105. {uxarray-2026.8.1 → uxarray-2026.9.1}/uxarray.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uxarray
3
- Version: 2026.8.1
3
+ Version: 2026.9.1
4
4
  Summary: Xarray extension for unstructured climate and global weather data analysis and visualization.
5
5
  License: Apache License
6
6
  Version 2.0, January 2004
@@ -213,46 +213,48 @@ Classifier: Intended Audience :: Science/Research
213
213
  Classifier: Topic :: Scientific/Engineering
214
214
  Classifier: Programming Language :: Python
215
215
  Classifier: Programming Language :: Python :: 3
216
- Classifier: Programming Language :: Python :: 3.10
217
216
  Classifier: Programming Language :: Python :: 3.11
218
217
  Classifier: Programming Language :: Python :: 3.12
219
218
  Classifier: Programming Language :: Python :: 3.13
220
219
  Classifier: Programming Language :: Python :: 3.14
221
- Requires-Python: >=3.10
220
+ Requires-Python: >=3.11
222
221
  Description-Content-Type: text/markdown
223
222
  License-File: LICENSE
224
223
  Requires-Dist: antimeridian
225
- Requires-Dist: cartopy
226
224
  Requires-Dist: dask[dataframe]
227
- Requires-Dist: datashader
228
- Requires-Dist: geoviews
229
- Requires-Dist: holoviews
230
- Requires-Dist: matplotlib<3.11
231
- Requires-Dist: matplotlib-inline
232
225
  Requires-Dist: netcdf4
233
226
  Requires-Dist: numba>=0.63
234
227
  Requires-Dist: numpy
235
228
  Requires-Dist: pandas
236
- Requires-Dist: pyarrow
237
- Requires-Dist: requests
238
229
  Requires-Dist: scikit-learn
239
230
  Requires-Dist: scipy
240
231
  Requires-Dist: shapely
241
- Requires-Dist: spatialpandas
242
- Requires-Dist: geopandas
243
232
  Requires-Dist: xarray
244
- Requires-Dist: hvplot
245
- Requires-Dist: healpix
246
233
  Requires-Dist: polars
247
- Requires-Dist: pyproj
234
+ Provides-Extra: all
235
+ Requires-Dist: uxarray[dev,geo,viz]; extra == "all"
248
236
  Provides-Extra: complete
249
- Requires-Dist: uxarray[dev]; extra == "complete"
237
+ Requires-Dist: uxarray[dev,geo,viz]; extra == "complete"
250
238
  Provides-Extra: dev
239
+ Requires-Dist: asv; extra == "dev"
240
+ Requires-Dist: pooch; extra == "dev"
251
241
  Requires-Dist: pre_commit; extra == "dev"
252
242
  Requires-Dist: pytest; extra == "dev"
253
243
  Requires-Dist: pytest-cov; extra == "dev"
254
244
  Requires-Dist: ruff; extra == "dev"
255
- Requires-Dist: asv; extra == "dev"
245
+ Provides-Extra: geo
246
+ Requires-Dist: cartopy; extra == "geo"
247
+ Requires-Dist: geopandas>=1.0; extra == "geo"
248
+ Requires-Dist: healpix; extra == "geo"
249
+ Requires-Dist: pyproj; extra == "geo"
250
+ Requires-Dist: spatialpandas; extra == "geo"
251
+ Provides-Extra: viz
252
+ Requires-Dist: cartopy<0.26; extra == "viz"
253
+ Requires-Dist: datashader; extra == "viz"
254
+ Requires-Dist: matplotlib<3.11; extra == "viz"
255
+ Requires-Dist: geoviews; extra == "viz"
256
+ Requires-Dist: holoviews; extra == "viz"
257
+ Requires-Dist: hvplot; extra == "viz"
256
258
  Dynamic: license-file
257
259
 
258
260
 
@@ -5,7 +5,6 @@ classifiers=[
5
5
  "Topic :: Scientific/Engineering",
6
6
  "Programming Language :: Python",
7
7
  "Programming Language :: Python :: 3",
8
- "Programming Language :: Python :: 3.10",
9
8
  "Programming Language :: Python :: 3.11",
10
9
  "Programming Language :: Python :: 3.12",
11
10
  "Programming Language :: Python :: 3.13",
@@ -18,46 +17,58 @@ description = "Xarray extension for unstructured climate and global weather data
18
17
  license = {file = "LICENSE"}
19
18
  name = "uxarray"
20
19
  readme = "README.md"
21
- requires-python = ">=3.10"
20
+ requires-python = ">=3.11"
22
21
 
23
22
  # minimal dependencies start
24
23
  dependencies = [
25
24
  "antimeridian",
26
- "cartopy",
27
25
  "dask[dataframe]",
28
- "datashader",
29
- "geoviews",
30
- "holoviews",
31
- "matplotlib<3.11", # matplotlib 3.11.0 breaks some plots but <3.11 is fine; see issue #1542.
32
- "matplotlib-inline",
33
26
  "netcdf4",
34
27
  "numba>=0.63", # 0.63 is the first release supporting Python 3.14 (3.10 <= py < 3.15). See #1561.
35
28
  "numpy",
36
29
  "pandas",
37
- "pyarrow",
38
- "requests",
39
30
  "scikit-learn",
40
31
  "scipy",
41
32
  "shapely",
42
- "spatialpandas",
43
- "geopandas",
44
33
  "xarray",
45
- "hvplot",
46
- "healpix",
47
34
  "polars",
48
- "pyproj"
49
35
  ]
50
36
  # minimal dependencies end
51
37
 
52
38
  [project.optional-dependencies]
53
- complete = ["uxarray[dev]"]
54
- dev = ['pre_commit', 'pytest', 'pytest-cov', 'ruff', 'asv']
39
+ all = ["uxarray[dev,geo,viz]"]
40
+ complete = ["uxarray[dev,geo,viz]"] # alias to "all"
41
+ dev = [
42
+ 'asv',
43
+ 'pooch',
44
+ 'pre_commit',
45
+ 'pytest',
46
+ 'pytest-cov',
47
+ 'ruff',
48
+ ]
49
+ geo = [
50
+ "cartopy", # in both geo and viz because it is needed by to_geodataframe() and by plotting routines.
51
+ "geopandas>=1.0", # 1.0 is the first release requiring pyogrio, the file-IO backend read_file needs. See #1693.
52
+ "healpix",
53
+ "pyproj",
54
+ "spatialpandas",
55
+ ]
56
+ viz = [
57
+ "cartopy<0.26", # cartopy 0.26.0 breaks some geoviews plots; see issue #1780.
58
+ # (cartopy pin intentionally here but not in "geo" extras because geoviews is only in "viz".)
59
+ "datashader",
60
+ "matplotlib<3.11", # matplotlib 3.11.0 breaks some plots but <3.11 is fine; see issue #1542.
61
+ "geoviews", # no version pin; newer should support any cartopy; see holoviz/geoviews#884.
62
+ "holoviews",
63
+ "hvplot",
64
+ ]
55
65
 
56
66
  [project.urls]
57
67
  Documentation = "https://uxarray.readthedocs.io/"
58
68
  Source = "https://github.com/UXARRAY/uxarray"
59
69
  Tracker = "https://github.com/UXARRAY/uxarray/issues"
60
-
70
+ # please keep [project.urls] immediately after [project.optional-dependencies],
71
+ # or, if rearranging sections, make sure to edit installation.rst accordingly.
61
72
 
62
73
  [build-system]
63
74
  build-backend = "setuptools.build_meta"
@@ -88,3 +99,6 @@ known-first-party = ["uxarray"]
88
99
 
89
100
  [tool.ruff.format]
90
101
  docstring-code-format = true
102
+
103
+ [tool.pytest.ini_options]
104
+ testpaths = ["test"] # (intentionally excludes test_optional_deps)
@@ -21,3 +21,13 @@ ENABLE_FMA = False
21
21
  GRID_DIMS = ["n_node", "n_edge", "n_face"]
22
22
 
23
23
  WGS84_CRS = "EPSG:4326"
24
+
25
+
26
+ # Threshold the adaptive ``edge_node`` sort in ``uxarray.grid.utils`` is built around, in two
27
+ # related roles. Above a bucket of ``2 * EDGE_NODE_SORT_THRESHOLD``, an insertion sort is abandoned
28
+ # for a heap sort once it has done ``EDGE_NODE_SORT_THRESHOLD`` shifts per edge, keeping
29
+ # that path linear while leaving ample room for the near-sorted input it is chosen for. At or below
30
+ # that size, the bookkeeping would never pay for itself: a bucket of ``size`` holds at most
31
+ # ``size * (size - 1) / 2`` inversions, too few to exhaust the budget, so the plain insertion
32
+ # sort is used instead.
33
+ EDGE_NODE_SORT_THRESHOLD = 8
@@ -2,19 +2,21 @@ from __future__ import annotations
2
2
 
3
3
  import os
4
4
  from pathlib import Path
5
- from typing import Any, Mapping, Sequence, TypeAlias
5
+ from typing import Any, Hashable, Iterable, Mapping, Sequence, TypeAlias
6
6
  from warnings import warn
7
7
 
8
8
  import numpy as np
9
+ import pandas as pd
9
10
  import xarray as xr
10
11
 
12
+ from uxarray.core.dataarray import UxDataArray
11
13
  from uxarray.core.dataset import UxDataset
12
14
  from uxarray.core.utils import (
13
15
  _map_dims_to_ugrid,
14
16
  _open_dataset_with_fallback,
15
17
  match_chunks_to_ugrid,
16
18
  )
17
- from uxarray.errors import GridInvalidError
19
+ from uxarray.errors import GridInvalidError, GridsMismatchError
18
20
  from uxarray.grid import Grid
19
21
  from uxarray.io._scrip import (
20
22
  _detect_multigrid,
@@ -575,25 +577,60 @@ def _get_grid(
575
577
  return open_grid(grid_filename_or_obj, use_dual=use_dual, **grid_kwargs)
576
578
 
577
579
 
578
- def concat(objs, *args, **kwargs):
579
- # Ensure there is at least one object to concat.
580
- if not objs:
581
- raise ValueError("No objects provided for concatenation.")
580
+ def concat(
581
+ objs: Iterable[UxDataArray | UxDataset],
582
+ dim: Hashable | xr.Variable | xr.DataArray | pd.Index,
583
+ **kwargs: dict[str, Any],
584
+ ):
585
+ """concatenate uxarray objects along a new or existing dimension.
582
586
 
583
- ref_uxgrid = getattr(objs[0], "uxgrid", None)
584
- if ref_uxgrid is None:
585
- raise AttributeError("The first object does not have a 'uxgrid' attribute.")
587
+ Parameters
588
+ ----------
589
+ objs : iterable of UxDataArray or UxDataset
590
+ uxarray objects to concatenate together. Each object is expected to
591
+ consist of variables and coordinates with matching shapes except for
592
+ along the concatenated dimension, and to have underlying grids which
593
+ compare as equal. The first object's uxgrid is attached to the result.
594
+ dim : Hashable or Variable or DataArray or pandas.Index
595
+ Name of the dimension to concatenate along. This can either be a new
596
+ dimension name, in which case it is added along axis=0, or an existing
597
+ dimension name, in which case the location of the dimension is
598
+ unchanged. If dimension is provided as a Variable, DataArray or Index, its name
599
+ is used as the dimension to concatenate along and the values are added
600
+ as a coordinate.
601
+ **kwargs : dict, optional
602
+ All additional kwargs forwarded directly to :func:`xarray.concat`.
586
603
 
587
- ref_id = id(ref_uxgrid)
604
+ Returns
605
+ -------
606
+ concatenated: type of objs
607
+ Concatenated uxarray object with the same type as the input objects.
608
+ """
609
+ objs = tuple(objs)
610
+ try:
611
+ ref_obj = objs[0]
612
+ except IndexError as err:
613
+ raise ValueError("concat requires at least one object to concatenate.") from err
614
+
615
+ result_type = type(ref_obj)
616
+ if not (
617
+ issubclass(result_type, (UxDataArray, UxDataset))
618
+ and all(isinstance(obj, result_type) for obj in objs)
619
+ ):
620
+ _types = {type(obj) for obj in objs}
621
+ raise TypeError(
622
+ "concat(objs, ...) expected either all UxDataArray "
623
+ f"or all UxDataset objs, but got types: {_types}."
624
+ )
588
625
 
589
- for i, obj in enumerate(objs):
590
- uxgrid = getattr(obj, "uxgrid", None)
591
- if uxgrid is None:
592
- raise AttributeError(
593
- f"Object at index {i} does not have a 'uxgrid' attribute."
626
+ result_uxgrid = ref_obj.uxgrid
627
+ for i, obj in enumerate(objs[1:], start=1):
628
+ if result_uxgrid != obj.uxgrid:
629
+ raise GridsMismatchError(
630
+ "concat(objs, ...) expects equivalent grids for all objs, "
631
+ f"but got objs[{i}].uxgrid != objs[0].uxgrid."
594
632
  )
595
- if id(uxgrid) != ref_id:
596
- raise ValueError(f"Object at index {i} has a different 'uxgrid' attribute.")
597
633
 
598
- res = xr.concat(objs, *args, **kwargs)
599
- return UxDataset(res, uxgrid=uxgrid)
634
+ xarray_objs = [obj.to_xarray() for obj in objs]
635
+
636
+ return result_type(xr.concat(xarray_objs, dim=dim, **kwargs), uxgrid=result_uxgrid)