nci-cidc-api-modules 1.2.50__py3-none-any.whl → 1.2.52__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 -1
- cidc_api/config/settings.py +1 -0
- cidc_api/models/models.py +13 -2
- cidc_api/models/pydantic/base.py +63 -2
- cidc_api/models/pydantic/stage1/adverse_event.py +36 -28
- cidc_api/models/pydantic/stage1/comorbidity.py +12 -7
- cidc_api/models/pydantic/stage1/demographic.py +32 -22
- cidc_api/models/pydantic/stage1/disease.py +70 -44
- cidc_api/models/pydantic/stage1/exposure.py +9 -7
- cidc_api/models/pydantic/stage1/medical_history.py +10 -7
- cidc_api/models/pydantic/stage1/other_malignancy.py +14 -10
- cidc_api/models/pydantic/stage1/participant.py +16 -11
- cidc_api/models/pydantic/stage1/radiotherapy_dose.py +17 -11
- cidc_api/models/pydantic/stage1/response.py +24 -15
- cidc_api/models/pydantic/stage1/response_by_system.py +78 -45
- cidc_api/models/pydantic/stage1/surgery.py +10 -6
- cidc_api/models/pydantic/stage1/therapy_agent_dose.py +17 -11
- cidc_api/models/pydantic/stage1/treatment.py +18 -11
- cidc_api/shared/gcloud_client.py +7 -0
- {nci_cidc_api_modules-1.2.50.dist-info → nci_cidc_api_modules-1.2.52.dist-info}/METADATA +2 -2
- {nci_cidc_api_modules-1.2.50.dist-info → nci_cidc_api_modules-1.2.52.dist-info}/RECORD +24 -24
- {nci_cidc_api_modules-1.2.50.dist-info → nci_cidc_api_modules-1.2.52.dist-info}/WHEEL +1 -1
- {nci_cidc_api_modules-1.2.50.dist-info → nci_cidc_api_modules-1.2.52.dist-info}/licenses/LICENSE +0 -0
- {nci_cidc_api_modules-1.2.50.dist-info → nci_cidc_api_modules-1.2.52.dist-info}/top_level.txt +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from pydantic import NonPositiveInt, model_validator
|
|
1
|
+
from pydantic import NonPositiveInt
|
|
2
|
+
from cidc_api.models.pydantic.base import forced_validator, forced_validators
|
|
4
3
|
|
|
5
4
|
from cidc_api.models.errors import ValueLocError
|
|
6
5
|
from cidc_api.models.pydantic.base import Base
|
|
7
6
|
from cidc_api.models.types import UberonAnatomicalTerm, ICDO3MorphologicalCode, ICDO3MorphologicalTerm, MalignancyStatus
|
|
8
7
|
|
|
9
8
|
|
|
9
|
+
@forced_validators
|
|
10
10
|
class OtherMalignancy(Base):
|
|
11
11
|
__data_category__ = "other_malignancy"
|
|
12
12
|
__cardinality__ = "many"
|
|
@@ -37,15 +37,19 @@ class OtherMalignancy(Base):
|
|
|
37
37
|
# Indicates the participant’s current clinical state regarding the cancer diagnosis.
|
|
38
38
|
other_malignancy_status: MalignancyStatus | None = None
|
|
39
39
|
|
|
40
|
-
@
|
|
41
|
-
|
|
40
|
+
@forced_validator
|
|
41
|
+
@classmethod
|
|
42
|
+
def validate_code_or_term_or_description_cr(cls, data, info) -> None:
|
|
43
|
+
other_malignancy_morphological_term = data.get("other_malignancy_morphological_term", None)
|
|
44
|
+
other_malignancy_description = data.get("other_malignancy_description", None)
|
|
45
|
+
other_malignancy_morphological_code = data.get("other_malignancy_morphological_code", None)
|
|
46
|
+
|
|
42
47
|
if (
|
|
43
|
-
not
|
|
44
|
-
and not
|
|
45
|
-
and not
|
|
48
|
+
not other_malignancy_morphological_code
|
|
49
|
+
and not other_malignancy_morphological_term
|
|
50
|
+
and not other_malignancy_description
|
|
46
51
|
):
|
|
47
52
|
raise ValueLocError(
|
|
48
53
|
'Please provide at least one of "morphological_code", "morphological_term" or "malignancy_description".',
|
|
49
|
-
loc="
|
|
54
|
+
loc="other_malignancy_morphological_code",
|
|
50
55
|
)
|
|
51
|
-
return self
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from pydantic import model_validator
|
|
1
|
+
from cidc_api.models.pydantic.base import forced_validator, forced_validators
|
|
4
2
|
|
|
5
3
|
from cidc_api.models.errors import ValueLocError
|
|
6
4
|
from cidc_api.models.pydantic.base import Base
|
|
@@ -8,6 +6,7 @@ from cidc_api.models.types import YNU
|
|
|
8
6
|
from cidc_api.models.types import OffStudyReason
|
|
9
7
|
|
|
10
8
|
|
|
9
|
+
@forced_validators
|
|
11
10
|
class Participant(Base):
|
|
12
11
|
__data_category__ = "participant"
|
|
13
12
|
__cardinality__ = "one"
|
|
@@ -39,20 +38,26 @@ class Participant(Base):
|
|
|
39
38
|
# Additional information if "Other" is selected for off_study_reason. e.g. "Transfer to another study"
|
|
40
39
|
off_study_reason_other: str | None = None
|
|
41
40
|
|
|
42
|
-
@
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
@forced_validator
|
|
42
|
+
@classmethod
|
|
43
|
+
def off_study_reason_cr(cls, data, info) -> None:
|
|
44
|
+
off_study = data.get("off_study", None)
|
|
45
|
+
off_study_reason = data.get("off_study_reason", None)
|
|
46
|
+
|
|
47
|
+
if off_study == "Yes" and not off_study_reason:
|
|
45
48
|
raise ValueLocError(
|
|
46
49
|
'If "off_study" is "Yes" then "off_study_reason" is required.',
|
|
47
50
|
loc="off_study_reason",
|
|
48
51
|
)
|
|
49
|
-
return self
|
|
50
52
|
|
|
51
|
-
@
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
@forced_validator
|
|
54
|
+
@classmethod
|
|
55
|
+
def off_study_reason_other_cr(cls, data, info) -> None:
|
|
56
|
+
off_study_reason_other = data.get("off_study_reason_other", None)
|
|
57
|
+
off_study_reason = data.get("off_study_reason", None)
|
|
58
|
+
|
|
59
|
+
if off_study_reason == "Other" and not off_study_reason_other:
|
|
54
60
|
raise ValueLocError(
|
|
55
61
|
'If "off_study_reason" is "Other" then "off_study_reason_other" is required.',
|
|
56
62
|
loc="off_study_reason_other",
|
|
57
63
|
)
|
|
58
|
-
return self
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from pydantic import NonNegativeInt, NonNegativeFloat, model_validator
|
|
1
|
+
from pydantic import NonNegativeInt, NonNegativeFloat
|
|
2
|
+
from cidc_api.models.pydantic.base import forced_validator, forced_validators
|
|
4
3
|
|
|
5
4
|
from cidc_api.models.errors import ValueLocError
|
|
6
5
|
from cidc_api.models.pydantic.base import Base
|
|
@@ -13,6 +12,7 @@ from cidc_api.models.types import (
|
|
|
13
12
|
)
|
|
14
13
|
|
|
15
14
|
|
|
15
|
+
@forced_validators
|
|
16
16
|
class RadiotherapyDose(Base):
|
|
17
17
|
__data_category__ = "radiotherapy_dose"
|
|
18
18
|
__cardinality__ = "many"
|
|
@@ -67,20 +67,26 @@ class RadiotherapyDose(Base):
|
|
|
67
67
|
# CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=7063755%20and%20ver_nr=1
|
|
68
68
|
radiation_extent: RadiationExtent
|
|
69
69
|
|
|
70
|
-
@
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
@forced_validator
|
|
71
|
+
@classmethod
|
|
72
|
+
def validate_changes_delays_description_cr(cls, data, info) -> None:
|
|
73
|
+
dose_changes_delays = data.get("dose_changes_delays", None)
|
|
74
|
+
changes_delays_description = data.get("changes_delays_description", None)
|
|
75
|
+
|
|
76
|
+
if dose_changes_delays == "Yes" and not changes_delays_description:
|
|
73
77
|
raise ValueLocError(
|
|
74
78
|
'If dose_changes_delays is "Yes", please provide changes_delays_description.',
|
|
75
79
|
loc="changes_delays_description",
|
|
76
80
|
)
|
|
77
|
-
return self
|
|
78
81
|
|
|
79
|
-
@
|
|
80
|
-
|
|
81
|
-
|
|
82
|
+
@forced_validator
|
|
83
|
+
@classmethod
|
|
84
|
+
def validate_planned_dose_units_cr(cls, data, info) -> None:
|
|
85
|
+
planned_dose = data.get("planned_dose", None)
|
|
86
|
+
planned_dose_units = data.get("planned_dose_units", None)
|
|
87
|
+
|
|
88
|
+
if planned_dose and not planned_dose_units:
|
|
82
89
|
raise ValueLocError(
|
|
83
90
|
"If planned_dose is provided, please provide planned_dose_units.",
|
|
84
91
|
loc="planned_dose_units",
|
|
85
92
|
)
|
|
86
|
-
return self
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from pydantic import NonNegativeInt, model_validator
|
|
1
|
+
from pydantic import NonNegativeInt
|
|
2
|
+
from cidc_api.models.pydantic.base import forced_validator, forced_validators
|
|
4
3
|
|
|
5
4
|
from cidc_api.models.errors import ValueLocError
|
|
6
5
|
from cidc_api.models.pydantic.base import Base
|
|
7
6
|
from cidc_api.models.types import SurvivalStatus, YNUNA, CauseOfDeath
|
|
8
7
|
|
|
9
8
|
|
|
9
|
+
@forced_validators
|
|
10
10
|
class Response(Base):
|
|
11
11
|
__data_category__ = "response"
|
|
12
12
|
__cardinality__ = "one"
|
|
@@ -47,29 +47,38 @@ class Response(Base):
|
|
|
47
47
|
# Days from enrollment date to the last time the patient's vital status was verified.
|
|
48
48
|
days_to_last_vital_status: NonNegativeInt | None = None
|
|
49
49
|
|
|
50
|
-
@
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
@forced_validator
|
|
51
|
+
@classmethod
|
|
52
|
+
def validate_cause_of_death_cr(cls, data, info) -> None:
|
|
53
|
+
survival_status = data.get("survival_status", None)
|
|
54
|
+
cause_of_death = data.get("cause_of_death", None)
|
|
55
|
+
|
|
56
|
+
if survival_status == "Dead" and not cause_of_death:
|
|
53
57
|
raise ValueLocError(
|
|
54
58
|
'If survival_status is "Dead" then cause_of_death is required.',
|
|
55
59
|
loc="cause_of_death",
|
|
56
60
|
)
|
|
57
|
-
return self
|
|
58
61
|
|
|
59
|
-
@
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
@forced_validator
|
|
63
|
+
@classmethod
|
|
64
|
+
def validate_cause_of_death_cr2(cls, data, info) -> None:
|
|
65
|
+
survival_status = data.get("survival_status", None)
|
|
66
|
+
cause_of_death = data.get("cause_of_death", None)
|
|
67
|
+
|
|
68
|
+
if survival_status == "Alive" and cause_of_death:
|
|
62
69
|
raise ValueLocError(
|
|
63
70
|
'If survival_status is "Alive", please leave cause_of_death blank.',
|
|
64
71
|
loc="cause_of_death",
|
|
65
72
|
)
|
|
66
|
-
return self
|
|
67
73
|
|
|
68
|
-
@
|
|
69
|
-
|
|
70
|
-
|
|
74
|
+
@forced_validator
|
|
75
|
+
@classmethod
|
|
76
|
+
def validate_days_to_death_cr(cls, data, info) -> None:
|
|
77
|
+
survival_status = data.get("survival_status", None)
|
|
78
|
+
days_to_death = data.get("days_to_death", None)
|
|
79
|
+
|
|
80
|
+
if survival_status in ["Alive", "Unknown"] and days_to_death:
|
|
71
81
|
raise ValueLocError(
|
|
72
82
|
"If survival_status does not indicate death, please leave days_to_death blank.",
|
|
73
83
|
loc="days_to_death",
|
|
74
84
|
)
|
|
75
|
-
return self
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from typing import Self
|
|
2
2
|
|
|
3
|
-
from pydantic import PositiveInt,
|
|
3
|
+
from pydantic import PositiveInt, NonNegativeInt, model_validator
|
|
4
|
+
from cidc_api.models.pydantic.base import forced_validator, forced_validators
|
|
4
5
|
|
|
5
6
|
from cidc_api.models.errors import ValueLocError
|
|
6
7
|
from cidc_api.models.pydantic.base import Base
|
|
@@ -19,6 +20,7 @@ negative_response_values = [
|
|
|
19
20
|
]
|
|
20
21
|
|
|
21
22
|
|
|
23
|
+
@forced_validators
|
|
22
24
|
class ResponseBySystem(Base):
|
|
23
25
|
__data_category__ = "response_by_system"
|
|
24
26
|
__cardinality__ = "many"
|
|
@@ -71,90 +73,117 @@ class ResponseBySystem(Base):
|
|
|
71
73
|
# CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=5143957%20and%20ver_nr=1
|
|
72
74
|
progression_free_survival: PositiveInt | None = None
|
|
73
75
|
|
|
74
|
-
@
|
|
75
|
-
|
|
76
|
-
|
|
76
|
+
@forced_validator
|
|
77
|
+
@classmethod
|
|
78
|
+
def validate_response_duration_cr(cls, data, info) -> None:
|
|
79
|
+
best_overall_response = data.get("best_overall_response", None)
|
|
80
|
+
response_duration = data.get("response_duration", None)
|
|
81
|
+
|
|
82
|
+
if best_overall_response in negative_response_values and response_duration:
|
|
77
83
|
raise ValueLocError(
|
|
78
84
|
"If best_overall_response does not indicate a positive response, "
|
|
79
85
|
"please leave response_duration blank.",
|
|
80
86
|
loc="response_duration",
|
|
81
87
|
)
|
|
82
|
-
return self
|
|
83
88
|
|
|
84
|
-
@
|
|
85
|
-
|
|
86
|
-
|
|
89
|
+
@forced_validator
|
|
90
|
+
@classmethod
|
|
91
|
+
def validate_days_to_first_response_cr(cls, data, info) -> None:
|
|
92
|
+
best_overall_response = data.get("best_overall_response", None)
|
|
93
|
+
days_to_first_response = data.get("days_to_first_response", None)
|
|
94
|
+
|
|
95
|
+
if best_overall_response in negative_response_values and days_to_first_response:
|
|
87
96
|
raise ValueLocError(
|
|
88
97
|
"If best_overall_response does not indicate a positive response, "
|
|
89
98
|
"please leave days_to_first_response blank.",
|
|
90
99
|
loc="days_to_first_response",
|
|
91
100
|
)
|
|
92
|
-
return self
|
|
93
101
|
|
|
94
|
-
@
|
|
95
|
-
|
|
96
|
-
|
|
102
|
+
@forced_validator
|
|
103
|
+
@classmethod
|
|
104
|
+
def validate_days_to_best_response_cr(cls, data, info) -> None:
|
|
105
|
+
best_overall_response = data.get("best_overall_response", None)
|
|
106
|
+
days_to_best_response = data.get("days_to_best_response", None)
|
|
107
|
+
|
|
108
|
+
if best_overall_response in negative_response_values and days_to_best_response:
|
|
97
109
|
raise ValueLocError(
|
|
98
|
-
"If best_overall_response does not indicate a positive response,
|
|
99
|
-
please leave days_to_best_response blank.",
|
|
110
|
+
"If best_overall_response does not indicate a positive response, "
|
|
111
|
+
"please leave days_to_best_response blank.",
|
|
100
112
|
loc="days_to_best_response",
|
|
101
113
|
)
|
|
102
|
-
return self
|
|
103
114
|
|
|
104
|
-
@
|
|
105
|
-
|
|
106
|
-
|
|
115
|
+
@forced_validator
|
|
116
|
+
@classmethod
|
|
117
|
+
def validate_days_to_disease_progression_cr(cls, data, info) -> None:
|
|
118
|
+
progression = data.get("progression", None)
|
|
119
|
+
days_to_disease_progression = data.get("days_to_disease_progression", None)
|
|
120
|
+
|
|
121
|
+
if progression in ["No", "Unknown", "Not Applicable"] and days_to_disease_progression:
|
|
107
122
|
raise ValueLocError(
|
|
108
|
-
"If progression does not indicate confirmed progression of the disease,
|
|
109
|
-
please leave
|
|
110
|
-
loc="
|
|
123
|
+
"If progression does not indicate confirmed progression of the disease, "
|
|
124
|
+
"please leave days_to_disease_progression blank.",
|
|
125
|
+
loc="days_to_disease_progression",
|
|
111
126
|
)
|
|
112
|
-
return self
|
|
113
127
|
|
|
114
|
-
@
|
|
115
|
-
|
|
116
|
-
|
|
128
|
+
@forced_validator
|
|
129
|
+
@classmethod
|
|
130
|
+
def validate_progression_free_survival_cr(cls, data, info) -> None:
|
|
131
|
+
progression_free_survival_event = data.get("progression_free_survival_event", None)
|
|
132
|
+
progression_free_survival = data.get("progression_free_survival", None)
|
|
133
|
+
|
|
134
|
+
if progression_free_survival_event in ["Unknown", "Not Applicable"] and progression_free_survival:
|
|
117
135
|
raise ValueLocError(
|
|
118
|
-
"If progression_free_survival_event is not known,
|
|
119
|
-
please leave progression_free_survival blank.",
|
|
136
|
+
"If progression_free_survival_event is not known, " "please leave progression_free_survival blank.",
|
|
120
137
|
loc="progression_free_survival",
|
|
121
138
|
)
|
|
122
|
-
return self
|
|
123
139
|
|
|
124
|
-
@
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
140
|
+
@forced_validator
|
|
141
|
+
@classmethod
|
|
142
|
+
def validate_days_to_best_response_chronology(cls, data, info) -> None:
|
|
143
|
+
days_to_first_response = data.get("days_to_first_response", None)
|
|
144
|
+
days_to_best_response = data.get("days_to_best_response", None)
|
|
145
|
+
|
|
146
|
+
if days_to_best_response is not None and days_to_first_response is not None:
|
|
147
|
+
if int(days_to_best_response) < int(days_to_first_response):
|
|
128
148
|
raise ValueLocError(
|
|
129
149
|
'Violate "days_to_best_response" >= days_to_first_response"',
|
|
130
150
|
loc="days_to_best_response",
|
|
131
151
|
)
|
|
132
|
-
return self
|
|
133
152
|
|
|
134
|
-
@
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
153
|
+
@forced_validator
|
|
154
|
+
@classmethod
|
|
155
|
+
def validate_days_to_disease_progression_chronology(cls, data, info) -> None:
|
|
156
|
+
days_to_disease_progression = data.get("days_to_disease_progression", None)
|
|
157
|
+
days_to_first_response = data.get("days_to_first_response", None)
|
|
158
|
+
|
|
159
|
+
if days_to_first_response is not None and days_to_disease_progression is not None:
|
|
160
|
+
if int(days_to_first_response) >= int(days_to_disease_progression):
|
|
138
161
|
raise ValueLocError(
|
|
139
162
|
'Violate "days_to_first_response" < "days_to_disease_progression"',
|
|
140
163
|
loc="days_to_first_response",
|
|
141
164
|
)
|
|
142
|
-
return self
|
|
143
165
|
|
|
144
|
-
@
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
166
|
+
@forced_validator
|
|
167
|
+
@classmethod
|
|
168
|
+
def validate_days_to_best_response_progression_chronology(cls, data, info) -> None:
|
|
169
|
+
days_to_disease_progression = data.get("days_to_disease_progression", None)
|
|
170
|
+
days_to_best_response = data.get("days_to_best_response", None)
|
|
171
|
+
|
|
172
|
+
if days_to_best_response is not None and days_to_disease_progression is not None:
|
|
173
|
+
if int(days_to_best_response) >= int(days_to_disease_progression):
|
|
148
174
|
raise ValueLocError(
|
|
149
175
|
'Violate "days_to_best_response" < "days_to_disease_progression"',
|
|
150
176
|
loc="days_to_best_response",
|
|
151
177
|
)
|
|
152
|
-
return self
|
|
153
178
|
|
|
154
179
|
@model_validator(mode="after")
|
|
155
180
|
def validate_days_to_last_vital_status_chronology(self) -> Self:
|
|
156
|
-
if not self.response
|
|
181
|
+
if not self.response:
|
|
182
|
+
return self
|
|
183
|
+
|
|
184
|
+
if not self.response.days_to_last_vital_status:
|
|
157
185
|
return self
|
|
186
|
+
|
|
158
187
|
max_value = max(
|
|
159
188
|
self.response.days_to_last_vital_status or 0,
|
|
160
189
|
self.days_to_first_response or 0,
|
|
@@ -171,8 +200,11 @@ class ResponseBySystem(Base):
|
|
|
171
200
|
|
|
172
201
|
@model_validator(mode="after")
|
|
173
202
|
def validate_days_to_death_chronology(self) -> Self:
|
|
174
|
-
if not self.response
|
|
203
|
+
if not self.response:
|
|
175
204
|
return self
|
|
205
|
+
if not self.response.days_to_death:
|
|
206
|
+
return self
|
|
207
|
+
|
|
176
208
|
max_value = max(
|
|
177
209
|
self.response.days_to_death or 0,
|
|
178
210
|
self.days_to_first_response or 0,
|
|
@@ -185,3 +217,4 @@ class ResponseBySystem(Base):
|
|
|
185
217
|
">= max(days_to_first_response,days_to_best_response,days_to_disease_progression)",
|
|
186
218
|
loc="days_to_death,days_to_first_response,days_to_best_response,days_to_disease_progression",
|
|
187
219
|
)
|
|
220
|
+
return self
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
from
|
|
1
|
+
from pydantic import NonNegativeInt
|
|
2
|
+
from cidc_api.models.pydantic.base import forced_validator, forced_validators
|
|
2
3
|
|
|
3
|
-
from pydantic import NonNegativeInt, model_validator
|
|
4
4
|
|
|
5
5
|
from cidc_api.models.errors import ValueLocError
|
|
6
6
|
from cidc_api.models.pydantic.base import Base
|
|
7
7
|
from cidc_api.models.types import SurgicalProcedure, UberonAnatomicalTerm, YNU
|
|
8
8
|
|
|
9
9
|
|
|
10
|
+
@forced_validators
|
|
10
11
|
class Surgery(Base):
|
|
11
12
|
__data_category__ = "surgery"
|
|
12
13
|
__cardinality__ = "many"
|
|
@@ -43,11 +44,14 @@ class Surgery(Base):
|
|
|
43
44
|
# CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=13362284%20and%20ver_nr=1
|
|
44
45
|
extent_of_residual_disease: str | None = None
|
|
45
46
|
|
|
46
|
-
@
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
@forced_validator
|
|
48
|
+
@classmethod
|
|
49
|
+
def validate_procedure_other_cr(cls, data, info) -> None:
|
|
50
|
+
procedure = data.get("procedure", None)
|
|
51
|
+
procedure_other = data.get("procedure_other", None)
|
|
52
|
+
|
|
53
|
+
if procedure == "Other, specify" and not procedure_other:
|
|
49
54
|
raise ValueLocError(
|
|
50
55
|
'If procedure is "Other, specify", please provide procedure_other.',
|
|
51
56
|
loc="procedure_other",
|
|
52
57
|
)
|
|
53
|
-
return self
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from pydantic import NonNegativeInt, NonNegativeFloat, PositiveFloat, model_validator
|
|
1
|
+
from pydantic import NonNegativeInt, NonNegativeFloat, PositiveFloat
|
|
2
|
+
from cidc_api.models.pydantic.base import forced_validator, forced_validators
|
|
4
3
|
|
|
5
4
|
from cidc_api.models.errors import ValueLocError
|
|
6
5
|
from cidc_api.models.pydantic.base import Base
|
|
7
6
|
from cidc_api.models.types import YNU, TherapyAgentDoseUnits
|
|
8
7
|
|
|
9
8
|
|
|
9
|
+
@forced_validators
|
|
10
10
|
class TherapyAgentDose(Base):
|
|
11
11
|
__data_category__ = "therapy_agent_dose"
|
|
12
12
|
__cardinality__ = "many"
|
|
@@ -55,20 +55,26 @@ class TherapyAgentDose(Base):
|
|
|
55
55
|
# Description of the dose changes, misses, or delays.
|
|
56
56
|
changes_delays_description: str | None = None
|
|
57
57
|
|
|
58
|
-
@
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
@forced_validator
|
|
59
|
+
@classmethod
|
|
60
|
+
def validate_changes_delays_description_cr(cls, data, info) -> None:
|
|
61
|
+
dose_changes_delays = data.get("dose_changes_delays", None)
|
|
62
|
+
changes_delays_description = data.get("changes_delays_description", None)
|
|
63
|
+
|
|
64
|
+
if dose_changes_delays == "Yes" and not changes_delays_description:
|
|
61
65
|
raise ValueLocError(
|
|
62
66
|
'If dose_changes_delays is "Yes", please provide changes_delays_description.',
|
|
63
67
|
loc="changes_delays_description",
|
|
64
68
|
)
|
|
65
|
-
return self
|
|
66
69
|
|
|
67
|
-
@
|
|
68
|
-
|
|
69
|
-
|
|
70
|
+
@forced_validator
|
|
71
|
+
@classmethod
|
|
72
|
+
def validate_planned_dose_units_cr(cls, data, info) -> None:
|
|
73
|
+
planned_dose = data.get("planned_dose", None)
|
|
74
|
+
planned_dose_units = data.get("planned_dose_units", None)
|
|
75
|
+
|
|
76
|
+
if planned_dose and not planned_dose_units:
|
|
70
77
|
raise ValueLocError(
|
|
71
78
|
"If planned_dose is provided, please provide planned_dose_units.",
|
|
72
79
|
loc="planned_dose_units",
|
|
73
80
|
)
|
|
74
|
-
return self
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from pydantic import model_validator
|
|
1
|
+
from cidc_api.models.pydantic.base import forced_validator, forced_validators
|
|
4
2
|
|
|
5
3
|
from cidc_api.models.errors import ValueLocError
|
|
6
4
|
from cidc_api.models.pydantic.base import Base
|
|
7
5
|
from cidc_api.models.types import YNU, OffTreatmentReason
|
|
8
6
|
|
|
9
7
|
|
|
8
|
+
@forced_validators
|
|
10
9
|
class Treatment(Base):
|
|
11
10
|
__data_category__ = "treatment"
|
|
12
11
|
__cardinality__ = "many"
|
|
@@ -38,20 +37,28 @@ class Treatment(Base):
|
|
|
38
37
|
# If "Other" is selected for "off_treatment_reason", provide a description of the reason.
|
|
39
38
|
off_treatment_reason_other: str | None = None
|
|
40
39
|
|
|
41
|
-
@
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
@forced_validator
|
|
41
|
+
@classmethod
|
|
42
|
+
def validate_off_treatment_reason_cr(cls, data, info) -> None:
|
|
43
|
+
off_treatment = data.get("off_treatment", None)
|
|
44
|
+
off_treatment_reason = data.get("off_treatment_reason", None)
|
|
45
|
+
|
|
46
|
+
if off_treatment == "Yes" and not off_treatment_reason:
|
|
44
47
|
raise ValueLocError(
|
|
45
48
|
'If off_treatment is "Yes", please provide off_treatment_reason.',
|
|
46
49
|
loc="off_treatment_reason",
|
|
47
50
|
)
|
|
48
|
-
return
|
|
51
|
+
return off_treatment_reason
|
|
52
|
+
|
|
53
|
+
@forced_validator
|
|
54
|
+
@classmethod
|
|
55
|
+
def validate_off_treatment_reason_other_cr(cls, data, info) -> None:
|
|
56
|
+
off_treatment_reason = data.get("off_treatment_reason", None)
|
|
57
|
+
off_treatment_reason_other = data.get("off_treatment_reason_other", None)
|
|
49
58
|
|
|
50
|
-
|
|
51
|
-
def validate_off_treatment_reason_other_cr(self) -> Self:
|
|
52
|
-
if self.off_treatment_reason == "Other" and not self.off_treatment_reason_other:
|
|
59
|
+
if off_treatment_reason == "Other" and not off_treatment_reason_other:
|
|
53
60
|
raise ValueLocError(
|
|
54
61
|
'If off_treatment_reason is "Other", please provide off_treatment_reason_other.',
|
|
55
62
|
loc="off_treatment_reason_other",
|
|
56
63
|
)
|
|
57
|
-
return
|
|
64
|
+
return off_treatment_reason_other
|
cidc_api/shared/gcloud_client.py
CHANGED
|
@@ -61,6 +61,7 @@ from ..config.settings import (
|
|
|
61
61
|
GOOGLE_HL_CLINICAL_VALIDATION_TOPIC,
|
|
62
62
|
GOOGLE_DL_CLINICAL_VALIDATION_TOPIC,
|
|
63
63
|
GOOGLE_ASSAY_METADATA_VALIDATION_TOPIC,
|
|
64
|
+
GOOGLE_CLINICAL_DATA_INGESTION_PROCESSING_TOPIC,
|
|
64
65
|
TESTING,
|
|
65
66
|
ENV,
|
|
66
67
|
IS_EMAIL_ON,
|
|
@@ -1067,6 +1068,12 @@ def publish_assay_metadata_validation(job_id: int) -> None:
|
|
|
1067
1068
|
_report = _encode_and_publish(str(job_id), GOOGLE_ASSAY_METADATA_VALIDATION_TOPIC)
|
|
1068
1069
|
|
|
1069
1070
|
|
|
1071
|
+
def publish_clinical_data_ingestion(job_id: int) -> None:
|
|
1072
|
+
"""Start ingestion of clinical data job"""
|
|
1073
|
+
# Start asynchronously
|
|
1074
|
+
_report = _encode_and_publish(str(job_id), GOOGLE_CLINICAL_DATA_INGESTION_PROCESSING_TOPIC)
|
|
1075
|
+
|
|
1076
|
+
|
|
1070
1077
|
def send_email(to_emails: List[str], subject: str, html_content: str, **kw) -> None:
|
|
1071
1078
|
"""
|
|
1072
1079
|
Publish an email-to-send to the emails topic.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nci_cidc_api_modules
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.52
|
|
4
4
|
Summary: SQLAlchemy data models and configuration tools used in the NCI CIDC API
|
|
5
5
|
Home-page: https://github.com/NCI-CIDC/cidc-api-gae
|
|
6
6
|
License: MIT license
|
|
@@ -43,7 +43,7 @@ Requires-Dist: opentelemetry-instrumentation-requests>=0.59b0
|
|
|
43
43
|
Requires-Dist: opentelemetry-instrumentation-sqlalchemy>=0.59b0
|
|
44
44
|
Requires-Dist: opentelemetry-exporter-gcp-trace>=1.11.0
|
|
45
45
|
Requires-Dist: opentelemetry-propagator-gcp>=1.11.0
|
|
46
|
-
Requires-Dist: nci-cidc-schemas==0.28.
|
|
46
|
+
Requires-Dist: nci-cidc-schemas==0.28.12
|
|
47
47
|
Dynamic: description
|
|
48
48
|
Dynamic: description-content-type
|
|
49
49
|
Dynamic: home-page
|