Skip to content

Commit

Permalink
Merge branch 'develop' into features/phenov2-1394
Browse files Browse the repository at this point in the history
  • Loading branch information
v-rocheleau committed Oct 10, 2023
2 parents 8fb0067 + bdf4b01 commit 5a11f7a
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 45 deletions.
10 changes: 10 additions & 0 deletions chord_metadata_service/chord/api_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from django_filters.rest_framework import DjangoFilterBackend
from chord_metadata_service.cleanup.run_all import run_all_cleanup

from chord_metadata_service.resources.serializers import ResourceSerializer
from chord_metadata_service.restapi.api_renderers import PhenopacketsRenderer, JSONLDDatasetRenderer, RDFDatasetRenderer
from chord_metadata_service.restapi.pagination import LargeResultsSetPagination

Expand Down Expand Up @@ -85,6 +86,15 @@ def dats(self, _request, *_args, **_kwargs):
dataset = self.get_object()
return Response(json.loads(dataset.dats_file))

@action(detail=True, methods=["get"])
def resources(self, _request, *_args, **_kwargs):
"""
Retrieve all resources (phenopackets/additional_resources) for a dataset and return a JSON response serialized
using ResourceSerializer
"""
dataset = self.get_object()
return Response(ResourceSerializer(dataset.resources.all(), many=True).data)

@async_to_sync
async def destroy(self, request, *args, **kwargs):
get_obj_async = sync_to_async(self.get_object)
Expand Down
29 changes: 29 additions & 0 deletions chord_metadata_service/chord/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,35 @@ def test_dats(self):
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertDictEqual(response.data, json.loads(payload['dats_file']))

def test_resources(self):
resource = {
"id": "NCBITaxon:2023-09-14",
"name": "NCBI Taxonomy OBO Edition",
"version": "2023-09-14",
"namespace_prefix": "NCBITaxon",
"url": "http://purl.obolibrary.org/obo/ncbitaxon/2023-09-14/ncbitaxon.owl",
"iri_prefix": "http://purl.obolibrary.org/obo/NCBITaxon_",
}

r = self.client.post("/api/resources", data=json.dumps(resource), content_type="application/json")
self.assertEqual(r.status_code, status.HTTP_201_CREATED)

r = self.client.post(
"/api/datasets",
data=json.dumps({
**valid_dataset_1(self.project["identifier"]),
"additional_resources": [resource["id"]],
}),
content_type="application/json")
self.assertEqual(r.status_code, status.HTTP_201_CREATED)

dataset_id = Dataset.objects.first().identifier
r = self.client.get(f"/api/datasets/{dataset_id}/resources")
self.assertEqual(r.status_code, status.HTTP_200_OK)
self.assertEqual(len(r.data), 1)
self.assertEqual(r.data[0]["id"], resource["id"])


# TODO: Update Dataset
# TODO: Delete Dataset

