Skip to content

Commit 1eb24cb

Browse files
authored
update CoverageJSON compliance (#2012)
* CoverageJSON: update compliance * remove extra None check
1 parent 5d2d8d8 commit 1eb24cb

File tree

6 files changed

+90
-35
lines changed

6 files changed

+90
-35
lines changed

pygeoapi/api/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1425,6 +1425,8 @@ def get_collection_schema(api: API, request: Union[APIRequest, Any],
14251425

14261426
for k, v in p.fields.items():
14271427
schema['properties'][k] = v
1428+
if v['type'] == 'float':
1429+
schema['properties'][k]['type'] = 'number'
14281430
if v.get('format') is None:
14291431
schema['properties'][k].pop('format', None)
14301432

pygeoapi/api/itemtypes.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ def get_collection_queryables(api: API, request: Union[APIRequest, Any],
199199
'title': k,
200200
'type': v['type']
201201
}
202+
if v['type'] == 'float':
203+
queryables['properties'][k]['type'] = 'number'
202204
if v.get('format') is not None:
203205
queryables['properties'][k]['format'] = v['format']
204206
if 'values' in v:

pygeoapi/provider/rasterio_.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#
33
# Authors: Tom Kralidis <tomkralidis@gmail.com>
44
#
5-
# Copyright (c) 2024 Tom Kralidis
5+
# Copyright (c) 2025 Tom Kralidis
66
#
77
# Permission is hereby granted, free of charge, to any person
88
# obtaining a copy of this software and associated documentation
@@ -79,9 +79,11 @@ def get_fields(self):
7979

8080
dtype2 = dtype
8181
if dtype.startswith('float'):
82-
dtype2 = 'number'
82+
dtype2 = 'float'
8383
elif dtype.startswith('int'):
8484
dtype2 = 'integer'
85+
elif dtype.startswith('str'):
86+
dtype2 = 'string'
8587

8688
self._fields[i2] = {
8789
'title': name,
@@ -306,7 +308,9 @@ def gen_covjson(self, metadata, data):
306308

307309
parameter = {
308310
'type': 'Parameter',
309-
'description': pm['description'],
311+
'description': {
312+
'en': pm['description']
313+
},
310314
'unit': {
311315
'symbol': pm['unit_label']
312316
},

pygeoapi/provider/xarray_.py

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# Authors: Tom Kralidis <tomkralidis@gmail.com>
55
#
66
# Copyright (c) 2020 Gregory Petrochenkov
7-
# Copyright (c) 2022 Tom Kralidis
7+
# Copyright (c) 2025 Tom Kralidis
88
#
99
# Permission is hereby granted, free of charge, to any person
1010
# obtaining a copy of this software and associated documentation
@@ -111,9 +111,11 @@ def get_fields(self):
111111
LOGGER.debug('Adding variable')
112112
dtype = value.dtype
113113
if dtype.name.startswith('float'):
114-
dtype = 'number'
114+
dtype = 'float'
115115
elif dtype.name.startswith('int'):
116116
dtype = 'integer'
117+
elif dtype.name.startswith('str'):
118+
dtype = 'string'
117119

118120
self._fields[key] = {
119121
'type': dtype,
@@ -330,18 +332,35 @@ def gen_covjson(self, metadata, data, fields):
330332
'ranges': {}
331333
}
332334

335+
if (data.coords[self.x_field].size == 1 and
336+
data.coords[self.y_field].size == 1):
337+
LOGGER.debug('Modelling as PointSeries')
338+
cj['domain']['axes']['x'] = {
339+
'values': [float(data.coords[self.x_field].values)]
340+
}
341+
cj['domain']['axes']['y'] = {
342+
'values': [float(data.coords[self.y_field].values)]
343+
}
344+
cj['domain']['domainType'] = 'PointSeries'
345+
333346
if self.time_field is not None:
334-
mint, maxt = metadata['time']
335-
cj['domain']['axes'][self.time_field] = {
336-
'start': mint,
337-
'stop': maxt,
338-
'num': metadata['time_steps'],
347+
cj['domain']['axes']['t'] = {
348+
'values': [str(v) for v in data[self.time_field].values]
339349
}
350+
cj['domain']['referencing'].append({
351+
'coordinates': ['t'],
352+
'system': {
353+
'type': 'TemporalRS',
354+
'calendar': 'Gregorian'
355+
}
356+
})
340357

341358
for key, value in selected_fields.items():
342359
parameter = {
343360
'type': 'Parameter',
344-
'description': value['title'],
361+
'description': {
362+
'en': value['title']
363+
},
345364
'unit': {
346365
'symbol': value['x-ogc-unit']
347366
},
@@ -368,12 +387,13 @@ def gen_covjson(self, metadata, data, fields):
368387
'shape': [metadata['height'],
369388
metadata['width']]
370389
}
371-
cj['ranges'][key]['values'] = data[key].values.flatten().tolist() # noqa
390+
cj['ranges'][key]['values'] = [
391+
None if np.isnan(v) else v
392+
for v in data[key].values.flatten()
393+
]
372394

373395
if self.time_field is not None:
374-
cj['ranges'][key]['axisNames'].append(
375-
self._coverage_properties['time_axis_label']
376-
)
396+
cj['ranges'][key]['axisNames'].append('t')
377397
cj['ranges'][key]['shape'].append(metadata['time_steps'])
378398
except IndexError as err:
379399
LOGGER.warning(err)

tests/api/test_environmental_data_retrieval.py

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# Colin Blackburn <colb@bgs.ac.uk>
66
# Bernhard Mallinger <bernhard.mallinger@eox.at>
77
#
8-
# Copyright (c) 2024 Tom Kralidis
8+
# Copyright (c) 2025 Tom Kralidis
99
# Copyright (c) 2022 John A Stevenson and Colin Blackburn
1010
#
1111
# Permission is hereby granted, free of charge, to any person
@@ -87,12 +87,12 @@ def test_get_collection_edr_query(config, api_):
8787
axes = list(data['domain']['axes'].keys())
8888
axes.sort()
8989
assert len(axes) == 3
90-
assert axes == ['TIME', 'x', 'y']
90+
assert axes == ['t', 'x', 'y']
9191

92-
assert data['domain']['axes']['x']['start'] == 11.0
93-
assert data['domain']['axes']['x']['stop'] == 11.0
94-
assert data['domain']['axes']['y']['start'] == 11.0
95-
assert data['domain']['axes']['y']['stop'] == 11.0
92+
assert isinstance(data['domain']['axes']['x'], dict)
93+
assert isinstance(data['domain']['axes']['x']['values'], list)
94+
assert data['domain']['axes']['x']['values'][0] == 11.0
95+
assert data['domain']['axes']['y']['values'][0] == 11.0
9696

9797
parameters = list(data['parameters'].keys())
9898
parameters.sort()
@@ -131,11 +131,19 @@ def test_get_collection_edr_query(config, api_):
131131
assert code == HTTPStatus.OK
132132

133133
data = json.loads(response)
134-
time_dict = data['domain']['axes']['TIME']
134+
time_dict = data['domain']['axes']['t']
135+
assert isinstance(time_dict, dict)
136+
assert isinstance(time_dict['values'], list)
135137

136-
assert time_dict['start'] == '2000-02-15T16:29:05.999999999'
137-
assert time_dict['stop'] == '2000-06-16T10:25:30.000000000'
138-
assert time_dict['num'] == 5
138+
t_values = [
139+
'2000-02-15T16:29:05.999999999',
140+
'2000-03-17T02:58:12.000000000',
141+
'2000-04-16T13:27:18.000000000',
142+
'2000-05-16T23:56:24.000000000',
143+
'2000-06-16T10:25:30.000000000'
144+
]
145+
146+
assert sorted(time_dict['values']) == t_values
139147

140148
# unbounded date range - start
141149
req = mock_api_request({
@@ -147,11 +155,20 @@ def test_get_collection_edr_query(config, api_):
147155
assert code == HTTPStatus.OK
148156

149157
data = json.loads(response)
150-
time_dict = data['domain']['axes']['TIME']
158+
time_dict = data['domain']['axes']['t']
159+
assert isinstance(time_dict, dict)
160+
assert isinstance(time_dict['values'], list)
161+
162+
t_values = [
163+
'2000-01-16T06:00:00.000000000',
164+
'2000-02-15T16:29:05.999999999',
165+
'2000-03-17T02:58:12.000000000',
166+
'2000-04-16T13:27:18.000000000',
167+
'2000-05-16T23:56:24.000000000',
168+
'2000-06-16T10:25:30.000000000'
169+
]
151170

152-
assert time_dict['start'] == '2000-01-16T06:00:00.000000000'
153-
assert time_dict['stop'] == '2000-06-16T10:25:30.000000000'
154-
assert time_dict['num'] == 6
171+
assert sorted(time_dict['values']) == t_values
155172

156173
# unbounded date range - end
157174
req = mock_api_request({
@@ -163,11 +180,21 @@ def test_get_collection_edr_query(config, api_):
163180
assert code == HTTPStatus.OK
164181

165182
data = json.loads(response)
166-
time_dict = data['domain']['axes']['TIME']
167-
168-
assert time_dict['start'] == '2000-06-16T10:25:30.000000000'
169-
assert time_dict['stop'] == '2000-12-16T01:20:05.999999996'
170-
assert time_dict['num'] == 7
183+
time_dict = data['domain']['axes']['t']
184+
assert isinstance(time_dict, dict)
185+
assert isinstance(time_dict['values'], list)
186+
187+
t_values = [
188+
'2000-06-16T10:25:30.000000000',
189+
'2000-07-16T20:54:36.000000000',
190+
'2000-08-16T07:23:42.000000000',
191+
'2000-09-15T17:52:48.000000000',
192+
'2000-10-16T04:21:54.000000000',
193+
'2000-11-15T14:51:00.000000000',
194+
'2000-12-16T01:20:05.999999996'
195+
]
196+
197+
assert sorted(time_dict['values']) == t_values
171198

172199
# some data
173200
req = mock_api_request({

tests/test_django.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,4 @@ def test_django_edr_without_instance_id(django_):
3838
# Validate CoverageJSON is returned
3939
response_json = response.json()
4040
assert response_json["type"] == "Coverage"
41-
assert response_json["domain"]["domainType"] == "Grid"
41+
assert response_json["domain"]["domainType"] == "PointSeries"

0 commit comments

Comments
 (0)