From c5d20a6e2b4f43565d5b7f5afea9f4ce04bc79e1 Mon Sep 17 00:00:00 2001 From: jniestroy Date: Mon, 9 Mar 2026 11:15:33 -0400 Subject: [PATCH 1/5] changes --- mds/src/fairscape_mds/crud/resolver.py | 29 +++++++++++++++++++++-- mds/src/fairscape_mds/routers/resolver.py | 9 +++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/mds/src/fairscape_mds/crud/resolver.py b/mds/src/fairscape_mds/crud/resolver.py index 72d2a56..9b15ced 100644 --- a/mds/src/fairscape_mds/crud/resolver.py +++ b/mds/src/fairscape_mds/crud/resolver.py @@ -1,4 +1,5 @@ import logging +import re from fairscape_mds.crud.fairscape_request import FairscapeRequest from fairscape_mds.crud.fairscape_response import FairscapeResponse from fairscape_mds.models.identifier import StoredIdentifier @@ -8,11 +9,35 @@ class FairscapeResolverRequest(FairscapeRequest): - def resolveIdentifier(self, guid: str): + def resolveIdentifier(self, guid: str): + # Step 1: Exact match (fast path) foundMetadata = self.config.identifierCollection.find_one( {"@id": guid}, projection={"_id": False} - ) + ) + + # Step 2: Normalize ark:/ to ark: and retry + if not foundMetadata: + normalized_guid = re.sub(r'^ark:/', 'ark:', guid) + if normalized_guid != guid: + foundMetadata = self.config.identifierCollection.find_one( + {"@id": normalized_guid}, + projection={"_id": False} + ) + + # Step 3: Dash-insensitive regex search + if not foundMetadata: + ark_match = re.match(r'^ark:/?([\d]+)/(.*)', guid) + if ark_match: + naan = ark_match.group(1) + postfix = ark_match.group(2) + stripped = postfix.replace('-', '') + fuzzy_postfix = '-?'.join(re.escape(c) for c in stripped) + pattern = f'^ark:{naan}/{fuzzy_postfix}$' + foundMetadata = self.config.identifierCollection.find_one( + {"@id": {"$regex": pattern}}, + projection={"_id": False} + ) if not foundMetadata: return FairscapeResponse( diff --git a/mds/src/fairscape_mds/routers/resolver.py b/mds/src/fairscape_mds/routers/resolver.py index 80158a3..0181d2c 100644 --- a/mds/src/fairscape_mds/routers/resolver.py +++ b/mds/src/fairscape_mds/routers/resolver.py @@ -70,6 +70,15 @@ def resolveARK( ) +@resolverRouter.get("/ark:/{NAAN}/{postfix}") +def resolveARKWithSlash( + NAAN: str, + postfix: str, + accept: Optional[str] = Header(default="application/json") +): + return resolveARK(NAAN, postfix, accept) + + @resolverRouter.put("/ark:{NAAN}/{postfix}") def updateARK( currentUser: Annotated[UserWriteModel, Depends(getCurrentUser)], From 800e57e47226c13542d83d51e8e4d3be5b71476e Mon Sep 17 00:00:00 2001 From: jniestroy Date: Mon, 9 Mar 2026 14:56:45 -0400 Subject: [PATCH 2/5] lots more for rocrate endpoints --- .../fairscape_mds/crud/fairscape_request.py | 39 ++++++++++++++++++- mds/src/fairscape_mds/crud/identifier.py | 24 +++--------- mds/src/fairscape_mds/crud/resolver.py | 30 +------------- mds/src/fairscape_mds/crud/rocrate.py | 21 +++------- mds/src/fairscape_mds/routers/rocrate.py | 29 ++++++++++---- 5 files changed, 70 insertions(+), 73 deletions(-) diff --git a/mds/src/fairscape_mds/crud/fairscape_request.py b/mds/src/fairscape_mds/crud/fairscape_request.py index b976f65..3fab410 100644 --- a/mds/src/fairscape_mds/crud/fairscape_request.py +++ b/mds/src/fairscape_mds/crud/fairscape_request.py @@ -1,13 +1,48 @@ +import re from fairscape_mds.core.config import FairscapeConfig +def flexible_ark_query(guid: str): + """Build a MongoDB query that matches an ARK with or without dashes + and with or without a slash after 'ark:'. Returns None if guid + doesn't look like an ARK. Matches ARK SPEC""" + ark_match = re.match(r'^ark:/?([\d]+)/(.*)', guid) + if not ark_match: + return None + naan = ark_match.group(1) + postfix = ark_match.group(2) + stripped = postfix.replace('-', '') + fuzzy_postfix = '-?'.join(re.escape(c) for c in stripped) + pattern = f'^ark:{naan}/{fuzzy_postfix}$' + return {"@id": {"$regex": pattern}} + + class FairscapeRequest(): def __init__( - self, + self, backendConfig: FairscapeConfig ): self.config = backendConfig - + def getMetadata(self, guid: str): return self.config.identifierCollection.find_one({"@id": guid}, projection={"_id": False}) + def flexibleFind(self, guid: str, projection=None): + """Look up an identifier by exact match first, then fall back to + a dash-insensitive and ark:/ark: tolerant regex search.""" + if projection is None: + projection = {"_id": False} + # Exact match + result = self.config.identifierCollection.find_one( + {"@id": guid}, projection=projection + ) + if result: + return result + # Flexible fallback + query = flexible_ark_query(guid) + if query: + result = self.config.identifierCollection.find_one( + query, projection=projection + ) + return result + diff --git a/mds/src/fairscape_mds/crud/identifier.py b/mds/src/fairscape_mds/crud/identifier.py index f59ac19..305b575 100644 --- a/mds/src/fairscape_mds/crud/identifier.py +++ b/mds/src/fairscape_mds/crud/identifier.py @@ -38,12 +38,9 @@ class IdentifierRequest(FairscapeRequest): def getIdentifier(self, guid): """ Find Identifier metadata and marshal into a StoredIdentifier class """ - + # get the metadata for a stored identifier - datasetMetadata = self.config.identifierCollection.find_one( - {"@id": guid}, - projection={"_id": False} - ) + datasetMetadata = self.flexibleFind(guid) if not datasetMetadata: raise IdentifierNotFound( @@ -170,10 +167,7 @@ def getContent(self, guid: str)->FairscapeResponse: """ # get the metadata - metadata = self.config.identifierCollection.find_one( - {"@id": guid}, - projection={"_id": False} - ) + metadata = self.flexibleFind(guid) if not metadata: return FairscapeResponse( @@ -234,10 +228,7 @@ def updatePublicationStatus( newStatus = publicationChange.publicationStatus # get the identifier metadata - metadata = self.config.identifierCollection.find_one( - {"@id": guid}, - projection={"_id": False} - ) + metadata = self.flexibleFind(guid) if not metadata: return FairscapeResponse( @@ -246,7 +237,7 @@ def updatePublicationStatus( error={"error": "identifier not found"} ) - # serialize metadata into model + # serialize metadata into model try: foundIdentifier = StoredIdentifier.model_validate(metadata) except ValidationError as e: @@ -357,10 +348,7 @@ def updateMetadata( """ # check if identifier exists - foundMetadata = self.config.identifierCollection.find_one( - {"@id": guid}, - projection={"_id": False} - ) + foundMetadata = self.flexibleFind(guid) if not foundMetadata: return FairscapeResponse( diff --git a/mds/src/fairscape_mds/crud/resolver.py b/mds/src/fairscape_mds/crud/resolver.py index 9b15ced..4970ad3 100644 --- a/mds/src/fairscape_mds/crud/resolver.py +++ b/mds/src/fairscape_mds/crud/resolver.py @@ -1,5 +1,4 @@ import logging -import re from fairscape_mds.crud.fairscape_request import FairscapeRequest from fairscape_mds.crud.fairscape_response import FairscapeResponse from fairscape_mds.models.identifier import StoredIdentifier @@ -10,34 +9,7 @@ class FairscapeResolverRequest(FairscapeRequest): def resolveIdentifier(self, guid: str): - # Step 1: Exact match (fast path) - foundMetadata = self.config.identifierCollection.find_one( - {"@id": guid}, - projection={"_id": False} - ) - - # Step 2: Normalize ark:/ to ark: and retry - if not foundMetadata: - normalized_guid = re.sub(r'^ark:/', 'ark:', guid) - if normalized_guid != guid: - foundMetadata = self.config.identifierCollection.find_one( - {"@id": normalized_guid}, - projection={"_id": False} - ) - - # Step 3: Dash-insensitive regex search - if not foundMetadata: - ark_match = re.match(r'^ark:/?([\d]+)/(.*)', guid) - if ark_match: - naan = ark_match.group(1) - postfix = ark_match.group(2) - stripped = postfix.replace('-', '') - fuzzy_postfix = '-?'.join(re.escape(c) for c in stripped) - pattern = f'^ark:{naan}/{fuzzy_postfix}$' - foundMetadata = self.config.identifierCollection.find_one( - {"@id": {"$regex": pattern}}, - projection={"_id": False} - ) + foundMetadata = self.flexibleFind(guid) if not foundMetadata: return FairscapeResponse( diff --git a/mds/src/fairscape_mds/crud/rocrate.py b/mds/src/fairscape_mds/crud/rocrate.py index 65c89c0..845f244 100644 --- a/mds/src/fairscape_mds/crud/rocrate.py +++ b/mds/src/fairscape_mds/crud/rocrate.py @@ -1037,10 +1037,7 @@ def _build_rocrate_structure(self, root_guid: str, root_metadata: dict, parts: l } def getROCrateMetadata(self, rocrateGUID: str): - root_doc = self.config.identifierCollection.find_one( - {"@id": rocrateGUID}, - projection={"_id": False} - ) + root_doc = self.flexibleFind(rocrateGUID) if not root_doc: return FairscapeResponse( @@ -1084,12 +1081,7 @@ def getROCrateMetadata(self, rocrateGUID: str): def getROCrateMetadataElem(self, rocrateGUID: str): - rocrateMetadata = self.config.identifierCollection.find_one( - { - "@id": rocrateGUID - }, - projection={"_id": False} - ) + rocrateMetadata = self.flexibleFind(rocrateGUID) # if no metadata is found return 404 if not rocrateMetadata: @@ -1126,8 +1118,8 @@ def getROCrateContentSummary( """ # Only fetch the contentSummary field - rocrate_doc = self.config.identifierCollection.find_one( - {"@id": rocrateGUID}, + rocrate_doc = self.flexibleFind( + rocrateGUID, projection={ "_id": False, "contentSummary": 1, @@ -1222,10 +1214,7 @@ def downloadROCrateArchive( rocrateGUID: str ): - rocrateIdentifier = self.config.identifierCollection.find_one( - {"@id": rocrateGUID}, - projection={"_id": False} - ) + rocrateIdentifier = self.flexibleFind(rocrateGUID) # if no metadata is found return 404 if not rocrateIdentifier: diff --git a/mds/src/fairscape_mds/routers/rocrate.py b/mds/src/fairscape_mds/routers/rocrate.py index b1541d5..e73448d 100644 --- a/mds/src/fairscape_mds/routers/rocrate.py +++ b/mds/src/fairscape_mds/routers/rocrate.py @@ -17,6 +17,7 @@ import datetime from fairscape_mds.crud.rocrate import FairscapeROCrateRequest +from fairscape_mds.crud.fairscape_request import flexible_ark_query from fairscape_mds.models.user import UserWriteModel from fairscape_mds.models.identifier import StoredIdentifier @@ -35,6 +36,18 @@ rocrateRouter = APIRouter(prefix="", tags=['evi', 'rocrate']) +def _flexible_find(guid: str, projection=None): + """Exact match then dash/slash-tolerant fallback lookup.""" + if projection is None: + projection = {"_id": 0} + result = appConfig.identifierCollection.find_one({"@id": guid}, projection) + if not result: + query = flexible_ark_query(guid) + if query: + result = appConfig.identifierCollection.find_one(query, projection) + return result + + @rocrateRouter.post("/rocrate/upload-async") def uploadROCrate( currentUser: Annotated[UserWriteModel, Depends(getCurrentUser)], @@ -279,7 +292,7 @@ def get_or_create_ai_ready_score( ): ark_id = f"ark:{NAAN}/{postfix}" - entity = appConfig.identifierCollection.find_one({"@id": ark_id}, {"_id": 0}) + entity = _flexible_find(ark_id) if not entity: return JSONResponse( status_code=404, @@ -311,10 +324,10 @@ def get_or_create_ai_ready_score( status_code=400, content={"error": "Entity is not an RO-Crate or AI-Ready Score"} ) - + if entity.get("metadata", {}).get("hasAIReadyScore"): score_id = entity["metadata"]["hasAIReadyScore"].get("@id") - score_entity = appConfig.identifierCollection.find_one({"@id": score_id}, {"_id": 0}) + score_entity = _flexible_find(score_id) if score_entity: try: stored_identifier = StoredIdentifier.model_validate(score_entity) @@ -402,26 +415,26 @@ def rescore_ai_ready_score( ): ark_id = f"ark:{NAAN}/{postfix}" - entity = appConfig.identifierCollection.find_one({"@id": ark_id}, {"_id": 0}) + entity = _flexible_find(ark_id) if not entity: return JSONResponse( status_code=404, content={"error": f"Entity {ark_id} not found"} ) - + entity_type = entity.get("@type", []) if isinstance(entity_type, str): entity_type = [entity_type] - + is_rocrate = any("ROCrate" in t for t in entity_type) if not is_rocrate: return JSONResponse( status_code=400, content={"error": "Entity is not an RO-Crate"} ) - + score_id = f"{ark_id}-ai-ready-score" - existing_score = appConfig.identifierCollection.find_one({"@id": score_id}) + existing_score = _flexible_find(score_id) if not existing_score: return JSONResponse( status_code=404, From 750105ae30059150ea0856f8e5600aa697f111fd Mon Sep 17 00:00:00 2001 From: jniestroy Date: Mon, 9 Mar 2026 15:02:37 -0400 Subject: [PATCH 3/5] million more endpoints for / matching --- mds/src/fairscape_mds/routers/computation.py | 2 ++ mds/src/fairscape_mds/routers/dataset.py | 1 + mds/src/fairscape_mds/routers/evidence_graph.py | 9 +++++++++ mds/src/fairscape_mds/routers/publish.py | 2 ++ mds/src/fairscape_mds/routers/publish_router.py | 10 ++++++++++ mds/src/fairscape_mds/routers/resolver.py | 2 ++ mds/src/fairscape_mds/routers/rocrate.py | 17 +++++++++++++++++ mds/src/fairscape_mds/routers/schema.py | 2 ++ mds/src/fairscape_mds/routers/software.py | 2 ++ 9 files changed, 47 insertions(+) diff --git a/mds/src/fairscape_mds/routers/computation.py b/mds/src/fairscape_mds/routers/computation.py index 23d73e6..4831d36 100644 --- a/mds/src/fairscape_mds/routers/computation.py +++ b/mds/src/fairscape_mds/routers/computation.py @@ -35,6 +35,7 @@ def createComputation( ) +@computationRouter.get("/computation/ark:/{NAAN}/{postfix}") @computationRouter.get("/computation/ark:{NAAN}/{postfix}") def getComputationMetadata( NAAN: str, @@ -57,6 +58,7 @@ def getComputationMetadata( ) +@computationRouter.delete("/computation/ark:/{NAAN}/{postfix}") @computationRouter.delete("/computation/ark:{NAAN}/{postfix}") def deleteComputation( NAAN: str, diff --git a/mds/src/fairscape_mds/routers/dataset.py b/mds/src/fairscape_mds/routers/dataset.py index ccbe439..effe105 100644 --- a/mds/src/fairscape_mds/routers/dataset.py +++ b/mds/src/fairscape_mds/routers/dataset.py @@ -104,6 +104,7 @@ def getDatasetContent( ) +@datasetRouter.delete("/dataset/ark:/{NAAN}/{postfix}") @datasetRouter.delete("/dataset/ark:{NAAN}/{postfix}") def deleteDataset( NAAN: str, diff --git a/mds/src/fairscape_mds/routers/evidence_graph.py b/mds/src/fairscape_mds/routers/evidence_graph.py index 8ec2d85..868e034 100644 --- a/mds/src/fairscape_mds/routers/evidence_graph.py +++ b/mds/src/fairscape_mds/routers/evidence_graph.py @@ -33,6 +33,7 @@ def create_evidence_graph_route( else: raise HTTPException(status_code=response.statusCode, detail=response.error) +@router.get("/ark:/{NAAN}/{postfix}", response_model=StoredIdentifier, summary="Get an EvidenceGraph by its ARK ID") @router.get("/ark:{NAAN}/{postfix}", response_model=StoredIdentifier, summary="Get an EvidenceGraph by its ARK ID") def get_evidence_graph_route( NAAN: Annotated[str, Path(description="Name Assigning Authority Number of the ARK ID")], @@ -46,6 +47,7 @@ def get_evidence_graph_route( raise HTTPException(status_code=response.statusCode, detail=response.error) +@router.get("/query/ark:/{NAAN}/{postfix}", response_model=StoredIdentifier, summary="Get an EvidenceGraph by its ARK ID") @router.get("/query/ark:{NAAN}/{postfix}", response_model=StoredIdentifier, summary="Get an EvidenceGraph by its ARK ID") def get_evidence_graph_query_route( NAAN: Annotated[str, Path(description="Name Assigning Authority Number of the ARK ID")], @@ -60,6 +62,7 @@ def get_evidence_graph_query_route( raise HTTPException(status_code=response.statusCode, detail=response.error) +@router.delete("/ark:/{NAAN}/{postfix}", summary="Delete an EvidenceGraph by its ARK ID") @router.delete("/ark:{NAAN}/{postfix}", summary="Delete an EvidenceGraph by its ARK ID") def delete_evidence_graph_route( NAAN: Annotated[str, Path(description="Name Assigning Authority Number of the ARK ID")], @@ -84,6 +87,12 @@ def list_evidence_graphs_route(): else: raise HTTPException(status_code=response.statusCode, detail=response.error) +@router.post( + "/build/ark:/{NAAN}/{postfix}", + status_code=status.HTTP_202_ACCEPTED, + response_model=Dict, + summary="Initiate building or rebuilding the EvidenceGraph for a given node ARK ID" +) @router.post( "/build/ark:{NAAN}/{postfix}", status_code=status.HTTP_202_ACCEPTED, diff --git a/mds/src/fairscape_mds/routers/publish.py b/mds/src/fairscape_mds/routers/publish.py index e330fea..f45115a 100644 --- a/mds/src/fairscape_mds/routers/publish.py +++ b/mds/src/fairscape_mds/routers/publish.py @@ -40,6 +40,7 @@ def updatePublicationStatus( ) +@publishRouter.get(path="/view/ark:/{NAAN}/{postfix}") @publishRouter.get(path="/view/ark:{NAAN}/{postfix}") def viewContent( NAAN: str, @@ -77,6 +78,7 @@ def viewContent( ) +@publishRouter.get(path="/download/ark:/{NAAN}/{postfix}") @publishRouter.get(path="/download/ark:{NAAN}/{postfix}") def downloadContent( NAAN: str, diff --git a/mds/src/fairscape_mds/routers/publish_router.py b/mds/src/fairscape_mds/routers/publish_router.py index 7f71e8f..0ee3f68 100644 --- a/mds/src/fairscape_mds/routers/publish_router.py +++ b/mds/src/fairscape_mds/routers/publish_router.py @@ -18,6 +18,11 @@ publish_request_handler = FairscapePublishRequest(appConfig) +@router.post( + "/create/ark:/{NAAN}/{postfix}", + summary="Create a dataset on a publishing platform for an ROCrate", + response_description="Details of the created dataset and ROCrate update status" +) @router.post( "/create/ark:{NAAN}/{postfix}", summary="Create a dataset on a publishing platform for an ROCrate", @@ -57,6 +62,11 @@ async def create_dataset_endpoint( return JSONResponse(status_code=response.statusCode, content=response.model) +@router.post( + "/upload/ark:/{NAAN}/{postfix}", + summary="Upload ROCrate archive to an existing platform dataset", + response_description="Details of the file upload transaction." +) @router.post( "/upload/ark:{NAAN}/{postfix}", summary="Upload ROCrate archive to an existing platform dataset", diff --git a/mds/src/fairscape_mds/routers/resolver.py b/mds/src/fairscape_mds/routers/resolver.py index 0181d2c..4e354ac 100644 --- a/mds/src/fairscape_mds/routers/resolver.py +++ b/mds/src/fairscape_mds/routers/resolver.py @@ -79,6 +79,7 @@ def resolveARKWithSlash( return resolveARK(NAAN, postfix, accept) +@resolverRouter.put("/ark:/{NAAN}/{postfix}") @resolverRouter.put("/ark:{NAAN}/{postfix}") def updateARK( currentUser: Annotated[UserWriteModel, Depends(getCurrentUser)], @@ -107,6 +108,7 @@ def updateARK( ) +@resolverRouter.delete("/ark:/{NAAN}/{postfix}") @resolverRouter.delete("/ark:{NAAN}/{postfix}") def deleteARK( currentUser: Annotated[UserWriteModel, Depends(getCurrentUser)], diff --git a/mds/src/fairscape_mds/routers/rocrate.py b/mds/src/fairscape_mds/routers/rocrate.py index e73448d..458cfa5 100644 --- a/mds/src/fairscape_mds/routers/rocrate.py +++ b/mds/src/fairscape_mds/routers/rocrate.py @@ -153,6 +153,7 @@ def getUploadStatus( ) +@rocrateRouter.get("/rocrate/download/ark:/{NAAN}/{postfix}") @rocrateRouter.get("/rocrate/download/ark:{NAAN}/{postfix}") def getROCrateArchive( currentUser: Annotated[UserWriteModel, Depends(getCurrentUser)], @@ -189,6 +190,11 @@ def getROCrateArchive( ) +@rocrateRouter.get( + "/rocrate/summary/ark:/{NAAN}/{postfix}", + summary="Get a summary of RO-Crate contents", + response_description="Paginated list of datasets, software, computations, etc. with counts" +) @rocrateRouter.get( "/rocrate/summary/ark:{NAAN}/{postfix}", summary="Get a summary of RO-Crate contents", @@ -237,6 +243,7 @@ def getROCrateContentSummary( ) +@rocrateRouter.get("/rocrate/ark:/{NAAN}/{postfix}") @rocrateRouter.get("/rocrate/ark:{NAAN}/{postfix}") def getROCrateMetadata( request: Request, @@ -281,6 +288,11 @@ def getROCrateMetadata( content=response.model ) +@rocrateRouter.get( + "/rocrate/ai-ready-score/ark:/{NAAN}/{postfix}", + summary="Get or initiate AI-Ready Score for an RO-Crate (Public)", + response_description="AI-Ready Score or task status" +) @rocrateRouter.get( "/rocrate/ai-ready-score/ark:{NAAN}/{postfix}", summary="Get or initiate AI-Ready Score for an RO-Crate (Public)", @@ -404,6 +416,11 @@ def get_ai_ready_score_status( content=task_doc ) +@rocrateRouter.post( + "/rocrate/ai-ready-score/ark:/{NAAN}/{postfix}/rescore", + summary="Rescore an existing AI-Ready Score (Public)", + status_code=202 +) @rocrateRouter.post( "/rocrate/ai-ready-score/ark:{NAAN}/{postfix}/rescore", summary="Rescore an existing AI-Ready Score (Public)", diff --git a/mds/src/fairscape_mds/routers/schema.py b/mds/src/fairscape_mds/routers/schema.py index 98f9b9c..b71d90c 100644 --- a/mds/src/fairscape_mds/routers/schema.py +++ b/mds/src/fairscape_mds/routers/schema.py @@ -33,6 +33,7 @@ def createSchema( ) +@schemaRouter.get("/schema/ark:/{NAAN}/{postfix}") @schemaRouter.get("/schema/ark:{NAAN}/{postfix}") def getSchema( NAAN: str, @@ -51,6 +52,7 @@ def getSchema( ) +@schemaRouter.delete("/schema/ark:/{NAAN}/{postfix}") @schemaRouter.delete("/schema/ark:{NAAN}/{postfix}") def deleteSchema( NAAN: str, diff --git a/mds/src/fairscape_mds/routers/software.py b/mds/src/fairscape_mds/routers/software.py index fa2b42e..c939cf2 100644 --- a/mds/src/fairscape_mds/routers/software.py +++ b/mds/src/fairscape_mds/routers/software.py @@ -32,6 +32,7 @@ def createSoftware( ) +@softwareRouter.get("/software/ark:/{NAAN}/{postfix}") @softwareRouter.get("/software/ark:{NAAN}/{postfix}") def getSoftware( NAAN: str, @@ -50,6 +51,7 @@ def getSoftware( ) +@softwareRouter.delete("/software/ark:/{NAAN}/{postfix}") @softwareRouter.delete("/software/ark:{NAAN}/{postfix}") def deleteSoftware( NAAN: str, From e96c395a64d69f57cdb230d74cbfb7650f8acb6a Mon Sep 17 00:00:00 2001 From: jniestroy Date: Tue, 10 Mar 2026 16:23:03 -0400 Subject: [PATCH 4/5] latest models --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 3b7a813..4dc0a7e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,7 @@ classifiers = [ "Programming Language :: Python :: 3"] keywords = ["fairscape", "reproducibility", "fair"] dependencies = [ - "fairscape_models>=1.0.26", + "fairscape_models>=1.0.27", "fastapi>=0.109.0", "uvicorn>=0.27.0", "requests>=2.31.0", From 0ace7e7b52946626c9076fc6c3d1bdabb8904c13 Mon Sep 17 00:00:00 2001 From: jniestroy Date: Tue, 10 Mar 2026 16:40:35 -0400 Subject: [PATCH 5/5] uv lock --- uv.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/uv.lock b/uv.lock index 79c0aac..9424c75 100644 --- a/uv.lock +++ b/uv.lock @@ -912,7 +912,7 @@ requires-dist = [ { name = "boto3", specifier = ">=1.34.26" }, { name = "celery", extras = ["redis"], specifier = ">=5.3.6" }, { name = "docker", specifier = ">=7.0.0" }, - { name = "fairscape-models", specifier = ">=1.0.26" }, + { name = "fairscape-models", specifier = ">=1.0.27" }, { name = "fastapi", specifier = ">=0.109.0" }, { name = "google-genai", specifier = ">=1.0.0" }, { name = "httpx", specifier = ">=0.28.1" }, @@ -941,7 +941,7 @@ requires-dist = [ [[package]] name = "fairscape-models" -version = "1.0.26" +version = "1.0.27" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mongomock" }, @@ -949,9 +949,9 @@ dependencies = [ { name = "pymongo" }, { name = "typing" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e6/93/513d0d81f94eb2b2a5b0149dfcf79ab49666133adb4cc7132747098cf21e/fairscape_models-1.0.26.tar.gz", hash = "sha256:946b74a55cf086c04ce57dcaaf19cd9b24a9f2f25c23591d3ef92dc7c5d12b2b", size = 80143, upload-time = "2026-02-24T15:48:04.261Z" } +sdist = { url = "https://files.pythonhosted.org/packages/55/36/340f98118540a5b03f56c961dfc2ca5294f1e5b7489d98f119b5ba2e60ed/fairscape_models-1.0.27.tar.gz", hash = "sha256:865978aec4ae43bf63917fcfcd16a60478c580df8643cc401a4ed1bf86138710", size = 80138, upload-time = "2026-02-24T21:15:38.392Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8e/4e/ac5784eea91fbe82a9d08965d1786a755818c61f81e11dfd44f1880ac59f/fairscape_models-1.0.26-py3-none-any.whl", hash = "sha256:9a23a2eb28f0f6d2fd8df1c75c8b0488bc6ed621045d8b75d2684fe47a2d3472", size = 86188, upload-time = "2026-02-24T15:48:02.979Z" }, + { url = "https://files.pythonhosted.org/packages/cf/39/0cab93268285270bc4ac11b7bae629d9fe88d169ebeebeccbeebc1446ec9/fairscape_models-1.0.27-py3-none-any.whl", hash = "sha256:45905e57d6b934eb86ece25b3ce92c28771919564f9f66d89e15417132282e9c", size = 86190, upload-time = "2026-02-24T21:15:37.263Z" }, ] [[package]]