nci-cidc-api-modules 1.2.29__py3-none-any.whl → 1.2.45__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cidc_api/__init__.py +1 -0
- cidc_api/config/db.py +21 -1
- cidc_api/config/settings.py +1 -0
- cidc_api/models/__init__.py +0 -2
- cidc_api/models/data.py +17 -4
- cidc_api/models/db/stage1/__init__.py +56 -0
- cidc_api/models/db/stage1/additional_treatment_orm.py +22 -0
- cidc_api/models/db/stage1/adverse_event_orm.py +46 -0
- cidc_api/models/db/stage1/base_orm.py +7 -0
- cidc_api/models/db/stage1/baseline_clinical_assessment_orm.py +22 -0
- cidc_api/models/db/stage1/comorbidity_orm.py +23 -0
- cidc_api/models/db/stage1/consent_group_orm.py +32 -0
- cidc_api/models/db/stage1/demographic_orm.py +47 -0
- cidc_api/models/db/stage1/disease_orm.py +52 -0
- cidc_api/models/db/stage1/exposure_orm.py +22 -0
- cidc_api/models/db/stage1/gvhd_diagnosis_acute_orm.py +34 -0
- cidc_api/models/db/stage1/gvhd_diagnosis_chronic_orm.py +36 -0
- cidc_api/models/db/stage1/gvhd_organ_acute_orm.py +21 -0
- cidc_api/models/db/stage1/gvhd_organ_chronic_orm.py +21 -0
- cidc_api/models/db/stage1/medical_history_orm.py +30 -0
- cidc_api/models/db/stage1/other_malignancy_orm.py +29 -0
- cidc_api/models/db/stage1/participant_orm.py +77 -0
- cidc_api/models/db/stage1/prior_treatment_orm.py +29 -0
- cidc_api/models/db/stage1/radiotherapy_dose_orm.py +39 -0
- cidc_api/models/db/stage1/response_by_system_orm.py +30 -0
- cidc_api/models/db/stage1/response_orm.py +28 -0
- cidc_api/models/db/stage1/specimen_orm.py +46 -0
- cidc_api/models/db/stage1/stem_cell_transplant_orm.py +25 -0
- cidc_api/models/db/stage1/surgery_orm.py +27 -0
- cidc_api/models/db/stage1/therapy_agent_dose_orm.py +31 -0
- cidc_api/models/db/stage1/treatment_orm.py +38 -0
- cidc_api/models/db/stage1/trial_orm.py +35 -0
- cidc_api/models/db/stage2/additional_treatment_orm.py +8 -8
- cidc_api/models/db/stage2/administrative_person_orm.py +4 -4
- cidc_api/models/db/stage2/administrative_role_assignment_orm.py +4 -4
- cidc_api/models/db/stage2/adverse_event_orm.py +12 -13
- cidc_api/models/db/stage2/arm_orm.py +3 -3
- cidc_api/models/db/stage2/base_orm.py +7 -0
- cidc_api/models/db/stage2/baseline_clinical_assessment_orm.py +6 -7
- cidc_api/models/db/stage2/cohort_orm.py +3 -3
- cidc_api/models/db/stage2/comorbidity_orm.py +7 -8
- cidc_api/models/db/stage2/consent_group_orm.py +5 -4
- cidc_api/models/db/stage2/contact_orm.py +16 -20
- cidc_api/models/db/stage2/demographic_orm.py +11 -8
- cidc_api/models/db/stage2/disease_orm.py +13 -14
- cidc_api/models/db/stage2/exposure_orm.py +5 -4
- cidc_api/models/db/stage2/file_orm.py +6 -9
- cidc_api/models/db/stage2/gvhd_diagnosis_acute_orm.py +5 -4
- cidc_api/models/db/stage2/gvhd_diagnosis_chronic_orm.py +5 -6
- cidc_api/models/db/stage2/gvhd_organ_acute_orm.py +4 -3
- cidc_api/models/db/stage2/gvhd_organ_chronic_orm.py +4 -3
- cidc_api/models/db/stage2/institution_orm.py +7 -7
- cidc_api/models/db/stage2/medical_history_orm.py +10 -9
- cidc_api/models/db/stage2/other_clinical_endpoint_orm.py +8 -12
- cidc_api/models/db/stage2/other_malignancy_orm.py +10 -11
- cidc_api/models/db/stage2/participant_orm.py +28 -28
- cidc_api/models/db/stage2/prior_treatment_orm.py +15 -14
- cidc_api/models/db/stage2/publication_orm.py +9 -11
- cidc_api/models/db/stage2/radiotherapy_dose_orm.py +9 -9
- cidc_api/models/db/stage2/response_by_system_orm.py +5 -3
- cidc_api/models/db/stage2/response_orm.py +6 -5
- cidc_api/models/db/stage2/shipment_orm.py +17 -17
- cidc_api/models/db/stage2/shipment_specimen_orm.py +4 -4
- cidc_api/models/db/stage2/specimen_orm.py +7 -6
- cidc_api/models/db/stage2/stem_cell_transplant_orm.py +7 -7
- cidc_api/models/db/stage2/surgery_orm.py +7 -7
- cidc_api/models/db/stage2/therapy_agent_dose_orm.py +8 -8
- cidc_api/models/db/stage2/treatment_orm.py +16 -15
- cidc_api/models/db/stage2/trial_orm.py +34 -33
- cidc_api/models/files/facets.py +4 -0
- cidc_api/models/models.py +154 -9
- cidc_api/models/pydantic/{stage2/base.py → base.py} +19 -1
- cidc_api/models/pydantic/stage1/__init__.py +56 -0
- cidc_api/models/pydantic/stage1/additional_treatment.py +23 -0
- cidc_api/models/pydantic/stage1/adverse_event.py +100 -0
- cidc_api/models/pydantic/stage1/baseline_clinical_assessment.py +23 -0
- cidc_api/models/pydantic/stage1/comorbidity.py +36 -0
- cidc_api/models/pydantic/stage1/consent_group.py +30 -0
- cidc_api/models/pydantic/stage1/demographic.py +123 -0
- cidc_api/models/pydantic/stage1/disease.py +158 -0
- cidc_api/models/pydantic/stage1/exposure.py +32 -0
- cidc_api/models/pydantic/stage1/gvhd_diagnosis_acute.py +33 -0
- cidc_api/models/pydantic/stage1/gvhd_diagnosis_chronic.py +32 -0
- cidc_api/models/pydantic/stage1/gvhd_organ_acute.py +22 -0
- cidc_api/models/pydantic/stage1/gvhd_organ_chronic.py +23 -0
- cidc_api/models/pydantic/stage1/medical_history.py +36 -0
- cidc_api/models/pydantic/stage1/other_malignancy.py +49 -0
- cidc_api/models/pydantic/stage1/participant.py +51 -0
- cidc_api/models/pydantic/stage1/prior_treatment.py +45 -0
- cidc_api/models/pydantic/stage1/radiotherapy_dose.py +79 -0
- cidc_api/models/pydantic/stage1/response.py +65 -0
- cidc_api/models/pydantic/stage1/response_by_system.py +112 -0
- cidc_api/models/pydantic/stage1/specimen.py +31 -0
- cidc_api/models/pydantic/stage1/stem_cell_transplant.py +35 -0
- cidc_api/models/pydantic/stage1/surgery.py +49 -0
- cidc_api/models/pydantic/stage1/therapy_agent_dose.py +67 -0
- cidc_api/models/pydantic/stage1/treatment.py +50 -0
- cidc_api/models/pydantic/stage1/trial.py +45 -0
- cidc_api/models/pydantic/stage2/additional_treatment.py +5 -5
- cidc_api/models/pydantic/stage2/administrative_person.py +1 -1
- cidc_api/models/pydantic/stage2/administrative_role_assignment.py +2 -2
- cidc_api/models/pydantic/stage2/adverse_event.py +2 -2
- cidc_api/models/pydantic/stage2/arm.py +2 -2
- cidc_api/models/pydantic/stage2/baseline_clinical_assessment.py +2 -2
- cidc_api/models/pydantic/stage2/cohort.py +1 -1
- cidc_api/models/pydantic/stage2/comorbidity.py +1 -1
- cidc_api/models/pydantic/stage2/consent_group.py +2 -2
- cidc_api/models/pydantic/stage2/contact.py +1 -1
- cidc_api/models/pydantic/stage2/demographic.py +27 -18
- cidc_api/models/pydantic/stage2/disease.py +33 -19
- cidc_api/models/pydantic/stage2/exposure.py +3 -3
- cidc_api/models/pydantic/stage2/file.py +2 -2
- cidc_api/models/pydantic/stage2/gvhd_diagnosis_acute.py +2 -2
- cidc_api/models/pydantic/stage2/gvhd_diagnosis_chronic.py +2 -2
- cidc_api/models/pydantic/stage2/gvhd_organ_acute.py +1 -1
- cidc_api/models/pydantic/stage2/gvhd_organ_chronic.py +1 -1
- cidc_api/models/pydantic/stage2/institution.py +1 -1
- cidc_api/models/pydantic/stage2/medical_history.py +2 -2
- cidc_api/models/pydantic/stage2/other_clinical_endpoint.py +1 -1
- cidc_api/models/pydantic/stage2/other_malignancy.py +12 -8
- cidc_api/models/pydantic/stage2/participant.py +10 -6
- cidc_api/models/pydantic/stage2/prior_treatment.py +14 -23
- cidc_api/models/pydantic/stage2/publication.py +2 -2
- cidc_api/models/pydantic/stage2/radiotherapy_dose.py +2 -2
- cidc_api/models/pydantic/stage2/response.py +5 -11
- cidc_api/models/pydantic/stage2/response_by_system.py +10 -7
- cidc_api/models/pydantic/stage2/shipment.py +2 -2
- cidc_api/models/pydantic/stage2/shipment_specimen.py +1 -1
- cidc_api/models/pydantic/stage2/specimen.py +8 -5
- cidc_api/models/pydantic/stage2/stem_cell_transplant.py +2 -2
- cidc_api/models/pydantic/stage2/surgery.py +1 -1
- cidc_api/models/pydantic/stage2/therapy_agent_dose.py +1 -1
- cidc_api/models/pydantic/stage2/treatment.py +2 -2
- cidc_api/models/pydantic/stage2/trial.py +19 -15
- cidc_api/models/types.py +45 -42
- cidc_api/shared/assay_handling.py +68 -0
- cidc_api/shared/auth.py +5 -5
- cidc_api/shared/file_handling.py +16 -4
- cidc_api/shared/gcloud_client.py +78 -16
- cidc_api/shared/utils.py +18 -9
- cidc_api/telemetry.py +101 -0
- {nci_cidc_api_modules-1.2.29.dist-info → nci_cidc_api_modules-1.2.45.dist-info}/METADATA +25 -14
- nci_cidc_api_modules-1.2.45.dist-info/RECORD +165 -0
- cidc_api/models/db/base_orm.py +0 -25
- nci_cidc_api_modules-1.2.29.dist-info/RECORD +0 -109
- {nci_cidc_api_modules-1.2.29.dist-info → nci_cidc_api_modules-1.2.45.dist-info}/WHEEL +0 -0
- {nci_cidc_api_modules-1.2.29.dist-info → nci_cidc_api_modules-1.2.45.dist-info}/licenses/LICENSE +0 -0
- {nci_cidc_api_modules-1.2.29.dist-info → nci_cidc_api_modules-1.2.45.dist-info}/top_level.txt +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from typing import Self
|
|
2
2
|
|
|
3
|
-
from pydantic import PositiveInt, model_validator
|
|
3
|
+
from pydantic import PositiveInt, model_validator, NonNegativeInt
|
|
4
4
|
|
|
5
|
-
from .base import Base
|
|
5
|
+
from cidc_api.models.pydantic.base import Base
|
|
6
6
|
from cidc_api.models.types import ResponseSystem, ResponseSystemVersion, BestOverallResponse, YNUNA
|
|
7
7
|
|
|
8
8
|
|
|
@@ -26,7 +26,7 @@ class ResponseBySystem(Base):
|
|
|
26
26
|
|
|
27
27
|
# The unique internal identifier for the associated participant
|
|
28
28
|
# CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=12220014%20and%20ver_nr=1
|
|
29
|
-
participant_id:
|
|
29
|
+
participant_id: str | None = None
|
|
30
30
|
|
|
31
31
|
# A standardized method used to evaluate and categorize the participant’s clinical response to treatment based on predefined criteria.
|
|
32
32
|
# CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=13381490%20and%20ver_nr=1
|
|
@@ -41,6 +41,9 @@ class ResponseBySystem(Base):
|
|
|
41
41
|
# Days from first response to progression.
|
|
42
42
|
response_duration: PositiveInt | None = None
|
|
43
43
|
|
|
44
|
+
# The number of days from the start of the treatment to the first signs of disease progression.
|
|
45
|
+
duration_of_stable_disease: NonNegativeInt | None = None
|
|
46
|
+
|
|
44
47
|
# Indicates whether a patient achieved a durable clinical benefit.
|
|
45
48
|
durable_clinical_benefit: bool | None = None
|
|
46
49
|
|
|
@@ -67,8 +70,8 @@ class ResponseBySystem(Base):
|
|
|
67
70
|
def validate_response_duration_cr(self) -> Self:
|
|
68
71
|
if self.best_overall_response in negative_response_values and self.response_duration:
|
|
69
72
|
raise ValueError(
|
|
70
|
-
"If best_overall_response does not indicate a positive response,
|
|
71
|
-
please leave response_duration blank."
|
|
73
|
+
"If best_overall_response does not indicate a positive response, "
|
|
74
|
+
"please leave response_duration blank."
|
|
72
75
|
)
|
|
73
76
|
return self
|
|
74
77
|
|
|
@@ -76,8 +79,8 @@ class ResponseBySystem(Base):
|
|
|
76
79
|
def validate_days_to_first_response_cr(self) -> Self:
|
|
77
80
|
if self.best_overall_response in negative_response_values and self.days_to_first_response:
|
|
78
81
|
raise ValueError(
|
|
79
|
-
"If best_overall_response does not indicate a positive response,
|
|
80
|
-
please leave days_to_first_response blank."
|
|
82
|
+
"If best_overall_response does not indicate a positive response, "
|
|
83
|
+
"please leave days_to_first_response blank."
|
|
81
84
|
)
|
|
82
85
|
return self
|
|
83
86
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
2
|
|
|
3
|
-
from .base import Base
|
|
3
|
+
from cidc_api.models.pydantic.base import Base
|
|
4
4
|
from cidc_api.models.types import AssayPriority, AssayType, Courier, ShipmentCondition, ShipmentQuality
|
|
5
5
|
|
|
6
6
|
|
|
@@ -12,7 +12,7 @@ class Shipment(Base):
|
|
|
12
12
|
institution_id: int | None = None
|
|
13
13
|
|
|
14
14
|
# The unique internal identifier for the associated trial.
|
|
15
|
-
trial_id:
|
|
15
|
+
trial_id: str | None = None
|
|
16
16
|
|
|
17
17
|
# The version number of the trial dataset
|
|
18
18
|
version: str | None = None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
2
|
|
|
3
|
-
from .base import Base
|
|
3
|
+
from cidc_api.models.pydantic.base import Base
|
|
4
4
|
from cidc_api.models.types import (
|
|
5
5
|
UberonAnatomicalTerm,
|
|
6
6
|
ICDO3MorphologicalCode,
|
|
@@ -26,7 +26,7 @@ from cidc_api.models.types import (
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
class Specimen(Base):
|
|
29
|
-
__data_category__ = "specimen"
|
|
29
|
+
# __data_category__ = "specimen"
|
|
30
30
|
__cardinality__ = "many"
|
|
31
31
|
|
|
32
32
|
# The unique internal identifier for the specimen record
|
|
@@ -34,7 +34,7 @@ class Specimen(Base):
|
|
|
34
34
|
|
|
35
35
|
# The unique internal identifier for the associated participant
|
|
36
36
|
# CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=12220014%20and%20ver_nr=1
|
|
37
|
-
participant_id:
|
|
37
|
+
participant_id: str | None = None
|
|
38
38
|
|
|
39
39
|
# The unique specimen identifier assigned by the CIMAC-CIDC Network.
|
|
40
40
|
# Formatted as CTTTPPPSS.AA for trial code TTT, participant PPP, sample SS, and aliquot AA.
|
|
@@ -66,7 +66,7 @@ class Specimen(Base):
|
|
|
66
66
|
# Categorical description of timepoint at which the sample was taken.
|
|
67
67
|
# CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=5899851%20and%20ver_nr=1
|
|
68
68
|
# Note: CIDC doesn't conform to this CDE's PVs
|
|
69
|
-
collection_event_name: str
|
|
69
|
+
collection_event_name: str
|
|
70
70
|
|
|
71
71
|
# The type of the specimen
|
|
72
72
|
specimen_type: SpecimenType | None = None
|
|
@@ -208,4 +208,7 @@ class Specimen(Base):
|
|
|
208
208
|
date_ingested: datetime | None = None
|
|
209
209
|
|
|
210
210
|
# Days from enrollment date to date specimen was collected.
|
|
211
|
-
days_to_specimen_collection: int
|
|
211
|
+
days_to_specimen_collection: int
|
|
212
|
+
|
|
213
|
+
# The location within the body from which a specimen was originally obtained as captured in the Uberon anatomical term.
|
|
214
|
+
organ_site_of_collection: UberonAnatomicalTerm
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from pydantic import NonNegativeInt
|
|
2
|
-
from .base import Base
|
|
2
|
+
from cidc_api.models.pydantic.base import Base
|
|
3
3
|
from cidc_api.models.types import (
|
|
4
4
|
StemCellDonorType,
|
|
5
5
|
AllogeneicDonorType,
|
|
@@ -26,7 +26,7 @@ class StemCellTransplant(Base):
|
|
|
26
26
|
allogeneic_donor_type: AllogeneicDonorType | None = None
|
|
27
27
|
|
|
28
28
|
# Source of the stem cells used for transplant.
|
|
29
|
-
|
|
29
|
+
stem_cell_source: StemCellSource
|
|
30
30
|
|
|
31
31
|
# Days from the enrollment date to the date of the stem cell transplant.
|
|
32
32
|
days_to_transplant: NonNegativeInt
|
|
@@ -2,7 +2,7 @@ from typing import Self
|
|
|
2
2
|
|
|
3
3
|
from pydantic import model_validator
|
|
4
4
|
|
|
5
|
-
from .base import Base
|
|
5
|
+
from cidc_api.models.pydantic.base import Base
|
|
6
6
|
from cidc_api.models.types import YNU, OffTreatmentReason
|
|
7
7
|
|
|
8
8
|
|
|
@@ -14,7 +14,7 @@ class Treatment(Base):
|
|
|
14
14
|
treatment_id: int | None = None
|
|
15
15
|
|
|
16
16
|
# The unique internal identifier for the associated Participant record
|
|
17
|
-
participant_id:
|
|
17
|
+
participant_id: str | None = None
|
|
18
18
|
|
|
19
19
|
# The unique internal identifier for the associated Arm record
|
|
20
20
|
arm_id: int | None = None
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
|
-
from
|
|
2
|
+
from pydantic import BeforeValidator
|
|
3
|
+
from typing import List, Annotated
|
|
3
4
|
|
|
4
|
-
from .base import Base
|
|
5
|
-
from cidc_api.models.types import TrialOrganization, TrialFundingAgency,
|
|
5
|
+
from cidc_api.models.pydantic.base import Base
|
|
6
|
+
from cidc_api.models.types import TrialOrganization, TrialFundingAgency, AssayType, AgeGroup, PrimaryPurposeType
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
class Trial(Base):
|
|
@@ -11,11 +12,20 @@ class Trial(Base):
|
|
|
11
12
|
|
|
12
13
|
# The unique identifier for the clinical trial. e.g. "GU16-287","BACCI"
|
|
13
14
|
# CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=5054234%20and%20ver_nr=1
|
|
14
|
-
trial_id: str
|
|
15
|
+
trial_id: str | None = None
|
|
15
16
|
|
|
16
17
|
# The version number of the trial dataset. e.g. "1.0"
|
|
17
18
|
version: str | None = None
|
|
18
19
|
|
|
20
|
+
# A broad textual description of the primary endpoint(s) of the trial.
|
|
21
|
+
primary_endpoint: str | None = None
|
|
22
|
+
|
|
23
|
+
# The identifiable class of the study participant based upon their age.
|
|
24
|
+
age_group: Annotated[List[AgeGroup], BeforeValidator(Base.split_list)]
|
|
25
|
+
|
|
26
|
+
# Clinical and/or molecular characteristics of the cancer(s) in the study population.
|
|
27
|
+
study_population: str | None = None
|
|
28
|
+
|
|
19
29
|
# ClinicalTrials.gov identifier. e.g. "NCT03731260"
|
|
20
30
|
# TODO need cde from janice, they will make one
|
|
21
31
|
nct_id: str | None = None
|
|
@@ -45,10 +55,6 @@ class Trial(Base):
|
|
|
45
55
|
# e.g. "Duke University - Duke Cancer Institute LAO"
|
|
46
56
|
grant_or_affiliated_network: TrialFundingAgency | None = None
|
|
47
57
|
|
|
48
|
-
# What stage the trial is at in its process.
|
|
49
|
-
# CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=15607838%20and%20ver_nr=1
|
|
50
|
-
trial_status: TrialStatus
|
|
51
|
-
|
|
52
58
|
# The id of the primary organization responsible for storing biospecimens from this study.
|
|
53
59
|
biobank_institution_id: int | None = None
|
|
54
60
|
|
|
@@ -63,6 +69,10 @@ class Trial(Base):
|
|
|
63
69
|
# CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=16333703%20and%20ver_nr=1
|
|
64
70
|
dates_of_conduct_end: datetime | None = None
|
|
65
71
|
|
|
72
|
+
# A classification of the study based upon the primary intent of the study's activities.
|
|
73
|
+
# CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=11160683%20and%20ver_nr=1
|
|
74
|
+
primary_purpose_type: PrimaryPurposeType
|
|
75
|
+
|
|
66
76
|
# The image of the trial data schema
|
|
67
77
|
schema_file_id: int | None = None
|
|
68
78
|
|
|
@@ -75,11 +85,5 @@ class Trial(Base):
|
|
|
75
85
|
# The list of assays that CIDC expects to receive for this trial.
|
|
76
86
|
expected_assays: List[AssayType] = []
|
|
77
87
|
|
|
78
|
-
# Is the cancer studying a liquid tumor type?
|
|
79
|
-
is_liquid_tumor_trial: bool = False
|
|
80
|
-
|
|
81
88
|
# The dbgap study accession number associated with the trial.
|
|
82
|
-
dbgap_study_accession: str
|
|
83
|
-
|
|
84
|
-
# The internal version identifier for this specific trial dataset.
|
|
85
|
-
version: str
|
|
89
|
+
dbgap_study_accession: str
|
cidc_api/models/types.py
CHANGED
|
@@ -20,6 +20,13 @@ from cidc_api.reference.gvhd import is_gvhd_organ
|
|
|
20
20
|
# As python Enums are rather cumbersome when we only want a list of permissible values for a string, use Literal instead
|
|
21
21
|
|
|
22
22
|
|
|
23
|
+
AgeGroup = Literal[
|
|
24
|
+
"Adolescent and Young Adult",
|
|
25
|
+
"Adult",
|
|
26
|
+
"Pediatric",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
|
|
23
30
|
TrialOrganization = Literal[
|
|
24
31
|
"ECOG-ACRIN",
|
|
25
32
|
"SWOG",
|
|
@@ -53,10 +60,31 @@ TrialFundingAgency = Literal[
|
|
|
53
60
|
]
|
|
54
61
|
|
|
55
62
|
|
|
56
|
-
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
63
|
+
PrimaryPurposeType = Literal[
|
|
64
|
+
"Adverse Effect Mitigation Study",
|
|
65
|
+
"Ancillary Study",
|
|
66
|
+
"Basic Science Research ",
|
|
67
|
+
"Correlative Study",
|
|
68
|
+
"Cure Study",
|
|
69
|
+
"Device Feasibility Study",
|
|
70
|
+
"Diagnosis Study",
|
|
71
|
+
"Disease Modifying Treatment Study",
|
|
72
|
+
"Early Detection Study",
|
|
73
|
+
"Education Training Clinical Study",
|
|
74
|
+
"Epidemiology Research ",
|
|
75
|
+
"Genomics Research",
|
|
76
|
+
"Health Services Research",
|
|
77
|
+
"Imaging Research",
|
|
78
|
+
"Interventional Study",
|
|
79
|
+
"Observational Study",
|
|
80
|
+
"Outcomes Research",
|
|
81
|
+
"Prevention Study",
|
|
82
|
+
"Proteomic Research",
|
|
83
|
+
"Rehabilitation Clinical Study ",
|
|
84
|
+
"Screening Study",
|
|
85
|
+
"Supportive Care Study",
|
|
86
|
+
"Transcriptomics Research",
|
|
87
|
+
"Treatment Study",
|
|
60
88
|
]
|
|
61
89
|
|
|
62
90
|
|
|
@@ -85,6 +113,7 @@ AssayType = Literal[
|
|
|
85
113
|
"snRNA-Seq",
|
|
86
114
|
"Visium",
|
|
87
115
|
"Olink HT",
|
|
116
|
+
"TCRseq RNA",
|
|
88
117
|
]
|
|
89
118
|
|
|
90
119
|
|
|
@@ -217,24 +246,6 @@ FileFormat = Literal[
|
|
|
217
246
|
]
|
|
218
247
|
|
|
219
248
|
|
|
220
|
-
PrimaryDiagnosisDiseaseGroup = Literal[
|
|
221
|
-
"Ovarian epithelial cancer",
|
|
222
|
-
"Esophageal cancer, NOS",
|
|
223
|
-
"Primary peritoneal carcinoma",
|
|
224
|
-
"Gastric cancer, NOS",
|
|
225
|
-
"Fallopian tube carcinoma",
|
|
226
|
-
"Invasive breast carcinoma",
|
|
227
|
-
"Small cell lung cancer",
|
|
228
|
-
"Prostate cancer, NOS",
|
|
229
|
-
"Non-small cell lung cancer, NOS",
|
|
230
|
-
"Myeloma, NOS",
|
|
231
|
-
"Melanoma",
|
|
232
|
-
"Adenocarcinoma of the gastroesophageal junction",
|
|
233
|
-
"Acute myeloid leukemia, NOS",
|
|
234
|
-
"Colorectal cancer, NOS",
|
|
235
|
-
]
|
|
236
|
-
|
|
237
|
-
|
|
238
249
|
TumorGrade = Literal[
|
|
239
250
|
"G1 Low Grade",
|
|
240
251
|
"G2 Intermediate Grade",
|
|
@@ -255,12 +266,20 @@ CancerStageSystem = Literal[
|
|
|
255
266
|
]
|
|
256
267
|
|
|
257
268
|
|
|
258
|
-
CancerStageSystemVersionAJCC = Literal["
|
|
269
|
+
CancerStageSystemVersionAJCC = Literal["8th Edition",]
|
|
259
270
|
|
|
260
|
-
CancerStageSystemVersionRISS = Literal["
|
|
271
|
+
CancerStageSystemVersionRISS = Literal["10.1200/JCO.2015.61.2267"]
|
|
261
272
|
|
|
262
|
-
|
|
263
|
-
|
|
273
|
+
CancerStageSystemVersionFIGO = Literal[
|
|
274
|
+
"10.1002/ijgo.14923",
|
|
275
|
+
"10.1002/ijgo.13881",
|
|
276
|
+
"10.1002/ijgo.13867",
|
|
277
|
+
"10.1002/ijgo.13865",
|
|
278
|
+
"10.1002/ijgo.13866",
|
|
279
|
+
"10.1002/ijgo.13878",
|
|
280
|
+
"10.1002/ijgo.13877",
|
|
281
|
+
"10.1002/ijgo.12613",
|
|
282
|
+
]
|
|
264
283
|
|
|
265
284
|
CancerStageSystemVersion = CancerStageSystemVersionAJCC | CancerStageSystemVersionFIGO | CancerStageSystemVersionRISS
|
|
266
285
|
|
|
@@ -296,7 +315,6 @@ CancerStageAJCC = Literal[
|
|
|
296
315
|
|
|
297
316
|
|
|
298
317
|
CancerStageFIGO = Literal[
|
|
299
|
-
"value",
|
|
300
318
|
"Stage I",
|
|
301
319
|
"Stage IA",
|
|
302
320
|
"Stage IA1",
|
|
@@ -1027,21 +1045,6 @@ GVHDDiagnosisChronicGlobalSeverity = Literal["Mild", "Moderate", "Severe"]
|
|
|
1027
1045
|
GVHDOrganChronicScore = Literal["0", "1", "2", "3"]
|
|
1028
1046
|
|
|
1029
1047
|
|
|
1030
|
-
PriorTreatmentType = Literal[
|
|
1031
|
-
"Surgery",
|
|
1032
|
-
"Radiotherapy",
|
|
1033
|
-
"Immunotherapy",
|
|
1034
|
-
"Chemotherapy",
|
|
1035
|
-
"Targeted therapy",
|
|
1036
|
-
"Other therapy",
|
|
1037
|
-
"Radiopharmaceutical",
|
|
1038
|
-
"Stem cell transplant",
|
|
1039
|
-
"Immunosuppressive therapy/GVHD prophylaxis for transplant",
|
|
1040
|
-
"Conditioning therapy",
|
|
1041
|
-
"Post-transplant salvage therapy",
|
|
1042
|
-
]
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
1048
|
ConditioningRegimenType = Literal["Myeloablative", "Reduced-intensity", "Non-myeloablative", "Other"]
|
|
1046
1049
|
|
|
1047
1050
|
StemCellDonorType = Literal["Autologous", "Allogeneic"]
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from urllib.parse import quote
|
|
3
|
+
|
|
4
|
+
from werkzeug.exceptions import BadRequest
|
|
5
|
+
|
|
6
|
+
from cidc_api.models import IngestionJobs
|
|
7
|
+
from . import gcloud_client
|
|
8
|
+
from ..shared.auth import get_current_user
|
|
9
|
+
|
|
10
|
+
JOB_TYPE_ASSAY = "assay"
|
|
11
|
+
JOB_TYPE_CLINICAL = "clinical"
|
|
12
|
+
ALLOWED_JOB_TYPES = {JOB_TYPE_CLINICAL, JOB_TYPE_ASSAY}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def resolve_job_type_and_assay_fields(data: dict) -> tuple[str, str | None, str | None]:
|
|
16
|
+
"""Decide job_type and gather assay_type/batch_id from request JSON."""
|
|
17
|
+
assay_type = data.get("assay_type")
|
|
18
|
+
# If job_type is assay or assay_type is present, treat this as an assay job.
|
|
19
|
+
job_type = data.get("job_type") or (JOB_TYPE_ASSAY if assay_type else JOB_TYPE_CLINICAL)
|
|
20
|
+
|
|
21
|
+
if job_type not in ALLOWED_JOB_TYPES:
|
|
22
|
+
raise BadRequest("Invalid job_type. Allowed values are 'clinical' or 'assay'.")
|
|
23
|
+
|
|
24
|
+
if job_type == JOB_TYPE_ASSAY and (not assay_type or not isinstance(assay_type, str)):
|
|
25
|
+
raise BadRequest("assay_type must be provided for job_type='assay'.")
|
|
26
|
+
|
|
27
|
+
assay_type = assay_type.strip() if assay_type else None
|
|
28
|
+
batch_id = data.get("batch_id").strip() if isinstance(data.get("batch_id"), str) else None
|
|
29
|
+
|
|
30
|
+
return job_type, assay_type, batch_id
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def prepare_assay_job(trial_id: str, assay_type: str, batch_id: str) -> tuple[str, str, str, datetime, int, str]:
|
|
34
|
+
"""
|
|
35
|
+
Validate assay job uniqueness and generate submission_id, start_date, version, and the trial’s GCS intake path.
|
|
36
|
+
"""
|
|
37
|
+
if not assay_type:
|
|
38
|
+
raise BadRequest("assay_type must be provided for job_type='assay'.")
|
|
39
|
+
|
|
40
|
+
# Enforce uniqueness of (trial_id, assay_type, batch_id) when batch_id is present.
|
|
41
|
+
if batch_id:
|
|
42
|
+
existing_job = IngestionJobs.get_unique_assay_job(trial_id, assay_type, batch_id)
|
|
43
|
+
if existing_job:
|
|
44
|
+
raise BadRequest(
|
|
45
|
+
f"Assay job {existing_job.id} already exists for this exact trial_id/assay_type/batch_id combination."
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
submission_id = IngestionJobs.next_assay_submission_id(trial_id, assay_type)
|
|
49
|
+
job_status = "INITIAL SUBMISSION"
|
|
50
|
+
error_status = "Upload Incomplete" # job starts with 'Incomplete' notifier
|
|
51
|
+
start_date = datetime.now()
|
|
52
|
+
version = 1
|
|
53
|
+
|
|
54
|
+
# Create or retrieve intake bucket corresponding to the trial
|
|
55
|
+
intake_bucket = gcloud_client.create_intake_bucket(get_current_user().email, trial_id=trial_id)
|
|
56
|
+
gcs_path = f"{intake_bucket.name}/{assay_type}/{submission_id}"
|
|
57
|
+
|
|
58
|
+
return submission_id, job_status, error_status, start_date, version, gcs_path
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def get_google_links(intake_path: str) -> tuple[str, str]:
|
|
62
|
+
"""Build the GCS URI and GCS Console URL corresponding to the intake path."""
|
|
63
|
+
gcs_uri = f"gs://{intake_path}"
|
|
64
|
+
# Encode path to ensure link opens correctly
|
|
65
|
+
encoded_path = quote(intake_path)
|
|
66
|
+
console_url = f"https://console.cloud.google.com/storage/browser/{encoded_path}"
|
|
67
|
+
|
|
68
|
+
return gcs_uri, console_url
|
cidc_api/shared/auth.py
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
from functools import wraps
|
|
2
2
|
from typing import List
|
|
3
3
|
|
|
4
|
-
from packaging import version
|
|
5
|
-
|
|
6
4
|
from flask import g, request, current_app as app, Flask
|
|
5
|
+
from packaging import version
|
|
7
6
|
from werkzeug.exceptions import Unauthorized, BadRequest, PreconditionFailed
|
|
8
7
|
|
|
9
|
-
from ..models import Users, UserSchema
|
|
10
|
-
|
|
11
8
|
from ..config.logging import get_logger
|
|
12
|
-
|
|
9
|
+
from ..models import Users, UserSchema
|
|
13
10
|
from ..shared.jose import decode_id_token
|
|
11
|
+
from ..telemetry import trace_
|
|
14
12
|
|
|
15
13
|
logger = get_logger(__name__)
|
|
16
14
|
|
|
@@ -144,6 +142,7 @@ def get_current_user() -> Users:
|
|
|
144
142
|
_user_schema = UserSchema()
|
|
145
143
|
|
|
146
144
|
|
|
145
|
+
@trace_()
|
|
147
146
|
def authenticate() -> Users:
|
|
148
147
|
id_token = _extract_token()
|
|
149
148
|
token_payload = decode_id_token(id_token)
|
|
@@ -172,6 +171,7 @@ def _extract_token() -> str:
|
|
|
172
171
|
|
|
173
172
|
|
|
174
173
|
### Authorization logic ###
|
|
174
|
+
@trace_()
|
|
175
175
|
def authorize(user: Users, allowed_roles: List[str], resource: str, method: str) -> bool:
|
|
176
176
|
"""Check if the current user is authorized to act on the current request's resource.
|
|
177
177
|
Raises Unauthorized
|
cidc_api/shared/file_handling.py
CHANGED
|
@@ -10,22 +10,33 @@ from ..config.settings import GOOGLE_CLINICAL_DATA_BUCKET
|
|
|
10
10
|
from ..models import PreprocessedFiles, TRIAL_APPENDIX_A_CELL_THAT_ENDS_THE_HEADER
|
|
11
11
|
from ..shared.auth import get_current_user
|
|
12
12
|
from ..shared.gcloud_client import upload_file_to_gcs, move_gcs_file
|
|
13
|
+
from ..telemetry import trace_
|
|
13
14
|
|
|
14
15
|
logger = get_logger(__name__)
|
|
15
16
|
|
|
16
17
|
|
|
18
|
+
@trace_()
|
|
17
19
|
def set_current_file(
|
|
18
|
-
file: FileStorage,
|
|
20
|
+
file: FileStorage,
|
|
21
|
+
file_category: str,
|
|
22
|
+
gcs_folder: str,
|
|
23
|
+
session: Session,
|
|
24
|
+
uploader_email: str,
|
|
25
|
+
job_id: int = None,
|
|
26
|
+
append_timestamp: bool = None,
|
|
19
27
|
) -> PreprocessedFiles:
|
|
20
28
|
"""
|
|
21
29
|
Archives any existing 'current' files for the given category and job,
|
|
22
30
|
then uploads the new file as the latest 'current' version.
|
|
23
31
|
"""
|
|
24
32
|
latest_version = PreprocessedFiles.archive_current_files(file_category, job_id=job_id, session=session)
|
|
25
|
-
latest_file = create_file(
|
|
33
|
+
latest_file = create_file(
|
|
34
|
+
file, gcs_folder, file_category, session, uploader_email, job_id, latest_version + 1, append_timestamp
|
|
35
|
+
)
|
|
26
36
|
return latest_file
|
|
27
37
|
|
|
28
38
|
|
|
39
|
+
@trace_()
|
|
29
40
|
def create_file(
|
|
30
41
|
file: FileStorage,
|
|
31
42
|
gcs_folder: str,
|
|
@@ -34,11 +45,12 @@ def create_file(
|
|
|
34
45
|
uploader_email: str,
|
|
35
46
|
job_id: int = None,
|
|
36
47
|
version: int = None,
|
|
48
|
+
append_timestamp: bool = None,
|
|
37
49
|
) -> PreprocessedFiles:
|
|
38
50
|
"""Upload file to GCS and create corresponding metadata record in the database."""
|
|
39
51
|
status = "pending" if gcs_folder.endswith("pending/") else "current"
|
|
40
|
-
# only need timestamp for current/versioned files
|
|
41
|
-
append_timestamp = status == "current"
|
|
52
|
+
# only need timestamp for current/versioned files, if not specified otherwise
|
|
53
|
+
append_timestamp = append_timestamp if append_timestamp is not None else (status == "current")
|
|
42
54
|
# create file in GCS
|
|
43
55
|
gcs_file_path = upload_file_to_gcs(file, GOOGLE_CLINICAL_DATA_BUCKET, gcs_folder, append_timestamp=append_timestamp)
|
|
44
56
|
# create corresponding record in db
|