Marshmallow isn't the right tool when dealing with large models with lots of null values. Rather than fight the process of mamaging the Study Details, I'm letting that fall through, and we can test on an individual value or maybe set up a constants array when that becomes meaningful.

This commit is contained in:
Dan Funk 2020-04-03 16:24:38 -04:00
parent 5de850cfdb
commit 60a10bb688
8 changed files with 34 additions and 182 deletions

View File

@ -42,6 +42,8 @@ class ProtocolBuilderStudySchema(ma.Schema):
class Meta:
model = ProtocolBuilderStudy
unknown = INCLUDE
fields = ["STUDYID", "HSRNUMBER", "TITLE", "NETBADGEID",
"Q_COMPLETE", "DATE_MODIFIED"]
@post_load
def make_pbs(self, data, **kwargs):
@ -65,6 +67,7 @@ class ProtocolBuilderInvestigatorSchema(ma.Schema):
def make_inv(self, data, **kwargs):
return ProtocolBuilderInvestigator(**data)
class ProtocolBuilderRequiredDocument(object):
def __init__(self, AUXDOCID: str, AUXDOC: str):
self.AUXDOCID = AUXDOCID
@ -73,154 +76,9 @@ class ProtocolBuilderRequiredDocument(object):
class ProtocolBuilderRequiredDocumentSchema(ma.Schema):
class Meta:
model = ProtocolBuilderRequiredDocument
fields = ["AUXDOCID","AUXDOC"]
unknown = INCLUDE
@post_load
def make_req(self, data, **kwargs):
return ProtocolBuilderRequiredDocument(**data)
class ProtocolBuilderStudyDetails(object):
def __init__(
self,
IS_IND: int = None,
IND_1: str = None,
IND_2: str = None,
IND_3: str = None,
IS_UVA_IND: int = None,
IS_IDE: int = None,
IS_UVA_IDE: int = None,
IDE: str = None,
IS_CHART_REVIEW: int = None,
IS_RADIATION: int = None,
GCRC_NUMBER: str = None,
IS_GCRC: int = None,
IS_PRC_DSMP: int = None,
IS_PRC: int = None,
PRC_NUMBER: str = None,
IS_IBC: int = None,
IBC_NUMBER: str = None,
SPONSORS_PROTOCOL_REVISION_DATE: int = None,
IS_SPONSOR_MONITORING: int = None,
IS_AUX: int = None,
IS_SPONSOR: int = None,
IS_GRANT: int = None,
IS_COMMITTEE_CONFLICT: int = None,
DSMB: int = None,
DSMB_FREQUENCY: int = None,
IS_DB: int = None,
IS_UVA_DB: int = None,
IS_CENTRAL_REG_DB: int = None,
IS_CONSENT_WAIVER: int = None,
IS_HGT: int = None,
IS_GENE_TRANSFER: int = None,
IS_TISSUE_BANKING: int = None,
IS_SURROGATE_CONSENT: int = None,
IS_ADULT_PARTICIPANT: int = None,
IS_MINOR_PARTICIPANT: int = None,
IS_MINOR: int = None,
IS_BIOMEDICAL: int = None,
IS_QUALITATIVE: int = None,
IS_PI_SCHOOL: int = None,
IS_PRISONERS_POP: int = None,
IS_PREGNANT_POP: int = None,
IS_FETUS_POP: int = None,
IS_MENTAL_IMPAIRMENT_POP: int = None,
IS_ELDERLY_POP: int = None,
IS_OTHER_VULNERABLE_POP: int = None,
OTHER_VULNERABLE_DESC: str = None,
IS_MULTI_SITE: int = None,
IS_UVA_LOCATION: int = None,
NON_UVA_LOCATION: str = None,
MULTI_SITE_LOCATIONS: str = None,
IS_OUTSIDE_CONTRACT: int = None,
IS_UVA_PI_MULTI: int = None,
IS_NOT_PRC_WAIVER: int = None,
IS_CANCER_PATIENT: int = None,
UPLOAD_COMPLETE: int = None,
IS_FUNDING_SOURCE: int = None,
IS_PI_INITIATED: int = None,
IS_ENGAGED_RESEARCH: int = None,
IS_APPROVED_DEVICE: int = None,
IS_FINANCIAL_CONFLICT: int = None,
IS_NOT_CONSENT_WAIVER: int = None,
IS_FOR_CANCER_CENTER: int = None,
IS_REVIEW_BY_CENTRAL_IRB: int = None,
IRBREVIEWERADMIN: str = None
):
self.IS_IND = IS_IND
self.IND_1 = IND_1
self.IND_2 = IND_2
self.IND_3 = IND_3
self.IS_UVA_IND = IS_UVA_IND
self.IS_IDE = IS_IDE
self.IS_UVA_IDE = IS_UVA_IDE
self.IDE = IDE
self.IS_CHART_REVIEW = IS_CHART_REVIEW
self.IS_RADIATION = IS_RADIATION
self.GCRC_NUMBER = GCRC_NUMBER
self.IS_GCRC = IS_GCRC
self.IS_PRC_DSMP = IS_PRC_DSMP
self.IS_PRC = IS_PRC
self.PRC_NUMBER = PRC_NUMBER
self.IS_IBC = IS_IBC
self.IBC_NUMBER = IBC_NUMBER
self.SPONSORS_PROTOCOL_REVISION_DATE = SPONSORS_PROTOCOL_REVISION_DATE
self.IS_SPONSOR_MONITORING = IS_SPONSOR_MONITORING
self.IS_AUX = IS_AUX
self.IS_SPONSOR = IS_SPONSOR
self.IS_GRANT = IS_GRANT
self.IS_COMMITTEE_CONFLICT = IS_COMMITTEE_CONFLICT
self.DSMB = DSMB
self.DSMB_FREQUENCY = DSMB_FREQUENCY
self.IS_DB = IS_DB
self.IS_UVA_DB = IS_UVA_DB
self.IS_CENTRAL_REG_DB = IS_CENTRAL_REG_DB
self.IS_CONSENT_WAIVER = IS_CONSENT_WAIVER
self.IS_HGT = IS_HGT
self.IS_GENE_TRANSFER = IS_GENE_TRANSFER
self.IS_TISSUE_BANKING = IS_TISSUE_BANKING
self.IS_SURROGATE_CONSENT = IS_SURROGATE_CONSENT
self.IS_ADULT_PARTICIPANT = IS_ADULT_PARTICIPANT
self.IS_MINOR_PARTICIPANT = IS_MINOR_PARTICIPANT
self.IS_MINOR = IS_MINOR
self.IS_BIOMEDICAL = IS_BIOMEDICAL
self.IS_QUALITATIVE = IS_QUALITATIVE
self.IS_PI_SCHOOL = IS_PI_SCHOOL
self.IS_PRISONERS_POP = IS_PRISONERS_POP
self.IS_PREGNANT_POP = IS_PREGNANT_POP
self.IS_FETUS_POP = IS_FETUS_POP
self.IS_MENTAL_IMPAIRMENT_POP = IS_MENTAL_IMPAIRMENT_POP
self.IS_ELDERLY_POP = IS_ELDERLY_POP
self.IS_OTHER_VULNERABLE_POP = IS_OTHER_VULNERABLE_POP
self.OTHER_VULNERABLE_DESC = OTHER_VULNERABLE_DESC
self.IS_MULTI_SITE = IS_MULTI_SITE
self.IS_UVA_LOCATION = IS_UVA_LOCATION
self.NON_UVA_LOCATION = NON_UVA_LOCATION
self.MULTI_SITE_LOCATIONS = MULTI_SITE_LOCATIONS
self.IS_OUTSIDE_CONTRACT = IS_OUTSIDE_CONTRACT
self.IS_UVA_PI_MULTI = IS_UVA_PI_MULTI
self.IS_NOT_PRC_WAIVER = IS_NOT_PRC_WAIVER
self.IS_CANCER_PATIENT = IS_CANCER_PATIENT
self.UPLOAD_COMPLETE = UPLOAD_COMPLETE
self.IS_FUNDING_SOURCE = IS_FUNDING_SOURCE
self.IS_PI_INITIATED = IS_PI_INITIATED
self.IS_ENGAGED_RESEARCH = IS_ENGAGED_RESEARCH
self.IS_APPROVED_DEVICE = IS_APPROVED_DEVICE
self.IS_FINANCIAL_CONFLICT = IS_FINANCIAL_CONFLICT
self.IS_NOT_CONSENT_WAIVER = IS_NOT_CONSENT_WAIVER
self.IS_FOR_CANCER_CENTER = IS_FOR_CANCER_CENTER
self.IS_REVIEW_BY_CENTRAL_IRB = IS_REVIEW_BY_CENTRAL_IRB
self.IRBREVIEWERADMIN = IRBREVIEWERADMIN
class ProtocolBuilderStudyDetailsSchema(ma.Schema):
class Meta:
model = ProtocolBuilderStudyDetails
unknown = INCLUDE
@post_load
def make_details(self, data, **kwargs):
return ProtocolBuilderStudyDetails(**data)

