Skip to content

Commit fcb69fd

Browse files
authored
Merge pull request #272 from volaya/set_property
Extract method to correctly handle setting properties in Item/Asset for ItemExtensions
2 parents 4728fab + fbd3004 commit fcb69fd

File tree

7 files changed

+56
-114
lines changed

7 files changed

+56
-114
lines changed

pystac/extensions/base.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,30 @@ def enable_extension(cls, stac_object):
121121
"""
122122
pass
123123

124+
def _set_property(self, key, value, asset):
125+
'''
126+
Set an Item or an Asset property.
127+
128+
If an Asset is supplied, sets the property on the Asset.
129+
Otherwise sets the Item's value.
130+
131+
If the passed value to set is None, the property key is removed from
132+
the dictionary of properties.
133+
134+
It's recommended to use this method from extensions, instead of implementing
135+
the logic for that in the corresponding subclasses.
136+
137+
Args:
138+
key (str): The name of the property
139+
value (Object): the value to set
140+
asset: The Asset to modify. If None, the property will be set in the Item
141+
'''
142+
target = self.item.properties if asset is None else asset.properties
143+
if value is None:
144+
target.pop(key, None)
145+
else:
146+
target[key] = value
147+
124148

125149
class RegisteredSTACExtensions:
126150
def __init__(self, extension_definitions):

pystac/extensions/eo.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,7 @@ def set_bands(self, bands, asset=None):
8585
Otherwise sets the Item's value.
8686
"""
8787
band_dicts = [b.to_dict() for b in bands]
88-
if asset is not None:
89-
asset.properties['eo:bands'] = band_dicts
90-
else:
91-
self.item.properties['eo:bands'] = band_dicts
88+
self._set_property('eo:bands', band_dicts, asset)
9289

9390
@property
9491
def cloud_cover(self):
@@ -124,10 +121,7 @@ def set_cloud_cover(self, cloud_cover, asset=None):
124121
If an Asset is supplied, sets the property on the Asset.
125122
Otherwise sets the Item's value.
126123
"""
127-
if asset is None:
128-
self.item.properties['eo:cloud_cover'] = cloud_cover
129-
else:
130-
asset.properties['eo:cloud_cover'] = cloud_cover
124+
self._set_property('eo:cloud_cover', cloud_cover, asset)
131125

132126
def __repr__(self):
133127
return '<EOItemExt Item id={}>'.format(self.item.id)

pystac/extensions/pointcloud.py

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,7 @@ def set_count(self, count, asset=None):
7979
If an Asset is supplied, sets the property on the Asset.
8080
Otherwise sets the Item's value.
8181
"""
82-
if asset is None:
83-
self.item.properties['pc:count'] = count
84-
else:
85-
asset.properties['pc:count'] = count
82+
self._set_property('pc:count', count, asset)
8683

8784
@property
8885
def type(self):
@@ -117,10 +114,7 @@ def set_type(self, type, asset=None):
117114
If an Asset is supplied, sets the property on the Asset.
118115
Otherwise sets the Item's value.
119116
"""
120-
if asset is None:
121-
self.item.properties['pc:type'] = type
122-
else:
123-
asset.properties['pc:type'] = type
117+
self._set_property('pc:type', type, asset)
124118

125119
@property
126120
def encoding(self):
@@ -158,10 +152,7 @@ def set_encoding(self, encoding, asset=None):
158152
If an Asset is supplied, sets the property on the Asset.
159153
Otherwise sets the Item's value.
160154
"""
161-
if asset is None:
162-
self.item.properties['pc:encoding'] = encoding
163-
else:
164-
asset.properties['pc:encoding'] = encoding
155+
self._set_property('pc:encoding', encoding, asset)
165156

166157
@property
167158
def schemas(self):
@@ -202,10 +193,7 @@ def set_schemas(self, schemas, asset=None):
202193
Otherwise sets the Item's value.
203194
"""
204195
dicts = [s.to_dict() for s in schemas]
205-
if asset is None:
206-
self.item.properties['pc:schemas'] = dicts
207-
else:
208-
asset.properties['pc:schemas'] = dicts
196+
self._set_property('pc:schemas', dicts, asset)
209197

210198
@property
211199
def density(self):
@@ -242,10 +230,7 @@ def set_density(self, density, asset=None):
242230
If an Asset is supplied, sets the property on the Asset.
243231
Otherwise sets the Item's value.
244232
"""
245-
if asset is None:
246-
self.item.properties['pc:density'] = density
247-
else:
248-
asset.properties['pc:density'] = density
233+
self._set_property('pc:density', density, asset)
249234

