Skip to content

Commit 56cea4c

Browse files
DAS-2373: Retrieve data type for string variables. (#68)
1 parent de6249e commit 56cea4c

File tree

4 files changed

+74
-3
lines changed

4 files changed

+74
-3
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
## v3.3.0
2+
### 2025-09-11
3+
4+
### Changed:
5+
6+
* DAS-2373 - Updated the retrieval of data type from `netCDF4.Variable` objects
7+
to first consider the `netCDF4.Variable.datatype.name` and then fall back to
8+
`netCDF4.Variable.datatype.dtype`.
9+
110
## v3.2.0
211
### 2025-07-25
312

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.2.0
1+
3.3.0

tests/unit/test_variable.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -923,6 +923,20 @@ def test_variable_get_shape_with_without_dim_size(self):
923923
self.assertEqual(variable.dimensions, [])
924924
self.assertEqual(variable.shape, [2222])
925925

926+
927+
class TestVariableFromNetCDF4(TestCase):
928+
"""Tests for the `Variable` class using `netCDF4.Variable` input."""
929+
930+
@classmethod
931+
def setUpClass(cls):
932+
"""Set up properties of the class that do not need to be reset between
933+
tests.
934+
935+
"""
936+
cls.config_file = 'tests/unit/data/test_config.json'
937+
cls.fakesat_config = CFConfig('FakeSat', 'FAKE99', config_file=cls.config_file)
938+
cls.namespace = 'namespace_string'
939+
926940
def test_variable_from_netcdf4(self):
927941
"""Ensure that a `netCDF4.Variable` instance can be correctly
928942
parsed by the `VariableFromNetCDF4` child class.
@@ -968,3 +982,45 @@ def test_variable_from_netcdf4(self):
968982
self.assertEqual(variable.get_valid_min(), -10)
969983
self.assertEqual(variable.get_valid_max(), 10)
970984
self.assertSetEqual(variable.get_references(), {'/lat', '/lon'})
985+
986+
def test_string_variable_get_data_type(self):
987+
"""Ensure VariableFromNetCDF4 extracts data type from `netCDF4.Variable`
988+
989+
* First trying `netCDF4.Variable.datatype.name`.
990+
* Then fall back to `netCDF4.Variable.datatype.dtype`.
991+
992+
"""
993+
with Dataset('test.nc4', 'w', diskless=True) as dataset:
994+
dataset.createDimension('lat', size=2)
995+
dataset.createDimension('lon', size=2)
996+
997+
# A float variable has netCDF4.Variable.datatype.name populated
998+
nc4_var_datatype_name = dataset.createVariable(
999+
'/datatype_name', float, dimensions=('lat', 'lon')
1000+
)
1001+
1002+
# A str variable has netCDF4.Variable.datatype.name of `None`
1003+
nc4_var_datatype_dtype = dataset.createVariable(
1004+
'datatype_dtype',
1005+
str,
1006+
dimensions=('lat', 'lon'),
1007+
)
1008+
1009+
variable_from_datatype_name = VariableFromNetCDF4(
1010+
nc4_var_datatype_name,
1011+
self.fakesat_config,
1012+
self.namespace,
1013+
'/datatype_name',
1014+
)
1015+
variable_from_datatype_dtype = VariableFromNetCDF4(
1016+
nc4_var_datatype_dtype,
1017+
self.fakesat_config,
1018+
self.namespace,
1019+
'/datatype_dtype',
1020+
)
1021+
1022+
with self.subTest('From netCDF4.Variable.datatype.name'):
1023+
self.assertEqual(variable_from_datatype_name.data_type, 'float64')
1024+
1025+
with self.subTest('From netCDF4.Variable.datatype.dtype'):
1026+
self.assertEqual(variable_from_datatype_dtype.data_type, 'str')

varinfo/variable.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -424,8 +424,14 @@ class VariableFromNetCDF4(VariableBase, AttributeContainerFromNetCDF4):
424424
"""
425425

426426
def _get_data_type(self, variable: NetCDF4Variable) -> str:
427-
"""Extract a string representation of the variable data type."""
428-
return variable.datatype.name
427+
"""Extract a string representation of the variable data type.
428+
429+
* First try `variable.datatype.name`. This can be `None` for some
430+
string type variables.
431+
* If `variable.datatype.name` is `None`, try `variable.datatype.dtype`.
432+
433+
"""
434+
return variable.datatype.name or variable.datatype.dtype.__name__
429435

430436
def _get_shape(self, variable: NetCDF4Variable) -> tuple[int]:
431437
"""Extract the shape of the variable data array."""

0 commit comments

Comments
 (0)