Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions libs/unity-py/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.10.1] - 2025-03-04

### Added

### Fixed

* Do not fail on case insensitive portion of collection id in DataService::create_collection routine
* Fixed error handling of DataService routines to use .text instead of the invalid .message attrbute of the response object
* Cleaned up JSON submitted by DataService::create_collection to not contain less random values

### Changed

* Enforce a specific capitalization for the case insensitive portion of a collection id in DataService::create_collection
* DataService::create_collection now returns the JSON it submitted to the API

## [0.10.0] - 2025-02-19

### Added
Expand Down
2 changes: 1 addition & 1 deletion libs/unity-py/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "unity-sds-client"
version = "0.10.0"
version = "0.10.1"

description = "Unity-Py is a Python client to simplify interactions with NASA's Unity Platform."
authors = ["Anil Natha, Mike Gangl"]
Expand Down
69 changes: 30 additions & 39 deletions libs/unity-py/unity_sds_client/services/data_service.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import re
import requests

from datetime import datetime, timezone

from unity_sds_client.unity_exception import UnityException
from unity_sds_client.unity_session import UnitySession
from unity_sds_client.resources.collection import Collection
from unity_sds_client.resources.dataset import Dataset
from unity_sds_client.resources.data_file import DataFile

# All capitals to match the unity-dataservices stage-out convention
UNITY_COLLECTION_INVARIANT_PREFIX = "URN:NASA:UNITY"

class DataService(object):
"""
Expand Down Expand Up @@ -95,50 +100,33 @@ def create_collection(self, collection: type = Collection, dry_run=False):
if collection is None:
raise UnityException("Invalid collection provided.")

# test version Information?

# Test collection ID name: project and venue
if self._session._project is None or self._session._venue is None:
raise UnityException("To create a collection, the Unity session Project and Venue must be set!")

if not collection.collection_id.startswith(f"urn:nasa:unity:{self._session._project}:{self._session._venue}"):
raise UnityException(f"Collection Identifiers must start with urn:nasa:unity:{self._session._project}:{self._session._venue}")
# Enusure the collection ID contains a prefix that conforms to expectations, testing in a case insensitive manner
# But promoting to the preferred case
submission_collection_id = collection.collection_id

if not re.search(rf'^{UNITY_COLLECTION_INVARIANT_PREFIX}', submission_collection_id, re.IGNORECASE):
raise UnityException(f"Collection Identifiers must start with {UNITY_COLLECTION_INVARIANT_PREFIX}")

collection = {
"title": "Collection " + collection.collection_id,
# Make the prefix conform to expected formatting (case) to ensure consistency across services
submission_collection_id = re.sub(rf'^{UNITY_COLLECTION_INVARIANT_PREFIX}', UNITY_COLLECTION_INVARIANT_PREFIX, submission_collection_id, flags=re.IGNORECASE)

if not submission_collection_id.startswith(f"{UNITY_COLLECTION_INVARIANT_PREFIX}:{self._session._project}:{self._session._venue}"):
raise UnityException(f"Collection Identifiers must start with {UNITY_COLLECTION_INVARIANT_PREFIX}:{self._session._project}:{self._session._venue}")

collection_json = {
"title": "Collection " + submission_collection_id,
"type": "Collection",
"id": collection.collection_id,
"id": submission_collection_id,
"stac_version": "1.0.0",
"description": "TODO",
"description": "Collection " + submission_collection_id,
"providers": [
{"name": "unity"}
],
"links": [
{
"rel": "root",
"href": "./collection.json?bucket=unknown_bucket&regex=%7BcmrMetadata.Granule.Collection.ShortName%7D___%7BcmrMetadata.Granule.Collection.VersionId%7D",
"type": "application/json",
"title": "test_file01.nc"
},
{
"rel": "item",
"href": "./collection.json?bucket=protected&regex=%5Etest_file.%2A%5C.nc%24",
"type": "data",
"title": "test_file01.nc"
},
{
"rel": "item",
"href": "./collection.json?bucket=protected&regex=%5Etest_file.%2A%5C.nc%5C.cas%24",
"type": "metadata",
"title": "test_file01.nc.cas"
},
{
"rel": "item",
"href": "./collection.json?bucket=private&regex=%5Etest_file.%2A%5C.cmr%5C.xml%24",
"type": "metadata",
"title": "test_file01.cmr.xml"
}
],
"links": [],
"stac_extensions": [],
"extent": {
"spatial": {
Expand All @@ -154,8 +142,8 @@ def create_collection(self, collection: type = Collection, dry_run=False):
"temporal": {
"interval": [
[
"2022-10-04T00:00:00.000Z",
"2022-10-04T23:59:59.999Z"
datetime.now(timezone.utc).isoformat(),
datetime.now(timezone.utc).isoformat()
]
]
}
Expand All @@ -176,9 +164,12 @@ def create_collection(self, collection: type = Collection, dry_run=False):
if not dry_run:
url = self.endpoint + f'am-uds-dapa/collections'
token = self._session.get_auth().get_token()
response = requests.post(url, headers={"Authorization": "Bearer " + token}, json=collection)
response = requests.post(url, headers={"Authorization": "Bearer " + token}, json=collection_json)

if response.status_code != 202:
raise UnityException("Error creating collection: " + response.message)
raise UnityException(f"Error creating collection: " + response.text)

return collection_json

def define_custom_metadata(self, metadata: dict):
if self._session._project is None or self._session._venue is None:
Expand All @@ -189,7 +180,7 @@ def define_custom_metadata(self, metadata: dict):
response = requests.put(url, headers={"Authorization": "Bearer " + token},
params={"venue": self._session._venue}, json=metadata)
if response.status_code != 200:
raise UnityException("Error adding custom metadata: " + response.message)
raise UnityException("Error adding custom metadata: " + response.text)

def delete_collection_item(self, collection: type = Collection, granule_id: str = None):
"""
Expand Down