def test_item_deserialization_end_date_before_start_date(self): today = datetime.utcnow() yesterday = today - timedelta(days=1) sample = self.data_factory.create_item_sample( collection=self.collection.model, sample='item-1', properties={ 'start_datetime': isoformat(utc_aware(today)), "end_datetime": isoformat(utc_aware(yesterday)) }) # translate to Python native: serializer = ItemSerializer(data=sample.get_json('deserialize')) with self.assertRaises(ValidationError): serializer.is_valid(raise_exception=True)
def to_representation(self, instance): ret = super().to_representation(instance) start = instance.extent_start_datetime end = instance.extent_end_datetime if start is not None: start = isoformat(start) if end is not None: end = isoformat(end) ret["temporal_extent"] = {"interval": [[start, end]]} return ret["temporal_extent"]
def test_item_deserialization_update_remove_title(self): original_sample = self.data_factory.create_item_sample( collection=self.collection.model, sample='item-1', ) sample = self.data_factory.create_item_sample( collection=self.collection.model, sample='item-2', name=original_sample["name"], properties={"datetime": isoformat(utc_aware(datetime.utcnow()))}) serializer = ItemSerializer(original_sample.model, data=sample.get_json('deserialize')) serializer.is_valid(raise_exception=True) item = serializer.save() # mock a request needed for the serialization of links context = { 'request': api_request_mocker.get( f'{STAC_BASE_V}/collections/{self.collection["name"]}/items/{sample["name"]}' ) } serializer = ItemSerializer(item, context=context) python_native = serializer.data self.check_stac_item(sample.json, python_native, self.collection["name"]) self.assertNotIn('title', python_native['properties'].keys(), msg="Title was not removed")
def get_extent(self, obj): start = obj.extent_start_datetime end = obj.extent_end_datetime if start is not None: start = isoformat(start) if end is not None: end = isoformat(end) bbox = [] if obj.extent_geometry is not None: bbox = list(GEOSGeometry(obj.extent_geometry).extent) return { "spatial": { "bbox": [bbox] }, "temporal": { "interval": [[start, end]] }, }
def _get_properties(self): properties = {} for attribute in self.__dict__: if not attribute.startswith('attr_properties_'): continue key = attribute[16:] value = getattr(self, attribute) properties[key] = value if key.endswith('datetime') and isinstance(value, datetime): properties[key] = isoformat(value) return properties
def create_presigned_url(self, key, asset, part, upload_id, part_md5): '''Create a presigned url for an upload part on the backend Args: key: string key on the S3 backend for which we want to create a presigned url upload part asset: Asset Asset metadata model associated with the S3 backend key part: int Part number for which to create a presigned url for upload part upload_id: string Upload ID for which to create a presigned url part_md5: string base64 MD5 digest of the part Returns: dict(string, int, datetime) Dict {'url': string, 'part': int, 'expires': datetime} ''' expires = utc_aware(datetime.utcnow() + timedelta( seconds=settings.AWS_PRESIGNED_URL_EXPIRES)) params = { 'Bucket': settings.AWS_STORAGE_BUCKET_NAME, 'Key': key, 'UploadId': upload_id, 'PartNumber': part, 'ContentMD5': part_md5, } url = self.call_s3_api(self.s3.generate_presigned_url, 'upload_part', Params=params, ExpiresIn=settings.AWS_PRESIGNED_URL_EXPIRES, HttpMethod='PUT', log_extra={ 'collection': asset.item.collection.name, 'item': asset.item.name, 'asset': asset.name, 'upload_id': upload_id }) logger.info('Presigned url %s for %s part %s with expires %s created', url, key, part, isoformat(expires), extra={ 'upload_id': upload_id, 'asset': asset.name }) return {'url': url, 'part': part, 'expires': expires}
def get_aborted(self, obj): if obj.status == AssetUpload.Status.ABORTED: return isoformat(obj.ended) return None
def get_completed(self, obj): if obj.status == AssetUpload.Status.COMPLETED: return isoformat(obj.ended) return None
def test_collection_serialization(self): collection_name = self.collection.model.name # mock a request needed for the serialization of links context = { 'request': api_request_mocker.get( f'{STAC_BASE_V}/collections/{collection_name}') } # transate to Python native: serializer = CollectionSerializer(self.collection.model, context=context) python_native = serializer.data logger.debug('python native:\n%s', pformat(python_native)) # translate to JSON: content = JSONRenderer().render(python_native) logger.debug('json string: %s', content.decode("utf-8")) expected = self.collection.get_json('serialize') expected.update({ 'created': isoformat(self.collection_created), 'crs': ['http://www.opengis.net/def/crs/OGC/1.3/CRS84'], 'extent': OrderedDict([('spatial', { 'bbox': [[5.644711, 46.775054, 7.602408, 49.014995]] }), ('temporal', { 'interval': [['2020-10-28T13:05:10Z', '2020-10-28T13:05:10Z']] })]), 'itemType': 'Feature', 'links': [ OrderedDict([ ('rel', 'self'), ('href', f'http://testserver/api/stac/v0.9/collections/{collection_name}' ), ]), OrderedDict([ ('rel', 'root'), ('href', 'http://testserver/api/stac/v0.9/'), ]), OrderedDict([ ('rel', 'parent'), ('href', 'http://testserver/api/stac/v0.9/collections'), ]), OrderedDict([ ('rel', 'items'), ('href', f'http://testserver/api/stac/v0.9/collections/{collection_name}/items' ), ]), OrderedDict([ ('href', 'https://www.example.com/described-by'), ('rel', 'describedBy'), ('type', 'description'), ('title', 'This is an extra link'), ]) ], 'providers': [ { 'name': 'provider-1', 'roles': ['licensor', 'producer'], 'description': 'This is a full description of the provider', 'url': 'https://www.provider.com' }, { 'name': 'provider-2', 'roles': ['licensor'], 'description': 'This is a full description of a second provider', 'url': 'https://www.provider.com/provider-2' }, { 'name': 'provider-3', }, ], 'stac_extensions': [ 'eo', 'proj', 'view', 'https://data.geo.admin.ch/stac/geoadmin-extension/1.0/schema.json' ], 'stac_version': settings.STAC_VERSION, 'summaries': { 'eo:gsd': [3.4], 'geoadmin:variant': ['kgrs'], 'proj:epsg': [2056], }, 'updated': isoformat(self.collection_created) }) self.check_stac_collection(expected, python_native)
def test_empty_collection_serialization(self): collection_name = self.collection.model.name # mock a request needed for the serialization of links context = { 'request': api_request_mocker.get( f'{STAC_BASE_V}/collections/{collection_name}') } # transate to Python native: serializer = CollectionSerializer(self.collection.model, context=context) python_native = serializer.data logger.debug('python native:\n%s', pformat(python_native)) # translate to JSON: content = JSONRenderer().render(python_native) logger.debug('json string: %s', content.decode("utf-8")) expected = self.collection.get_json('serialize') expected.update({ 'created': isoformat(self.collection_created), 'crs': ['http://www.opengis.net/def/crs/OGC/1.3/CRS84'], 'extent': { 'spatial': { 'bbox': [[]] }, 'temporal': { 'interval': [[None, None]] } }, 'itemType': 'Feature', 'links': [ OrderedDict([ ('rel', 'self'), ('href', f'http://testserver/api/stac/v0.9/collections/{collection_name}' ), ]), OrderedDict([ ('rel', 'root'), ('href', 'http://testserver/api/stac/v0.9/'), ]), OrderedDict([ ('rel', 'parent'), ('href', 'http://testserver/api/stac/v0.9/'), ]), OrderedDict([ ('rel', 'items'), ('href', f'http://testserver/api/stac/v0.9/collections/{collection_name}/items' ), ]), OrderedDict([ ('href', 'https://www.example.com/described-by'), ('rel', 'describedBy'), ('type', 'description'), ('title', 'This is an extra collection link'), ]) ], 'providers': [ { 'name': 'provider-1', 'roles': ['licensor', 'producer'], 'description': 'This is a full description of the provider', 'url': 'https://www.provider.com' }, { 'name': 'provider-2', 'roles': ['licensor'], 'description': 'This is a full description of a second provider', 'url': 'https://www.provider.com/provider-2' }, { 'name': 'provider-3', }, ], 'stac_version': settings.STAC_VERSION, 'summaries': {}, 'updated': isoformat(self.collection_created) }) self.check_stac_collection(expected, python_native)