250235
@property
251236
def statistics(self):
@@ -289,10 +274,7 @@ def set_statistics(self, statistics, asset=None):
289274
"""
290275
if statistics is not None:
291276
statistics = [s.to_dict() for s in statistics]
292-
if asset is None:
293-
self.item.properties['pc:statistics'] = statistics
294-
else:
295-
asset.properties['pc:statistics'] = statistics
277+
self._set_property('pc:statistics', statistics, asset)
296278

297279
@classmethod
298280
def _object_links(cls):

pystac/extensions/projection.py

Lines changed: 15 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,7 @@ def set_epsg(self, epsg, asset=None):
103103
If an Asset is supplied, sets the property on the Asset.
104104
Otherwise sets the Item's value.
105105
"""
106-
if asset is None:
107-
self.item.properties['proj:epsg'] = epsg
108-
else:
109-
asset.properties['proj:epsg'] = epsg
106+
self._set_property('proj:epsg', epsg, asset)
110107

111108
@property
112109
def wkt2(self):
@@ -141,18 +138,13 @@ def get_wkt2(self, asset=None):
141138
else:
142139
return asset.properties.get('proj:wkt2')
143140

144-
def set_wkt2(self, value, asset=None):
141+
def set_wkt2(self, wkt2, asset=None):
145142
"""Set an Item or an Asset wkt2.
146143
147144
If an Asset is supplied, sets the property on the Asset.
148145
Otherwise sets the Item's value.
149146
"""
150-
key = 'proj:wkt2'
151-
target = self.item.properties if asset is None else asset.properties
152-
if value is None:
153-
target.pop(key, None)
154-
else:
155-
target[key] = value
147+
self._set_property('proj:wkt2', wkt2, asset)
156148

157149
@property
158150
def projjson(self):
@@ -190,18 +182,13 @@ def get_projjson(self, asset=None):
190182
else:
191183
return asset.properties.get('proj:projjson')
192184

193-
def set_projjson(self, value, asset=None):
185+
def set_projjson(self, projjson, asset=None):
194186
"""Set an Item or an Asset projjson.
195187
196188
If an Asset is supplied, sets the property on the Asset.
197189
Otherwise sets the Item's value.
198190
"""
199-
key = 'proj:projjson'
200-
target = self.item.properties if asset is None else asset.properties
201-
if value is None:
202-
target.pop(key, None)
203-
else:
204-
target[key] = value
191+
self._set_property('proj:projjson', projjson, asset)
205192

206193
@property
207194
def geometry(self):
@@ -237,18 +224,13 @@ def get_geometry(self, asset=None):
237224
else:
238225
return asset.properties.get('proj:geometry')
239226

240-
def set_geometry(self, value, asset=None):
227+
def set_geometry(self, geometry, asset=None):
241228
"""Set an Item or an Asset projection geometry.
242229
243230
If an Asset is supplied, sets the property on the Asset.
244231
Otherwise sets the Item's value.
245232
"""
246-
key = 'proj:geometry'
247-
target = self.item.properties if asset is None else asset.properties
248-
if value is None:
249-
target.pop(key, None)
250-
else:
251-
target[key] = value
233+
self._set_property('proj:geometry', geometry, asset)
252234

253235
@property
254236
def bbox(self):
@@ -285,18 +267,13 @@ def get_bbox(self, asset=None):
285267
else:
286268
return asset.properties.get('proj:bbox')
287269

288-
def set_bbox(self, value, asset=None):
270+
def set_bbox(self, bbox, asset=None):
289271
"""Set an Item or an Asset projection bbox.
290272
291273
If an Asset is supplied, sets the property on the Asset.
292274
Otherwise sets the Item's value.
293275
"""
294-
key = 'proj:bbox'
295-
target = self.item.properties if asset is None else asset.properties
296-
if value is None:
297-
target.pop(key, None)
298-
else:
299-
target[key] = value
276+
self._set_property('proj:bbox', bbox, asset)
300277

301278
@property
302279
def centroid(self):
@@ -332,18 +309,13 @@ def get_centroid(self, asset=None):
332309
else:
333310
return asset.properties.get('proj:centroid')
334311

335-
def set_centroid(self, value, asset=None):
312+
def set_centroid(self, centroid, asset=None):
336313
"""Set an Item or an Asset centroid.
337314
338315
If an Asset is supplied, sets the property on the Asset.
339316
Otherwise sets the Item's value.
340317
"""
341-
key = 'proj:centroid'
342-
target = self.item.properties if asset is None else asset.properties
343-
if value is None:
344-
target.pop(key, None)
345-
else:
346-
target[key] = value
318+
self._set_property('proj:centroid', centroid, asset)
347319

348320
@property
349321
def shape(self):
@@ -377,18 +349,13 @@ def get_shape(self, asset=None):
377349
else:
378350
return asset.properties.get('proj:shape')
379351

