nci-cidc-api-modules 1.2.34__py3-none-any.whl → 1.2.53__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.
Files changed (151) hide show
  1. boot.py +14 -0
  2. cidc_api/__init__.py +1 -0
  3. cidc_api/config/db.py +21 -1
  4. cidc_api/config/settings.py +5 -10
  5. cidc_api/models/__init__.py +0 -2
  6. cidc_api/models/data.py +15 -6
  7. cidc_api/models/db/stage1/__init__.py +56 -0
  8. cidc_api/models/db/stage1/additional_treatment_orm.py +22 -0
  9. cidc_api/models/db/stage1/adverse_event_orm.py +46 -0
  10. cidc_api/models/db/stage1/base_orm.py +7 -0
  11. cidc_api/models/db/stage1/baseline_clinical_assessment_orm.py +22 -0
  12. cidc_api/models/db/stage1/comorbidity_orm.py +23 -0
  13. cidc_api/models/db/stage1/consent_group_orm.py +32 -0
  14. cidc_api/models/db/stage1/demographic_orm.py +47 -0
  15. cidc_api/models/db/stage1/disease_orm.py +52 -0
  16. cidc_api/models/db/stage1/exposure_orm.py +22 -0
  17. cidc_api/models/db/stage1/gvhd_diagnosis_acute_orm.py +34 -0
  18. cidc_api/models/db/stage1/gvhd_diagnosis_chronic_orm.py +36 -0
  19. cidc_api/models/db/stage1/gvhd_organ_acute_orm.py +21 -0
  20. cidc_api/models/db/stage1/gvhd_organ_chronic_orm.py +21 -0
  21. cidc_api/models/db/stage1/medical_history_orm.py +30 -0
  22. cidc_api/models/db/stage1/other_malignancy_orm.py +29 -0
  23. cidc_api/models/db/stage1/participant_orm.py +77 -0
  24. cidc_api/models/db/stage1/prior_treatment_orm.py +29 -0
  25. cidc_api/models/db/stage1/radiotherapy_dose_orm.py +39 -0
  26. cidc_api/models/db/stage1/response_by_system_orm.py +30 -0
  27. cidc_api/models/db/stage1/response_orm.py +28 -0
  28. cidc_api/models/db/stage1/specimen_orm.py +46 -0
  29. cidc_api/models/db/stage1/stem_cell_transplant_orm.py +25 -0
  30. cidc_api/models/db/stage1/surgery_orm.py +27 -0
  31. cidc_api/models/db/stage1/therapy_agent_dose_orm.py +31 -0
  32. cidc_api/models/db/stage1/treatment_orm.py +38 -0
  33. cidc_api/models/db/stage1/trial_orm.py +35 -0
  34. cidc_api/models/db/stage2/additional_treatment_orm.py +6 -7
  35. cidc_api/models/db/stage2/administrative_person_orm.py +4 -4
  36. cidc_api/models/db/stage2/administrative_role_assignment_orm.py +4 -4
  37. cidc_api/models/db/stage2/adverse_event_orm.py +11 -13
  38. cidc_api/models/db/stage2/arm_orm.py +3 -3
  39. cidc_api/models/db/stage2/base_orm.py +7 -0
  40. cidc_api/models/db/stage2/baseline_clinical_assessment_orm.py +5 -7
  41. cidc_api/models/db/stage2/cohort_orm.py +3 -3
  42. cidc_api/models/db/stage2/comorbidity_orm.py +6 -8
  43. cidc_api/models/db/stage2/consent_group_orm.py +4 -4
  44. cidc_api/models/db/stage2/contact_orm.py +16 -20
  45. cidc_api/models/db/stage2/demographic_orm.py +3 -3
  46. cidc_api/models/db/stage2/disease_orm.py +4 -4
  47. cidc_api/models/db/stage2/exposure_orm.py +3 -3
  48. cidc_api/models/db/stage2/file_orm.py +6 -9
  49. cidc_api/models/db/stage2/gvhd_diagnosis_acute_orm.py +4 -4
  50. cidc_api/models/db/stage2/gvhd_diagnosis_chronic_orm.py +4 -6
  51. cidc_api/models/db/stage2/gvhd_organ_acute_orm.py +3 -3
  52. cidc_api/models/db/stage2/gvhd_organ_chronic_orm.py +3 -3
  53. cidc_api/models/db/stage2/institution_orm.py +7 -7
  54. cidc_api/models/db/stage2/medical_history_orm.py +9 -9
  55. cidc_api/models/db/stage2/other_clinical_endpoint_orm.py +8 -12
  56. cidc_api/models/db/stage2/other_malignancy_orm.py +8 -10
  57. cidc_api/models/db/stage2/participant_orm.py +23 -24
  58. cidc_api/models/db/stage2/prior_treatment_orm.py +12 -13
  59. cidc_api/models/db/stage2/publication_orm.py +9 -11
  60. cidc_api/models/db/stage2/radiotherapy_dose_orm.py +8 -9
  61. cidc_api/models/db/stage2/response_by_system_orm.py +3 -3
  62. cidc_api/models/db/stage2/response_orm.py +3 -3
  63. cidc_api/models/db/stage2/shipment_orm.py +17 -17
  64. cidc_api/models/db/stage2/shipment_specimen_orm.py +4 -4
  65. cidc_api/models/db/stage2/specimen_orm.py +7 -6
  66. cidc_api/models/db/stage2/stem_cell_transplant_orm.py +6 -7
  67. cidc_api/models/db/stage2/surgery_orm.py +6 -7
  68. cidc_api/models/db/stage2/therapy_agent_dose_orm.py +7 -8
  69. cidc_api/models/db/stage2/treatment_orm.py +15 -15
  70. cidc_api/models/db/stage2/trial_orm.py +15 -17
  71. cidc_api/models/errors.py +7 -0
  72. cidc_api/models/files/facets.py +4 -0
  73. cidc_api/models/models.py +167 -11
  74. cidc_api/models/pydantic/base.py +109 -0
  75. cidc_api/models/pydantic/stage1/__init__.py +56 -0
  76. cidc_api/models/pydantic/stage1/additional_treatment.py +23 -0
  77. cidc_api/models/pydantic/stage1/adverse_event.py +127 -0
  78. cidc_api/models/pydantic/stage1/baseline_clinical_assessment.py +23 -0
  79. cidc_api/models/pydantic/stage1/comorbidity.py +43 -0
  80. cidc_api/models/pydantic/stage1/consent_group.py +30 -0
  81. cidc_api/models/pydantic/stage1/demographic.py +140 -0
  82. cidc_api/models/pydantic/stage1/disease.py +200 -0
  83. cidc_api/models/pydantic/stage1/exposure.py +38 -0
  84. cidc_api/models/pydantic/stage1/gvhd_diagnosis_acute.py +33 -0
  85. cidc_api/models/pydantic/stage1/gvhd_diagnosis_chronic.py +32 -0
  86. cidc_api/models/pydantic/stage1/gvhd_organ_acute.py +22 -0
  87. cidc_api/models/pydantic/stage1/gvhd_organ_chronic.py +23 -0
  88. cidc_api/models/pydantic/stage1/medical_history.py +43 -0
  89. cidc_api/models/pydantic/stage1/other_malignancy.py +55 -0
  90. cidc_api/models/pydantic/stage1/participant.py +63 -0
  91. cidc_api/models/pydantic/stage1/prior_treatment.py +45 -0
  92. cidc_api/models/pydantic/stage1/radiotherapy_dose.py +92 -0
  93. cidc_api/models/pydantic/stage1/response.py +84 -0
  94. cidc_api/models/pydantic/stage1/response_by_system.py +220 -0
  95. cidc_api/models/pydantic/stage1/specimen.py +31 -0
  96. cidc_api/models/pydantic/stage1/stem_cell_transplant.py +35 -0
  97. cidc_api/models/pydantic/stage1/surgery.py +57 -0
  98. cidc_api/models/pydantic/stage1/therapy_agent_dose.py +80 -0
  99. cidc_api/models/pydantic/stage1/treatment.py +64 -0
  100. cidc_api/models/pydantic/stage1/trial.py +45 -0
  101. cidc_api/models/pydantic/stage2/additional_treatment.py +2 -4
  102. cidc_api/models/pydantic/stage2/administrative_person.py +1 -1
  103. cidc_api/models/pydantic/stage2/administrative_role_assignment.py +2 -2
  104. cidc_api/models/pydantic/stage2/adverse_event.py +1 -1
  105. cidc_api/models/pydantic/stage2/arm.py +2 -2
  106. cidc_api/models/pydantic/stage2/baseline_clinical_assessment.py +1 -1
  107. cidc_api/models/pydantic/stage2/cohort.py +1 -1
  108. cidc_api/models/pydantic/stage2/comorbidity.py +1 -1
  109. cidc_api/models/pydantic/stage2/consent_group.py +2 -2
  110. cidc_api/models/pydantic/stage2/contact.py +1 -1
  111. cidc_api/models/pydantic/stage2/demographic.py +1 -1
  112. cidc_api/models/pydantic/stage2/disease.py +1 -1
  113. cidc_api/models/pydantic/stage2/exposure.py +1 -1
  114. cidc_api/models/pydantic/stage2/file.py +2 -2
  115. cidc_api/models/pydantic/stage2/gvhd_diagnosis_acute.py +1 -1
  116. cidc_api/models/pydantic/stage2/gvhd_diagnosis_chronic.py +1 -1
  117. cidc_api/models/pydantic/stage2/gvhd_organ_acute.py +1 -1
  118. cidc_api/models/pydantic/stage2/gvhd_organ_chronic.py +1 -1
  119. cidc_api/models/pydantic/stage2/institution.py +1 -1
  120. cidc_api/models/pydantic/stage2/medical_history.py +1 -1
  121. cidc_api/models/pydantic/stage2/other_clinical_endpoint.py +1 -1
  122. cidc_api/models/pydantic/stage2/other_malignancy.py +1 -1
  123. cidc_api/models/pydantic/stage2/participant.py +6 -3
  124. cidc_api/models/pydantic/stage2/prior_treatment.py +6 -15
  125. cidc_api/models/pydantic/stage2/publication.py +2 -2
  126. cidc_api/models/pydantic/stage2/radiotherapy_dose.py +1 -1
  127. cidc_api/models/pydantic/stage2/response.py +2 -2
  128. cidc_api/models/pydantic/stage2/response_by_system.py +1 -1
  129. cidc_api/models/pydantic/stage2/shipment.py +2 -2
  130. cidc_api/models/pydantic/stage2/shipment_specimen.py +1 -1
  131. cidc_api/models/pydantic/stage2/specimen.py +6 -3
  132. cidc_api/models/pydantic/stage2/stem_cell_transplant.py +2 -2
  133. cidc_api/models/pydantic/stage2/surgery.py +1 -1
  134. cidc_api/models/pydantic/stage2/therapy_agent_dose.py +1 -1
  135. cidc_api/models/pydantic/stage2/treatment.py +1 -1
  136. cidc_api/models/pydantic/stage2/trial.py +8 -10
  137. cidc_api/models/types.py +30 -16
  138. cidc_api/shared/assay_handling.py +68 -0
  139. cidc_api/shared/auth.py +5 -5
  140. cidc_api/shared/file_handling.py +18 -4
  141. cidc_api/shared/gcloud_client.py +96 -16
  142. cidc_api/shared/utils.py +18 -9
  143. cidc_api/telemetry.py +101 -0
  144. {nci_cidc_api_modules-1.2.34.dist-info → nci_cidc_api_modules-1.2.53.dist-info}/METADATA +25 -15
  145. nci_cidc_api_modules-1.2.53.dist-info/RECORD +167 -0
  146. {nci_cidc_api_modules-1.2.34.dist-info → nci_cidc_api_modules-1.2.53.dist-info}/WHEEL +1 -1
  147. {nci_cidc_api_modules-1.2.34.dist-info → nci_cidc_api_modules-1.2.53.dist-info}/top_level.txt +1 -0
  148. cidc_api/models/db/base_orm.py +0 -25
  149. cidc_api/models/pydantic/stage2/base.py +0 -48
  150. nci_cidc_api_modules-1.2.34.dist-info/RECORD +0 -109
  151. {nci_cidc_api_modules-1.2.34.dist-info → nci_cidc_api_modules-1.2.53.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,63 @@
1
+ from cidc_api.models.pydantic.base import forced_validator, forced_validators
2
+
3
+ from cidc_api.models.errors import ValueLocError
4
+ from cidc_api.models.pydantic.base import Base
5
+ from cidc_api.models.types import YNU
6
+ from cidc_api.models.types import OffStudyReason
7
+
8
+
9
+ @forced_validators
10
+ class Participant(Base):
11
+ __data_category__ = "participant"
12
+ __cardinality__ = "one"
13
+
14
+ # The unique internal identifier for the participant
15
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=12220014%20and%20ver_nr=1
16
+ participant_id: str | None = None
17
+
18
+ # The participant identifier assigned by the clinical trial team overseeing the study
19
+ native_participant_id: str | None = None
20
+
21
+ # The globally unique participant identifier assigned by the CIMAC network. e.g. C8P29A7
22
+ cimac_participant_id: str | None = None
23
+
24
+ # The unique identifier for the associated trial that the participant is participating in
25
+ trial_id: str | None = None
26
+
27
+ # The version number of the trial dataset. e.g. "1.0"
28
+ version: str | None = None
29
+
30
+ # Indicates if the individual is no longer actively participating in the clinical trial.
31
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=14834973%20and%20ver_nr=1
32
+ off_study: YNU
33
+
34
+ # An explanation describing why an individual is no longer participating in the clinical trial.
35
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=13362265%20and%20ver_nr=1
36
+ off_study_reason: OffStudyReason | None = None
37
+
38
+ # Additional information if "Other" is selected for off_study_reason. e.g. "Transfer to another study"
39
+ off_study_reason_other: str | None = None
40
+
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:
48
+ raise ValueLocError(
49
+ 'If "off_study" is "Yes" then "off_study_reason" is required.',
50
+ loc="off_study_reason",
51
+ )
52
+
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:
60
+ raise ValueLocError(
61
+ 'If "off_study_reason" is "Other" then "off_study_reason_other" is required.',
62
+ loc="off_study_reason_other",
63
+ )
@@ -0,0 +1,45 @@
1
+ from typing import Self, Annotated, List
2
+
3
+ from pydantic import NonPositiveInt, NegativeInt, model_validator, BeforeValidator
4
+
5
+ from cidc_api.models.pydantic.base import Base
6
+ from cidc_api.models.types import ConditioningRegimenType, StemCellDonorType
7
+
8
+
9
+ class PriorTreatment(Base):
10
+ __data_category__ = "prior_treatment"
11
+ __cardinality__ = "many"
12
+
13
+ # A unique internal identifier for the prior treatment record
14
+ prior_treatment_id: int | None = None
15
+
16
+ # A unique internal identifier for the associated participant record
17
+ participant_id: str | None = None
18
+
19
+ # Number of days from the enrollment date to the first recorded administration or occurrence of
20
+ # the treatment modality.
21
+ prior_treatment_days_to_start: NonPositiveInt | None = None
22
+
23
+ # Number of days from the enrollment date to the last recorded administration or occurrence of
24
+ # the treatment modality.
25
+ prior_treatment_days_to_end: NonPositiveInt | None = None
26
+
27
+ # Specifies the category or kind of prior treatment modality a participant received.
28
+
29
+ # Description of the prior treatment such as its full generic name if it is a type of therapy agent,
30
+ # radiotherapy procedure name and location, or surgical procedure name and location.
31
+ prior_treatment_description: str
32
+
33
+ # Best response from any response assessment system to the prior treatment if available or applicable.
34
+ prior_treatment_best_response: str | None = None
35
+
36
+ # If the prior treatment is "Conditioning therapy" received before a stem cell transplant, specifies what
37
+ # type of conditioning regimen used.
38
+ prior_treatment_conditioning_regimen_type: ConditioningRegimenType | None = None
39
+
40
+ # If prior treatment is "Stem cell transplant", indicates what stem cell donor type used.
41
+ prior_treatment_stem_cell_donor_type: StemCellDonorType | None = None
42
+
43
+ # If prior treatment is "Stem cell transplant", indicates the number of days from enrollment
44
+ # to the prior transplant. This must be a negative number.
45
+ prior_treatment_days_from_transplant_to_treatment_initiation: NegativeInt | None = None
@@ -0,0 +1,92 @@
1
+ from pydantic import NonNegativeInt, NonNegativeFloat
2
+ from cidc_api.models.pydantic.base import forced_validator, forced_validators
3
+
4
+ from cidc_api.models.errors import ValueLocError
5
+ from cidc_api.models.pydantic.base import Base
6
+ from cidc_api.models.types import (
7
+ YNU,
8
+ RadiotherapyProcedure,
9
+ UberonAnatomicalTerm,
10
+ RadiotherapyDoseUnits,
11
+ RadiationExtent,
12
+ )
13
+
14
+
15
+ @forced_validators
16
+ class RadiotherapyDose(Base):
17
+ __data_category__ = "radiotherapy_dose"
18
+ __cardinality__ = "many"
19
+
20
+ # The unique internal identifier for the radiotherapy dose record
21
+ radiotherapy_dose_id: int | None = None
22
+
23
+ # The unique internal identifier for the associated treatment record
24
+ treatment_id: int | None = None
25
+
26
+ # Number of days from enrollment date to the start of the radiotherapy dose.
27
+ days_to_start: NonNegativeInt
28
+
29
+ # Number of days from enrollment date to the end of the radiotherapy dose.
30
+ days_to_end: NonNegativeInt
31
+
32
+ # The term that describes the kind of radiotherapy procedure administered.
33
+ procedure: RadiotherapyProcedure
34
+
35
+ # The Uberon anatomical term for the site of surgery.
36
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=14461856%20and%20ver_nr=1
37
+ anatomical_location: UberonAnatomicalTerm | None = None
38
+
39
+ # Indicates whether the record represents the total dose for a radiotherapy treatment course (which may be either
40
+ # a multi-fractionated or a single-fraction dose).
41
+ is_total_dose: bool
42
+
43
+ # The number of fractions a participant received to deliver the radiation dose.
44
+ number_of_fractions: NonNegativeInt | None = None
45
+
46
+ # The dose amount received by the participant.
47
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=13433490%20and%20ver_nr=1
48
+ received_dose: NonNegativeFloat
49
+
50
+ # Unit of measure for the dose of the radiotherapy to be received by the participant.
51
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=13383458%20and%20ver_nr=1
52
+ received_dose_units: RadiotherapyDoseUnits
53
+
54
+ # The planned dose amount for the participant.
55
+ planned_dose: NonNegativeFloat | None = None
56
+
57
+ # Unit of measure for the planned total dose of the radiotherapy to be received by the participant.
58
+ planned_dose_units: RadiotherapyDoseUnits | None = None
59
+
60
+ # Indicates if the radiotherapy dose was changed, missed, or delayed.
61
+ dose_changes_delays: YNU
62
+
63
+ # Description of the radiotherapy dose changes, misses, or delays.
64
+ changes_delays_description: str | None = None
65
+
66
+ # The extent of radiation exposure administered to the patient's body during radiation therapy.
67
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=7063755%20and%20ver_nr=1
68
+ radiation_extent: RadiationExtent
69
+
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:
77
+ raise ValueLocError(
78
+ 'If dose_changes_delays is "Yes", please provide changes_delays_description.',
79
+ loc="changes_delays_description",
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:
89
+ raise ValueLocError(
90
+ "If planned_dose is provided, please provide planned_dose_units.",
91
+ loc="planned_dose_units",
92
+ )
@@ -0,0 +1,84 @@
1
+ from pydantic import NonNegativeInt
2
+ from cidc_api.models.pydantic.base import forced_validator, forced_validators
3
+
4
+ from cidc_api.models.errors import ValueLocError
5
+ from cidc_api.models.pydantic.base import Base
6
+ from cidc_api.models.types import SurvivalStatus, YNUNA, CauseOfDeath
7
+
8
+
9
+ @forced_validators
10
+ class Response(Base):
11
+ __data_category__ = "response"
12
+ __cardinality__ = "one"
13
+
14
+ # The unique internal identifier for the response record
15
+ response_id: int | None = None
16
+
17
+ # The unique internal identifier for the associated participant
18
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=12220014%20and%20ver_nr=1
19
+ participant_id: str | None = None
20
+
21
+ # The response to a question that describes a participant's survival status.
22
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=2847330%20and%20ver_nr=1
23
+ survival_status: SurvivalStatus
24
+
25
+ # Number of days from enrollment date to death date.
26
+ overall_survival: NonNegativeInt
27
+
28
+ # Indicator for whether there was an abscopal effect on disease after local therapy.
29
+ abscopal_response: YNUNA | None = None
30
+
31
+ # Indicates if pathological complete response (pCR) occurred.
32
+ pathological_complete_response: YNUNA | None = None
33
+
34
+ # Number of days between enrollment date and date of death, if applicable.
35
+ days_to_death: NonNegativeInt | None = None
36
+
37
+ # The circumstance or condition of greatest rank or importance that results in the death of the participant
38
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=4783274%20and%20ver_nr=1
39
+ cause_of_death: CauseOfDeath | None = None
40
+
41
+ # Indicates whether participant was evaluable for toxicity (adverse events, DLT, etc.) overall.
42
+ evaluable_for_toxicity: bool
43
+
44
+ # Indicates whether participant was evaluable for efficacy (for example, response, PFS, OS, etc.) overall.
45
+ evaluable_for_efficacy: bool
46
+
47
+ # Days from enrollment date to the last time the patient's vital status was verified.
48
+ days_to_last_vital_status: NonNegativeInt | None = None
49
+
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:
57
+ raise ValueLocError(
58
+ 'If survival_status is "Dead" then cause_of_death is required.',
59
+ loc="cause_of_death",
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:
69
+ raise ValueLocError(
70
+ 'If survival_status is "Alive", please leave cause_of_death blank.',
71
+ loc="cause_of_death",
72
+ )
73
+
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:
81
+ raise ValueLocError(
82
+ "If survival_status does not indicate death, please leave days_to_death blank.",
83
+ loc="days_to_death",
84
+ )
@@ -0,0 +1,220 @@
1
+ from typing import Self
2
+
3
+ from pydantic import PositiveInt, NonNegativeInt, model_validator
4
+ from cidc_api.models.pydantic.base import forced_validator, forced_validators
5
+
6
+ from cidc_api.models.errors import ValueLocError
7
+ from cidc_api.models.pydantic.base import Base
8
+ from cidc_api.models.pydantic.stage1.response import Response
9
+ from cidc_api.models.types import ResponseSystem, ResponseSystemVersion, BestOverallResponse, YNUNA
10
+
11
+
12
+ negative_response_values = [
13
+ "Progressive Disease",
14
+ "Stable Disease",
15
+ "immune Unconfirmed Progressive Disease",
16
+ "immune Confirmed Progressive Disease",
17
+ "immune Stable Disease",
18
+ "Not available",
19
+ "Not assessed",
20
+ ]
21
+
22
+
23
+ @forced_validators
24
+ class ResponseBySystem(Base):
25
+ __data_category__ = "response_by_system"
26
+ __cardinality__ = "many"
27
+
28
+ # The unique internal identifier for this ResponseBySystem record
29
+ response_by_system_id: int | None = None
30
+
31
+ # The unique internal identifier for the associated participant
32
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=12220014%20and%20ver_nr=1
33
+ participant_id: str | None = None
34
+
35
+ # The linked parent response for the participant. Used for cross-model validation.
36
+ response: Response | None = None
37
+
38
+ # A standardized method used to evaluate and categorize the participant’s clinical response to treatment based on predefined criteria.
39
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=13381490%20and%20ver_nr=1
40
+ response_system: ResponseSystem
41
+
42
+ # The release version of the clinical assessment system used to evaluate a participant’s response to treatment.
43
+ response_system_version: ResponseSystemVersion
44
+
45
+ # Confirmed best overall response to study treatment by the corresponding response system.
46
+ best_overall_response: BestOverallResponse
47
+
48
+ # Days from first response to progression.
49
+ response_duration: PositiveInt | None = None
50
+
51
+ # The number of days from the start of the treatment to the first signs of disease progression.
52
+ duration_of_stable_disease: NonNegativeInt | None = None
53
+
54
+ # Indicates whether a patient achieved a durable clinical benefit.
55
+ durable_clinical_benefit: bool | None = None
56
+
57
+ # Number of days between enrollment date and the date of first response to trial treatment.
58
+ days_to_first_response: PositiveInt | None = None
59
+
60
+ # Number of days between enrollment date and the date of the best response to trial treatment.
61
+ days_to_best_response: PositiveInt | None = None
62
+
63
+ # Indicates whether a participant's disease progressed.
64
+ progression: YNUNA
65
+
66
+ # Number of days between enrollment date and date of disease progression.
67
+ days_to_disease_progression: PositiveInt | None = None
68
+
69
+ # Indicator to identify whether a patient had a Progression-Free Survival (PFS) event.
70
+ progression_free_survival_event: YNUNA
71
+
72
+ # The number of days from the date the patient was enrolled in the study to the date the patient was last verified to be free of progression.
73
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=5143957%20and%20ver_nr=1
74
+ progression_free_survival: PositiveInt | None = None
75
+
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:
83
+ raise ValueLocError(
84
+ "If best_overall_response does not indicate a positive response, "
85
+ "please leave response_duration blank.",
86
+ loc="response_duration",
87
+ )
88
+
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:
96
+ raise ValueLocError(
97
+ "If best_overall_response does not indicate a positive response, "
98
+ "please leave days_to_first_response blank.",
99
+ loc="days_to_first_response",
100
+ )
101
+
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:
109
+ raise ValueLocError(
110
+ "If best_overall_response does not indicate a positive response, "
111
+ "please leave days_to_best_response blank.",
112
+ loc="days_to_best_response",
113
+ )
114
+
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:
122
+ raise ValueLocError(
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",
126
+ )
127
+
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:
135
+ raise ValueLocError(
136
+ "If progression_free_survival_event is not known, " "please leave progression_free_survival blank.",
137
+ loc="progression_free_survival",
138
+ )
139
+
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):
148
+ raise ValueLocError(
149
+ 'Violate "days_to_best_response" >= days_to_first_response"',
150
+ loc="days_to_best_response",
151
+ )
152
+
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):
161
+ raise ValueLocError(
162
+ 'Violate "days_to_first_response" < "days_to_disease_progression"',
163
+ loc="days_to_first_response",
164
+ )
165
+
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):
174
+ raise ValueLocError(
175
+ 'Violate "days_to_best_response" < "days_to_disease_progression"',
176
+ loc="days_to_best_response",
177
+ )
178
+
179
+ @model_validator(mode="after")
180
+ def validate_days_to_last_vital_status_chronology(self) -> Self:
181
+ if not self.response:
182
+ return self
183
+
184
+ if not self.response.days_to_last_vital_status:
185
+ return self
186
+
187
+ max_value = max(
188
+ self.response.days_to_last_vital_status or 0,
189
+ self.days_to_first_response or 0,
190
+ self.days_to_best_response or 0,
191
+ self.days_to_disease_progression or 0,
192
+ )
193
+ if (self.response.days_to_last_vital_status or 0) != max_value:
194
+ raise ValueLocError(
195
+ '"days_to_last_vital_status" is not the max of all events. Rule: days_to_last_vital_status '
196
+ ">= max(days_to_first_response,days_to_best_response,days_to_disease_progression)",
197
+ loc="days_to_last_vital_status,days_to_first_response,days_to_best_response,days_to_disease_progression",
198
+ )
199
+ return self
200
+
201
+ @model_validator(mode="after")
202
+ def validate_days_to_death_chronology(self) -> Self:
203
+ if not self.response:
204
+ return self
205
+ if not self.response.days_to_death:
206
+ return self
207
+
208
+ max_value = max(
209
+ self.response.days_to_death or 0,
210
+ self.days_to_first_response or 0,
211
+ self.days_to_best_response or 0,
212
+ self.days_to_disease_progression or 0,
213
+ )
214
+ if (self.response.days_to_death or 0) != max_value:
215
+ raise ValueLocError(
216
+ '"days_to_death" is not the max of all events. Rule: days_to_death'
217
+ ">= max(days_to_first_response,days_to_best_response,days_to_disease_progression)",
218
+ loc="days_to_death,days_to_first_response,days_to_best_response,days_to_disease_progression",
219
+ )
220
+ return self
@@ -0,0 +1,31 @@
1
+ from datetime import datetime
2
+
3
+ from cidc_api.models.pydantic.base import Base
4
+ from cidc_api.models.types import UberonAnatomicalTerm
5
+
6
+
7
+ class Specimen(Base):
8
+ __data_category__ = "specimen"
9
+ __cardinality__ = "many"
10
+
11
+ # The unique internal identifier for the specimen record
12
+ specimen_id: int | None = None
13
+
14
+ # The unique internal identifier for the associated participant
15
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=12220014%20and%20ver_nr=1
16
+ participant_id: str | None = None
17
+
18
+ # The unique specimen identifier assigned by the CIMAC-CIDC Network.
19
+ # Formatted as CTTTPPPSS.AA for trial code TTT, participant PPP, sample SS, and aliquot AA.
20
+ cimac_id: str
21
+
22
+ # Categorical description of timepoint at which the sample was taken.
23
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=5899851%20and%20ver_nr=1
24
+ # Note: CIDC doesn't conform to this CDE's PVs
25
+ collection_event_name: str
26
+
27
+ # Days from enrollment date to date specimen was collected.
28
+ days_to_specimen_collection: int
29
+
30
+ # The location within the body from which a specimen was originally obtained as captured in the Uberon anatomical term.
31
+ organ_site_of_collection: UberonAnatomicalTerm
@@ -0,0 +1,35 @@
1
+ from pydantic import NonNegativeInt
2
+ from cidc_api.models.pydantic.base import Base
3
+ from cidc_api.models.types import (
4
+ StemCellDonorType,
5
+ AllogeneicDonorType,
6
+ StemCellSource,
7
+ ConditioningRegimenType,
8
+ )
9
+
10
+
11
+ class StemCellTransplant(Base):
12
+ __data_category__ = "stem_cell_transplant"
13
+ __cardinality__ = "many"
14
+
15
+ # The unique internal identifier for the stem cell transplant record
16
+ stem_cell_transplant_id: int | None = None
17
+
18
+ # The unique internal identifier for the associated Treatment record
19
+ treatment_id: int | None = None
20
+
21
+ # Indicates the stem cell donor type.
22
+ stem_cell_donor_type: StemCellDonorType
23
+
24
+ # If "stem_cell_donor_type" is "Allogeneic", specifies the relationship and
25
+ # compatibility of the donor relative to the receipient
26
+ allogeneic_donor_type: AllogeneicDonorType | None = None
27
+
28
+ # Source of the stem cells used for transplant.
29
+ stem_cell_source: StemCellSource
30
+
31
+ # Days from the enrollment date to the date of the stem cell transplant.
32
+ days_to_transplant: NonNegativeInt
33
+
34
+ # Specifies what type of conditioning regimen was used for the stem cell transplant if applicable.
35
+ conditioning_regimen_type: ConditioningRegimenType | None = None
@@ -0,0 +1,57 @@
1
+ from pydantic import NonNegativeInt
2
+ from cidc_api.models.pydantic.base import forced_validator, forced_validators
3
+
4
+
5
+ from cidc_api.models.errors import ValueLocError
6
+ from cidc_api.models.pydantic.base import Base
7
+ from cidc_api.models.types import SurgicalProcedure, UberonAnatomicalTerm, YNU
8
+
9
+
10
+ @forced_validators
11
+ class Surgery(Base):
12
+ __data_category__ = "surgery"
13
+ __cardinality__ = "many"
14
+
15
+ # The unique internal identifier for the surgery record
16
+ surgery_id: int | None = None
17
+
18
+ # The unique internal identifier for the associated treatment record
19
+ treatment_id: int | None = None
20
+
21
+ # The term that describes the kind of surgical procedure administered.
22
+ procedure: SurgicalProcedure
23
+
24
+ # The name of surgical procedure if the value provided for procedure is "Other, specify".
25
+ procedure_other: str | None = None
26
+
27
+ # Number of days from enrollment date to surgical procedure date.
28
+ days_to_procedure: NonNegativeInt
29
+
30
+ # The Uberon identifier for the location within the body targeted by a procedure that
31
+ # is intended to alter or stop a pathologic process.
32
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=14980609%20and%20ver_nr=1
33
+ anatomical_location: UberonAnatomicalTerm
34
+
35
+ # An indication as to whether the surgical procedure in question was performed with therapeutic intent.
36
+ therapeutic: YNU
37
+
38
+ # A narrative description of any significant findings observed during the surgical procedure in question.
39
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=14918773%20and%20ver_nr=1
40
+ findings: str | None = None
41
+
42
+ # A textual description of evidence for remaining tumor following primary treatment that is only
43
+ # apparent using highly sensitive techniques.
44
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=13362284%20and%20ver_nr=1
45
+ extent_of_residual_disease: str | None = None
46
+
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:
54
+ raise ValueLocError(
55
+ 'If procedure is "Other, specify", please provide procedure_other.',
56
+ loc="procedure_other",
57
+ )