Expand Down
4 changes: 2 additions & 2 deletions chord_metadata_service/experiments/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
"enum": ["DNA Methylation", "mRNA-Seq", "smRNA-Seq", "RNA-Seq", "WES",
"WGS", "Genotyping", "Proteomic profiling",
"Neutralizing antibody titers", "Metabolite profiling",
"Antibody measurement", "Other"]
"Antibody measurement", "Viral WGS", "Other"]
},
"experiment_ontology": ONTOLOGY_CLASS_LIST,
"molecule": {
Expand All @@ -107,7 +107,7 @@
"molecule_ontology": ONTOLOGY_CLASS_LIST,
"library_strategy": {
"type": "string",
"enum": ["Bisulfite-Seq", "RNA-Seq", "ChIP-Seq", "WES", "Other"]
"enum": ["Bisulfite-Seq", "RNA-Seq", "ChIP-Seq", "WES", "WGS", "RAD-Seq", "AMPLICON", "Other"]
},
"library_source": {
"type": "string",
Expand Down
27 changes: 26 additions & 1 deletion chord_metadata_service/patients/api_views.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import re

from datetime import datetime

from rest_framework import viewsets, filters, mixins, serializers
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.settings import api_settings
from rest_framework.views import APIView
from django.conf import settings
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
Expand All @@ -22,6 +25,7 @@
from chord_metadata_service.logger import logger
from chord_metadata_service.phenopackets.api_views import BIOSAMPLE_PREFETCH, PHENOPACKET_PREFETCH
from chord_metadata_service.phenopackets.models import Phenopacket
from chord_metadata_service.phenopackets.serializers import PhenopacketSerializer
from chord_metadata_service.restapi.api_renderers import (
FHIRRenderer,
PhenopacketsRenderer,
Expand Down Expand Up @@ -97,6 +101,27 @@ def list(self, request, *args, **kwargs):

return super(IndividualViewSet, self).list(request, *args, **kwargs)

@action(detail=True, methods=["GET", "POST"])
def phenopackets(self, request, *_args, **_kwargs):
as_attachment = request.query_params.get("attachment", "") in ("1", "true", "yes")
individual = self.get_object()

phenopackets = (
Phenopacket.objects
.filter(subject=individual)
.prefetch_related(*PHENOPACKET_PREFETCH)
.order_by("id")
)

filename_safe_id = re.sub(r"[\\/:*?\"<>|]", "_", individual.id)
return Response(
PhenopacketSerializer(phenopackets, many=True).data,
headers=(
{"Content-Disposition": f"attachment; filename=\"{filename_safe_id}_phenopackets.json\""}
if as_attachment else {}
),
)


class BatchViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
"""
Expand Down
18 changes: 15 additions & 3 deletions chord_metadata_service/patients/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def test_csv_export(self):
self.assertIn(column, [column_name.lower() for column_name in headers])


class IndividualFullTextSearchTest(APITestCase):
class IndividualWithPhenopacketSearchTest(APITestCase):
""" Test for api/individuals?search= """

def setUp(self):
Expand All @@ -165,7 +165,7 @@ def setUp(self):
**ph_c.valid_phenopacket(subject=self.individual_one, meta_data=self.metadata_1)
)

def test_search(self):
def test_search(self): # test full-text search
get_resp_1 = self.client.get('/api/individuals?search=P49Y')
self.assertEqual(get_resp_1.status_code, status.HTTP_200_OK)
response_obj_1 = get_resp_1.json()
Expand All @@ -176,13 +176,25 @@ def test_search(self):
response_obj_2 = get_resp_2.json()
self.assertEqual(len(response_obj_2['results']), 2)

def test_search_bento_search_format(self):
def test_search_bento_search_format(self): # test full-text search - bento search result format
get_resp_1 = self.client.get('/api/individuals?search=P49Y&format=bento_search_result')
self.assertEqual(get_resp_1.status_code, status.HTTP_200_OK)
response_obj_1 = get_resp_1.json()
self.assertEqual(len(response_obj_1['results']), 1)
self.assertEqual(len(response_obj_1['results'][0]), 4) # 4 fields in the bento search response

def test_individual_phenopackets(self):
get_resp = self.client.get(f"/api/individuals/{self.individual_one.id}/phenopackets")
self.assertEqual(get_resp.status_code, status.HTTP_200_OK)
response_obj_1 = get_resp.json()
self.assertEqual(len(response_obj_1), 1) # 1 phenopacket for individual

post_resp = self.client.post(f"/api/individuals/{self.individual_one.id}/phenopackets?attachment=1")
self.assertEqual(post_resp.status_code, status.HTTP_200_OK)
self.assertIn("attachment; filename=", post_resp.headers.get("Content-Disposition", ""))
response_obj_2 = post_resp.json()
self.assertEqual(len(response_obj_2), 1) # 1 phenopacket for individual, still


# Note: the next five tests use the same setUp method. Initially they were
# all combined in the same class. But this caused bugs with regard to unavailable
Expand Down
6 changes: 3 additions & 3 deletions chord_metadata_service/phenopackets/autocomplete_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ class DiseaseTermAutocomplete(autocomplete.Select2QuerySetView):

# get_result_value return result.pk

def get_result_label(self, item):
return item.term["label"]
def get_result_value(self, item):
return item.term["id"]

def get_selected_result_label(self, item):
def get_result_label(self, item):
return item.term["label"]

def get_queryset(self):
Expand Down
59 changes: 24 additions & 35 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "chord_metadata_service" # can be renamed to katsu if inner module directory is renamed too
version = "4.0.0"
version = "4.4.0"
description = "An implementation of a clin/pheno metadata store for the Bento platform."
authors = [
"Ksenia Zaytseva",
Expand Down

0 comments on commit 5a11f7a

Please sign in to comment.