380-
def set_shape(self, value, asset=None):
352+
def set_shape(self, shape, asset=None):
381353
"""Set an Item or an Asset shape.
382354
383355
If an Asset is supplied, sets the property on the Asset.
384356
Otherwise sets the Item's value.
385357
"""
386-
key = 'proj:shape'
387-
target = self.item.properties if asset is None else asset.properties
388-
if value is None:
389-
target.pop(key, None)
390-
else:
391-
target[key] = value
358+
self._set_property('proj:shape', shape, asset)
392359

393360
@property
394361
def transform(self):
@@ -425,18 +392,13 @@ def get_transform(self, asset=None):
425392
else:
426393
return asset.properties.get('proj:transform')
427394

428-
def set_transform(self, value, asset=None):
395+
def set_transform(self, transform, asset=None):
429396
"""Set an Item or an Asset transform.
430397
431398
If an Asset is supplied, sets the property on the Asset.
432399
Otherwise sets the Item's value.
433400
"""
434-
key = 'proj:transform'
435-
target = self.item.properties if asset is None else asset.properties
436-
if value is None:
437-
target.pop(key, None)
438-
else:
439-
target[key] = value
401+
self._set_property('proj:transform', transform, asset)
440402

441403
@classmethod
442404
def _object_links(cls):

pystac/extensions/timestamps.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,9 @@ def _timestamp_getter(self, key, asset=None):
6666
return timestamp
6767

6868
def _timestamp_setter(self, timestamp, key, asset=None):
69-
if timestamp is None:
70-
self.item.properties[key] = timestamp
71-
else:
72-
timestamp_str = datetime_to_str(timestamp)
73-
if asset is not None:
74-
asset.properties[key] = timestamp_str
75-
else:
76-
self.item.properties[key] = timestamp_str
69+
if timestamp is not None:
70+
timestamp = datetime_to_str(timestamp)
71+
self._set_property(key, timestamp, asset)
7772

7873
@property
7974
def published(self):

pystac/extensions/view.py

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,7 @@ def set_off_nadir(self, off_nadir, asset=None):
101101
If an Asset is supplied, sets the property on the Asset.
102102
Otherwise sets the Item's value.
103103
"""
104-
if asset is None:
105-
self.item.properties['view:off_nadir'] = off_nadir
106-
else:
107-
asset.properties['view:off_nadir'] = off_nadir
104+
self._set_property('view:off_nadir', off_nadir, asset)
108105

109106
@property
110107
def incidence_angle(self):
@@ -141,10 +138,7 @@ def set_incidence_angle(self, incidence_angle, asset=None):
141138
If an Asset is supplied, sets the property on the Asset.
142139
Otherwise sets the Item's value.
143140
"""
144-
if asset is None:
145-
self.item.properties['view:incidence_angle'] = incidence_angle
146-
else:
147-
asset.properties['view:incidence_angle'] = incidence_angle
141+
self._set_property('view:incidence_angle', incidence_angle, asset)
148142

149143
@property
150144
def azimuth(self):
@@ -181,10 +175,7 @@ def set_azimuth(self, azimuth, asset=None):
181175
If an Asset is supplied, sets the property on the Asset.
182176
Otherwise sets the Item's value.
183177
"""
184-
if asset is None:
185-
self.item.properties['view:azimuth'] = azimuth
186-
else:
187-
asset.properties['view:azimuth'] = azimuth
178+
self._set_property('view:azimuth', azimuth, asset)
188179

189180
@property
190181
def sun_azimuth(self):
@@ -220,10 +211,7 @@ def set_sun_azimuth(self, sun_azimuth, asset=None):
220211
If an Asset is supplied, sets the property on the Asset.
221212
Otherwise sets the Item's value.
222213
"""
223-
if asset is None:
224-
self.item.properties['view:sun_azimuth'] = sun_azimuth
225-
else:
226-
asset.properties['view:sun_azimuth'] = sun_azimuth
214+
self._set_property('view:sun_azimuth', sun_azimuth, asset)
227215

228216
@property
229217
def sun_elevation(self):
@@ -259,10 +247,7 @@ def set_sun_elevation(self, sun_elevation, asset=None):
259247
If an Asset is supplied, sets the property on the Asset.
260248
Otherwise sets the Item's value.
261249
"""
262-
if asset is None:
263-
self.item.properties['view:sun_elevation'] = sun_elevation
264-
else:
265-
asset.properties['view:sun_elevation'] = sun_elevation
250+
self._set_property('view:sun_elevation', sun_elevation, asset)
266251

267252
@classmethod
268253
def _object_links(cls):

tests/extensions/test_timestamps.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def test_apply(self):
5050
self.assertIsNone(d)
5151

5252
for p in ('expires', 'unpublished'):
53-
self.assertIsNone(item.properties[p])
53+
self.assertNotIn(p, item.properties)
5454

5555
def test_validate_timestamps(self):
5656
item = pystac.read_file(self.example_uri)

0 commit comments

Comments
 (0)