View File

@ -43,7 +43,7 @@ For example:
def do_task(self, task, study_id, *args, **kwargs):
"""Takes data from the protocol builder, and merges it with data from the IRB Pro Categories
spreadsheet to return pertinent details about the required documents."""
pb_docs = self.pb.get_required_docs(study_id)
pb_docs = self.pb.get_required_docs(study_id, as_objects=True)
self.get_required_docs(study_id, pb_docs)
task.data["required_docs"] = self.get_required_docs(study_id, pb_docs)

View File

@ -39,9 +39,9 @@ class StudyInfo(Script):
schema = StudySchema()
study_info["info"] = schema.dump(study)
if cmd == 'investigators':
study_info["investigators"] = self.pb.get_investigators(study_id, as_json=True)
study_info["investigators"] = self.pb.get_investigators(study_id)
if cmd == 'details':
study_info["details"] = self.pb.get_study_details(study_id, as_json=True)
study_info["details"] = self.pb.get_study_details(study_id)
task.data["study"] = study_info

View File

@ -6,8 +6,7 @@ import requests
from crc import app
from crc.api.common import ApiError
from crc.models.protocol_builder import ProtocolBuilderStudy, ProtocolBuilderStudySchema, ProtocolBuilderInvestigator, \
ProtocolBuilderRequiredDocument, ProtocolBuilderStudyDetails, ProtocolBuilderInvestigatorSchema, \
ProtocolBuilderRequiredDocumentSchema, ProtocolBuilderStudyDetailsSchema
ProtocolBuilderRequiredDocument, ProtocolBuilderRequiredDocumentSchema
class ProtocolBuilderService(object):
@ -17,7 +16,7 @@ class ProtocolBuilderService(object):
STUDY_DETAILS_URL = app.config['PB_STUDY_DETAILS_URL']
@staticmethod
def get_studies(user_id) -> Optional[List[ProtocolBuilderStudy]]:
def get_studies(user_id) -> {}:
if not isinstance(user_id, str):
raise ApiError("invalid_user_id", "This user id is invalid: " + str(user_id))
response = requests.get(ProtocolBuilderService.STUDY_URL % user_id)
@ -30,45 +29,38 @@ class ProtocolBuilderService(object):
(response.status_code, response.text))
@staticmethod
def get_investigators(study_id, as_json=False) -> Optional[List[ProtocolBuilderInvestigator]]:
def get_investigators(study_id) -> {}:
ProtocolBuilderService.check_args(study_id)
response = requests.get(ProtocolBuilderService.INVESTIGATOR_URL % study_id)
if response.ok and response.text:
pb_studies = ProtocolBuilderInvestigatorSchema(many=True).loads(response.text)
if as_json:
return ProtocolBuilderInvestigatorSchema(many=True).dump(pb_studies)
else:
return pb_studies
pb_studies = json.loads(response.text)
return pb_studies
else:
raise ApiError("protocol_builder_error",
"Received an invalid response from the protocol builder (status %s): %s" %
(response.status_code, response.text))
@staticmethod
def get_required_docs(study_id, as_json=False) -> Optional[List[ProtocolBuilderRequiredDocument]]:
def get_required_docs(study_id, as_objects=False) -> Optional[List[ProtocolBuilderRequiredDocument]]:
ProtocolBuilderService.check_args(study_id)
response = requests.get(ProtocolBuilderService.REQUIRED_DOCS_URL % study_id)
if response.ok and response.text:
pb_studies = ProtocolBuilderRequiredDocumentSchema(many=True).loads(response.text)
if as_json:
return ProtocolBuilderRequiredDocumentSchema(many=True).dump(pb_studies)
if as_objects:
return ProtocolBuilderRequiredDocumentSchema(many=True).loads(response.text)
else:
return pb_studies
return json.loads(response.text)
else:
raise ApiError("protocol_builder_error",
"Received an invalid response from the protocol builder (status %s): %s" %
(response.status_code, response.text))
@staticmethod
def get_study_details(study_id, as_json=False) -> Optional[ProtocolBuilderStudyDetails]:
def get_study_details(study_id) -> {}:
ProtocolBuilderService.check_args(study_id)
response = requests.get(ProtocolBuilderService.STUDY_DETAILS_URL % study_id)
if response.ok and response.text:
pb_study_details = ProtocolBuilderStudyDetailsSchema().loads(response.text)
if as_json:
return ProtocolBuilderStudyDetailsSchema().dump(pb_study_details)
else:
return pb_study_details
pb_study_details = json.loads(response.text)
return pb_study_details
else:
raise ApiError("protocol_builder_error",
"Received an invalid response from the protocol builder (status %s): %s" %

View File

@ -4,7 +4,7 @@
"GCRC_NUMBER": null,
"IBC_NUMBER": null,
"IDE": null,
"IND_1": null,
"IND_1": 1234,
"IND_2": null,
"IND_3": null,
"IRBREVIEWERADMIN": null,

View File

@ -21,6 +21,10 @@ class TestProtocolBuilder(BaseTest):
mock_get.return_value.text = self.protocol_builder_response('investigators.json')
response = ProtocolBuilderService.get_investigators(self.test_study_id)
self.assertIsNotNone(response)
self.assertEquals(3, len(response))
self.assertEquals("DC", response[0]["INVESTIGATORTYPE"])
self.assertEquals("Department Contact", response[0]["INVESTIGATORTYPEFULL"])
self.assertEquals("asd3v", response[0]["NETBADGEID"])
@patch('crc.services.protocol_builder.requests.get')
def test_get_required_docs(self, mock_get):
@ -28,6 +32,8 @@ class TestProtocolBuilder(BaseTest):
mock_get.return_value.text = self.protocol_builder_response('required_docs.json')
response = ProtocolBuilderService.get_required_docs(self.test_study_id)
self.assertIsNotNone(response)
self.assertEquals(5, len(response))
self.assertEquals("6", response[0]['AUXDOCID'])
@patch('crc.services.protocol_builder.requests.get')
def test_get_details(self, mock_get):
@ -35,3 +41,5 @@ class TestProtocolBuilder(BaseTest):
mock_get.return_value.text = self.protocol_builder_response('study_details.json')
response = ProtocolBuilderService.get_study_details(self.test_study_id)
self.assertIsNotNone(response)
self.assertEquals(64, len(response))
self.assertEquals(1234, response['IND_1'])

View File

@ -4,7 +4,7 @@ from unittest.mock import patch
from crc import session
from crc.models.api_models import WorkflowApiSchema
from crc.models.protocol_builder import ProtocolBuilderStatus, ProtocolBuilderStudyDetailsSchema, \
from crc.models.protocol_builder import ProtocolBuilderStatus, \
ProtocolBuilderStudySchema
from crc.models.study import StudyModel, StudySchema
from crc.models.workflow import WorkflowSpecModel, WorkflowSpecModelSchema, WorkflowModel, WorkflowStatus, \
@ -125,7 +125,7 @@ class TestStudyApi(BaseTest):
studies_response = self.protocol_builder_response('user_studies.json')
mock_studies.return_value = ProtocolBuilderStudySchema(many=True).loads(studies_response)
details_response = self.protocol_builder_response('study_details.json')
mock_details.return_value = ProtocolBuilderStudyDetailsSchema().loads(details_response)
mock_details.return_value = json.loads(details_response)
# Make the api call to get all studies
api_response = self.app.get('/v1.0/study', headers=self.logged_in_headers(), content_type="application/json")

View File

@ -1,14 +1,8 @@
import json
from datetime import datetime, timezone
from unittest.mock import patch
from crc import session, db
from crc.models.api_models import WorkflowApiSchema
from crc.models.protocol_builder import ProtocolBuilderStatus, ProtocolBuilderStudyDetailsSchema, \
ProtocolBuilderStudySchema
from crc.models.study import StudyModel, StudySchema
from crc import db
from crc.models.protocol_builder import ProtocolBuilderStatus
from crc.models.study import StudyModel
from crc.models.user import UserModel
from crc.models.workflow import WorkflowSpecModel, WorkflowSpecModelSchema, WorkflowModel, WorkflowStatus, \
from crc.models.workflow import WorkflowModel, WorkflowStatus, \
WorkflowSpecCategoryModel
from crc.services.study_service import StudyService
from crc.services.workflow_processor import WorkflowProcessor