nci-cidc-api-modules 1.2.31__tar.gz → 1.2.39__tar.gz

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 (125) hide show
  1. {nci_cidc_api_modules-1.2.31/nci_cidc_api_modules.egg-info → nci_cidc_api_modules-1.2.39}/PKG-INFO +22 -13
  2. nci_cidc_api_modules-1.2.39/cidc_api/__init__.py +1 -0
  3. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/additional_treatment_orm.py +3 -3
  4. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/demographic_orm.py +6 -4
  5. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/other_malignancy_orm.py +6 -6
  6. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/prior_treatment_orm.py +11 -10
  7. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/response_by_system_orm.py +1 -0
  8. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/response_orm.py +2 -2
  9. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/trial_orm.py +19 -16
  10. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/models.py +140 -9
  11. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/additional_treatment.py +3 -3
  12. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/base.py +5 -1
  13. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/demographic.py +11 -3
  14. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/other_malignancy.py +11 -7
  15. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/prior_treatment.py +11 -11
  16. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/response.py +3 -9
  17. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/response_by_system.py +4 -1
  18. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/trial.py +12 -2
  19. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/types.py +6 -0
  20. nci_cidc_api_modules-1.2.39/cidc_api/shared/assay_handling.py +68 -0
  21. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/shared/auth.py +5 -5
  22. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/shared/file_handling.py +3 -0
  23. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/shared/gcloud_client.py +27 -5
  24. nci_cidc_api_modules-1.2.39/cidc_api/shared/utils.py +19 -0
  25. nci_cidc_api_modules-1.2.39/cidc_api/telemetry.py +101 -0
  26. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39/nci_cidc_api_modules.egg-info}/PKG-INFO +22 -13
  27. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/nci_cidc_api_modules.egg-info/SOURCES.txt +3 -0
  28. nci_cidc_api_modules-1.2.39/nci_cidc_api_modules.egg-info/requires.txt +35 -0
  29. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/pyproject.toml +3 -0
  30. nci_cidc_api_modules-1.2.39/requirements.modules.txt +43 -0
  31. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/setup.py +3 -1
  32. nci_cidc_api_modules-1.2.31/cidc_api/shared/utils.py +0 -11
  33. nci_cidc_api_modules-1.2.31/nci_cidc_api_modules.egg-info/requires.txt +0 -26
  34. nci_cidc_api_modules-1.2.31/requirements.modules.txt +0 -28
  35. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/LICENSE +0 -0
  36. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/MANIFEST.in +0 -0
  37. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/README.md +0 -0
  38. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/config/__init__.py +0 -0
  39. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/config/db.py +0 -0
  40. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/config/logging.py +0 -0
  41. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/config/secrets.py +0 -0
  42. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/config/settings.py +0 -0
  43. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/__init__.py +0 -0
  44. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/data.py +0 -0
  45. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/base_orm.py +0 -0
  46. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/__init__.py +0 -0
  47. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/administrative_person_orm.py +0 -0
  48. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/administrative_role_assignment_orm.py +0 -0
  49. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/adverse_event_orm.py +0 -0
  50. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/arm_orm.py +0 -0
  51. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/baseline_clinical_assessment_orm.py +0 -0
  52. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/cohort_orm.py +0 -0
  53. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/comorbidity_orm.py +0 -0
  54. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/consent_group_orm.py +0 -0
  55. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/contact_orm.py +0 -0
  56. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/disease_orm.py +0 -0
  57. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/exposure_orm.py +0 -0
  58. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/file_orm.py +0 -0
  59. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/gvhd_diagnosis_acute_orm.py +0 -0
  60. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/gvhd_diagnosis_chronic_orm.py +0 -0
  61. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/gvhd_organ_acute_orm.py +0 -0
  62. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/gvhd_organ_chronic_orm.py +0 -0
  63. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/institution_orm.py +0 -0
  64. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/medical_history_orm.py +0 -0
  65. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/other_clinical_endpoint_orm.py +0 -0
  66. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/participant_orm.py +0 -0
  67. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/publication_orm.py +0 -0
  68. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/radiotherapy_dose_orm.py +0 -0
  69. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/shipment_orm.py +0 -0
  70. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/shipment_specimen_orm.py +0 -0
  71. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/specimen_orm.py +0 -0
  72. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/stem_cell_transplant_orm.py +0 -0
  73. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/surgery_orm.py +0 -0
  74. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/therapy_agent_dose_orm.py +0 -0
  75. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/db/stage2/treatment_orm.py +0 -0
  76. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/files/__init__.py +0 -0
  77. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/files/details.py +0 -0
  78. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/files/facets.py +0 -0
  79. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/migrations.py +0 -0
  80. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/__init__.py +0 -0
  81. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/administrative_person.py +0 -0
  82. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/administrative_role_assignment.py +0 -0
  83. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/adverse_event.py +0 -0
  84. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/arm.py +0 -0
  85. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/baseline_clinical_assessment.py +0 -0
  86. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/cohort.py +0 -0
  87. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/comorbidity.py +0 -0
  88. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/consent_group.py +0 -0
  89. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/contact.py +0 -0
  90. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/disease.py +0 -0
  91. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/exposure.py +0 -0
  92. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/file.py +0 -0
  93. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/gvhd_diagnosis_acute.py +0 -0
  94. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/gvhd_diagnosis_chronic.py +0 -0
  95. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/gvhd_organ_acute.py +0 -0
  96. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/gvhd_organ_chronic.py +0 -0
  97. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/institution.py +0 -0
  98. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/medical_history.py +0 -0
  99. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/other_clinical_endpoint.py +0 -0
  100. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/participant.py +0 -0
  101. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/publication.py +0 -0
  102. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/radiotherapy_dose.py +0 -0
  103. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/shipment.py +0 -0
  104. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/shipment_specimen.py +0 -0
  105. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/specimen.py +0 -0
  106. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/stem_cell_transplant.py +0 -0
  107. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/surgery.py +0 -0
  108. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/therapy_agent_dose.py +0 -0
  109. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/pydantic/stage2/treatment.py +0 -0
  110. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/models/schemas.py +0 -0
  111. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/reference/ctcae.py +0 -0
  112. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/reference/gvhd.py +0 -0
  113. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/reference/icd10cm.py +0 -0
  114. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/reference/icdo3.py +0 -0
  115. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/reference/uberon.py +0 -0
  116. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/shared/__init__.py +0 -0
  117. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/shared/email_layout.html +0 -0
  118. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/shared/emails.py +0 -0
  119. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/shared/jose.py +0 -0
  120. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/cidc_api/shared/rest_utils.py +0 -0
  121. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/nci_cidc_api_modules.egg-info/dependency_links.txt +0 -0
  122. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/nci_cidc_api_modules.egg-info/not-zip-safe +0 -0
  123. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/nci_cidc_api_modules.egg-info/top_level.txt +0 -0
  124. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/setup.cfg +0 -0
  125. {nci_cidc_api_modules-1.2.31 → nci_cidc_api_modules-1.2.39}/tests/test_api.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nci_cidc_api_modules
3
- Version: 1.2.31
3
+ Version: 1.2.39
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
@@ -8,30 +8,39 @@ Requires-Python: >=3.13
8
8
  Description-Content-Type: text/markdown
9
9
  License-File: LICENSE
10
10
  Requires-Dist: certifi>=2025.11.12
11
- Requires-Dist: cloud-sql-python-connector[pg8000]>=1.18.5
11
+ Requires-Dist: cloud-sql-python-connector[pg8000]>=1.19.0
12
12
  Requires-Dist: flask>=3.1.2
13
13
  Requires-Dist: flask-migrate>=4.1.0
14
14
  Requires-Dist: flask-sqlalchemy>=3.1.1
15
15
  Requires-Dist: flask-talisman>=0.7.0
16
- Requires-Dist: google-auth==2.43.0
17
- Requires-Dist: google-api-python-client>=2.185.0
18
- Requires-Dist: google-cloud-bigquery>=3.38.0
19
- Requires-Dist: google-cloud-pubsub>=2.33.0
20
- Requires-Dist: google-cloud-secret-manager>=2.25.0
21
- Requires-Dist: google-cloud-storage>=3.6.0
16
+ Requires-Dist: google-auth==2.45.0
17
+ Requires-Dist: google-api-python-client>=2.187.0
18
+ Requires-Dist: google-cloud-bigquery>=3.39.0
19
+ Requires-Dist: google-cloud-pubsub>=2.34.0
20
+ Requires-Dist: google-cloud-secret-manager>=2.26.0
21
+ Requires-Dist: google-cloud-storage>=3.7.0
22
22
  Requires-Dist: jinja2>=3.1.6
23
- Requires-Dist: marshmallow>=4.1.0
23
+ Requires-Dist: joserfc>=1.6.0
24
+ Requires-Dist: marshmallow>=4.1.2
24
25
  Requires-Dist: marshmallow-sqlalchemy>=1.4.2
25
- Requires-Dist: numpy>=2.3.5
26
+ Requires-Dist: numpy>=2.4.0
26
27
  Requires-Dist: packaging>=25.0
27
28
  Requires-Dist: pandas>=2.3.3
28
29
  Requires-Dist: pyarrow>=22.0.0
29
- Requires-Dist: pydantic~=2.12.4
30
+ Requires-Dist: pydantic~=2.12.5
30
31
  Requires-Dist: python-dotenv>=1.2.1
31
32
  Requires-Dist: requests>=2.32.5
32
- Requires-Dist: sqlalchemy>=2.0.44
33
+ Requires-Dist: sqlalchemy>=2.0.45
33
34
  Requires-Dist: sqlalchemy-mixins~=2.0.5
34
- Requires-Dist: werkzeug>=3.1.3
35
+ Requires-Dist: werkzeug>=3.1.4
36
+ Requires-Dist: opentelemetry-api>=1.39.1
37
+ Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.39.1
38
+ Requires-Dist: opentelemetry-sdk>=1.39.1
39
+ Requires-Dist: opentelemetry-instrumentation-flask>=0.59b0
40
+ Requires-Dist: opentelemetry-instrumentation-requests>=0.59b0
41
+ Requires-Dist: opentelemetry-instrumentation-sqlalchemy>=0.59b0
42
+ Requires-Dist: opentelemetry-exporter-gcp-trace>=1.11.0
43
+ Requires-Dist: opentelemetry-propagator-gcp>=1.11.0
35
44
  Requires-Dist: nci-cidc-schemas==0.28.10
36
45
  Dynamic: description
37
46
  Dynamic: description-content-type
@@ -0,0 +1 @@
1
+ __version__ = "1.2.39"
@@ -16,8 +16,8 @@ class AdditionalTreatmentORM(BaseORM):
16
16
  additional_treatment_id: Mapped[int] = mapped_column(primary_key=True)
17
17
  participant_id: Mapped[int] = mapped_column(ForeignKey("stage2.participant.participant_id", ondelete="CASCADE"))
18
18
 
19
- days_to_start: Mapped[Optional[NonNegativeInt]]
20
- days_to_end: Mapped[Optional[NonNegativeInt]]
21
- description: Mapped[str]
19
+ additional_treatment_days_to_start: Mapped[Optional[NonNegativeInt]]
20
+ additional_treatment_days_to_end: Mapped[Optional[NonNegativeInt]]
21
+ additional_treatment_description: Mapped[str]
22
22
 
23
23
  participant: Mapped["ParticipantORM"] = relationship(back_populates="additional_treatments", cascade="all, delete")
@@ -1,7 +1,9 @@
1
1
  from pydantic import NonNegativeFloat, PositiveFloat, PositiveInt
2
+ from typing import List
2
3
 
3
4
  from sqlalchemy import ForeignKey
4
5
  from sqlalchemy.orm import Mapped, mapped_column, relationship
6
+ from sqlalchemy.types import JSON
5
7
 
6
8
  from cidc_api.models.db.base_orm import BaseORM
7
9
  from cidc_api.models.types import (
@@ -29,15 +31,15 @@ class DemographicORM(BaseORM):
29
31
  age_at_enrollment_units: Mapped[AgeAtEnrollmentUnits | None]
30
32
  age_90_or_over: Mapped[bool]
31
33
  sex: Mapped[Sex]
32
- race: Mapped[Race]
34
+ race: Mapped[List[Race]] = mapped_column(JSON)
33
35
  ethnicity: Mapped[Ethnicity]
34
36
  height: Mapped[PositiveFloat]
35
37
  height_units: Mapped[HeightUnits]
36
38
  weight: Mapped[PositiveFloat]
37
39
  weight_units: Mapped[WeightUnits]
38
- body_mass_index: Mapped[PositiveFloat]
39
- body_surface_area: Mapped[PositiveFloat]
40
- body_surface_area_units: Mapped[BodySurfaceAreaUnits]
40
+ body_mass_index: Mapped[PositiveFloat | None]
41
+ body_surface_area: Mapped[PositiveFloat | None]
42
+ body_surface_area_units: Mapped[BodySurfaceAreaUnits | None]
41
43
  occupation: Mapped[Occupation | None]
42
44
  income: Mapped[NonNegativeFloat | None]
43
45
  highest_level_of_education: Mapped[Education | None]
@@ -19,12 +19,12 @@ class OtherMalignancyORM(BaseORM):
19
19
  ForeignKey("stage2.medical_history.medical_history_id", ondelete="CASCADE")
20
20
  )
21
21
 
22
- primary_disease_site: Mapped[UberonAnatomicalTerm]
23
- morphological_code: Mapped[Optional[ICDO3MorphologicalCode]]
24
- morphological_term: Mapped[Optional[ICDO3MorphologicalTerm]]
25
- malignancy_description: Mapped[Optional[str]]
26
- days_since_diagnosis: Mapped[Optional[NonPositiveInt]]
27
- malignancy_status: Mapped[Optional[MalignancyStatus]]
22
+ other_malignancy_primary_disease_site: Mapped[UberonAnatomicalTerm]
23
+ other_malignancy_morphological_code: Mapped[Optional[ICDO3MorphologicalCode]]
24
+ other_malignancy_morphological_term: Mapped[Optional[ICDO3MorphologicalTerm]]
25
+ other_malignancy_description: Mapped[Optional[str]]
26
+ other_malignancy_days_since_diagnosis: Mapped[Optional[NonPositiveInt]]
27
+ other_malignancy_status: Mapped[Optional[MalignancyStatus]]
28
28
 
29
29
  medical_history: Mapped["MedicalHistoryORM"] = relationship(
30
30
  back_populates="other_malignancies", cascade="all, delete"
@@ -1,8 +1,9 @@
1
- from typing import Optional
1
+ from typing import Optional, List
2
2
 
3
- from pydantic import NonPositiveInt, NonNegativeInt
3
+ from pydantic import NonPositiveInt, NegativeInt
4
4
  from sqlalchemy import ForeignKey
5
5
  from sqlalchemy.orm import Mapped, mapped_column, relationship
6
+ from sqlalchemy.types import JSON
6
7
 
7
8
  from cidc_api.models.db.base_orm import BaseORM
8
9
  from cidc_api.models.types import PriorTreatmentType, ConditioningRegimenType, StemCellDonorType
@@ -17,13 +18,13 @@ class PriorTreatmentORM(BaseORM):
17
18
  prior_treatment_id: Mapped[int] = mapped_column(primary_key=True)
18
19
  participant_id: Mapped[int] = mapped_column(ForeignKey("stage2.participant.participant_id", ondelete="CASCADE"))
19
20
 
20
- days_to_start: Mapped[Optional[NonPositiveInt]]
21
- days_to_end: Mapped[Optional[NonPositiveInt]]
22
- type: Mapped[PriorTreatmentType]
23
- description: Mapped[Optional[str]]
24
- best_response: Mapped[Optional[str]]
25
- conditioning_regimen_type: Mapped[Optional[ConditioningRegimenType]]
26
- stem_cell_donor_type: Mapped[Optional[StemCellDonorType]]
27
- days_from_transplant_to_treatment_initiation: Mapped[Optional[NonNegativeInt]]
21
+ prior_treatment_days_to_start: Mapped[Optional[NonPositiveInt]]
22
+ prior_treatment_days_to_end: Mapped[Optional[NonPositiveInt]]
23
+ prior_treatment_type: Mapped[List[PriorTreatmentType]] = mapped_column(JSON, nullable=False)
24
+ prior_treatment_description: Mapped[Optional[str]]
25
+ prior_treatment_best_response: Mapped[Optional[str]]
26
+ prior_treatment_conditioning_regimen_type: Mapped[Optional[ConditioningRegimenType]]
27
+ prior_treatment_stem_cell_donor_type: Mapped[Optional[StemCellDonorType]]
28
+ prior_treatment_days_to_prior_transplant: Mapped[Optional[NegativeInt]]
28
29
 
29
30
  participant: Mapped["ParticipantORM"] = relationship(back_populates="prior_treatments", cascade="all, delete")
@@ -18,6 +18,7 @@ class ResponseBySystemORM(BaseORM):
18
18
  response_system_version: Mapped[ResponseSystemVersion] = mapped_column(String)
19
19
  best_overall_response: Mapped[BestOverallResponse] = mapped_column(String)
20
20
  response_duration: Mapped[PositiveInt | None]
21
+ duration_of_stable_disease: Mapped[PositiveInt | None]
21
22
  durable_clinical_benefit: Mapped[bool | None]
22
23
  days_to_first_response: Mapped[PositiveInt | None]
23
24
  days_to_best_response: Mapped[PositiveInt | None]
@@ -16,13 +16,13 @@ class ResponseORM(BaseORM):
16
16
  response_id: Mapped[int] = mapped_column(primary_key=True)
17
17
  participant_id: Mapped[int] = mapped_column(ForeignKey("stage2.participant.participant_id", ondelete="CASCADE"))
18
18
  survival_status: Mapped[SurvivalStatus]
19
- overall_survival: Mapped[NonNegativeInt | None]
19
+ overall_survival: Mapped[NonNegativeInt]
20
20
  abscopal_response: Mapped[YNUNA | None]
21
21
  pathological_complete_response: Mapped[YNUNA | None]
22
22
  days_to_death: Mapped[NonNegativeInt | None]
23
23
  cause_of_death: Mapped[CauseOfDeath | None]
24
24
  evaluable_for_toxicity: Mapped[bool]
25
25
  evaluable_for_efficacy: Mapped[bool]
26
- days_to_last_follow_up: Mapped[NonNegativeInt | None]
26
+ days_to_last_vital_status: Mapped[NonNegativeInt | None]
27
27
 
28
28
  participant: Mapped["ParticipantORM"] = relationship(back_populates="response", cascade="all, delete")
@@ -6,7 +6,7 @@ from sqlalchemy.orm import Mapped, mapped_column, relationship
6
6
  from sqlalchemy.types import JSON
7
7
 
8
8
  from cidc_api.models.db.base_orm import BaseORM
9
- from cidc_api.models.types import AssayType, TrialOrganization, TrialFundingAgency
9
+ from cidc_api.models.types import AssayType, TrialOrganization, TrialFundingAgency, AgeGroup
10
10
 
11
11
 
12
12
  class TrialORM(BaseORM):
@@ -18,23 +18,26 @@ class TrialORM(BaseORM):
18
18
  trial_id: Mapped[str] = mapped_column(primary_key=True)
19
19
  version: Mapped[str] = mapped_column(primary_key=True)
20
20
 
21
- nct_id: Mapped[Optional[str]]
22
- nci_id: Mapped[Optional[str]]
23
- trial_name: Mapped[Optional[str]]
24
- trial_type: Mapped[Optional[str]]
25
- trial_description: Mapped[Optional[str]]
26
- trial_organization: Mapped[Optional[TrialOrganization]]
27
- grant_or_affiliated_network: Mapped[Optional[TrialFundingAgency]]
28
- biobank_institution_id: Mapped[Optional[int]]
29
- justification: Mapped[Optional[str]]
21
+ primary_endpoint: Mapped[str | None]
22
+ age_group: Mapped[List[AgeGroup]] = mapped_column(JSON, nullable=True)
23
+ study_population: Mapped[str | None]
24
+ nct_id: Mapped[str | None]
25
+ nci_id: Mapped[str | None]
26
+ trial_name: Mapped[str | None]
27
+ trial_type: Mapped[str | None]
28
+ trial_description: Mapped[str | None]
29
+ trial_organization: Mapped[TrialOrganization | None]
30
+ grant_or_affiliated_network: Mapped[TrialFundingAgency | None]
31
+ biobank_institution_id: Mapped[int | None]
32
+ justification: Mapped[str | None]
30
33
  dates_of_conduct_start: Mapped[datetime]
31
- dates_of_conduct_end: Mapped[Optional[datetime]]
32
- schema_file_id: Mapped[Optional[int]]
33
- biomarker_plan: Mapped[Optional[str]]
34
- data_sharing_plan: Mapped[Optional[str]]
35
- expected_assays: Mapped[Optional[List[AssayType]]] = mapped_column(JSON, nullable=True)
34
+ dates_of_conduct_end: Mapped[datetime | None]
35
+ schema_file_id: Mapped[int | None]
36
+ biomarker_plan: Mapped[str | None]
37
+ data_sharing_plan: Mapped[str | None]
38
+ expected_assays: Mapped[List[AssayType]] = mapped_column(JSON, nullable=True)
36
39
  is_liquid_tumor_trial: Mapped[bool]
37
- dbgap_study_accession: Mapped[Optional[str]]
40
+ dbgap_study_accession: Mapped[str | None]
38
41
 
39
42
  biobank: Mapped["InstitutionORM"] = relationship(back_populates="trial")
40
43
  schema: Mapped[Optional["FileORM"]] = relationship(back_populates="trial", viewonly=True)
@@ -35,7 +35,8 @@ __all__ = [
35
35
  "ADMIN_FILE_CATEGORIES",
36
36
  "FINAL_JOB_STATUS",
37
37
  "INGESTION_JOB_STATUSES",
38
- "INGESTION_JOB_COLORS",
38
+ "ASSAY_JOB_COLORS",
39
+ "CLINICAL_JOB_COLORS",
39
40
  ]
40
41
 
41
42
  import hashlib
@@ -3436,7 +3437,7 @@ INGESTION_JOB_STATUSES = [
3436
3437
  ]
3437
3438
 
3438
3439
  # Business decision to pass hex codes from the backend though that should be done by the front end...
3439
- INGESTION_JOB_COLORS = {
3440
+ CLINICAL_JOB_COLORS = {
3440
3441
  "DRAFT": "",
3441
3442
  "INITIAL SUBMISSION": "#ACCAD7",
3442
3443
  "VALIDATION REVIEW": "#DABE90",
@@ -3444,6 +3445,13 @@ INGESTION_JOB_COLORS = {
3444
3445
  "INGESTION": "#8FCEC7",
3445
3446
  "PUBLISHED": "#90D9E6",
3446
3447
  }
3448
+ ASSAY_JOB_COLORS = {
3449
+ "INITIAL SUBMISSION": "#43807E",
3450
+ "VALIDATION REVIEW": "#906F3F",
3451
+ "REVISION SUBMISSION": "#95358A",
3452
+ "INGESTION": "#542C88",
3453
+ "PUBLISHED": "#1C81A0",
3454
+ }
3447
3455
  # TODO If have "CANCELLED" concept or other final status, add here
3448
3456
  FINAL_JOB_STATUS = ["PUBLISHED"]
3449
3457
  TRIAL_APPENDIX_A_CELL_THAT_ENDS_THE_HEADER = "Data Category"
@@ -3465,11 +3473,44 @@ class IngestionJobs(CommonColumns):
3465
3473
  pending = Column(Boolean, nullable=False, default=False)
3466
3474
  start_date = Column(DateTime, nullable=True)
3467
3475
  error_status = Column(String, nullable=True)
3476
+ job_type = Column(String, nullable=False, default="clinical")
3477
+ assay_type = Column(String, nullable=True)
3478
+ batch_id = Column(String, nullable=True)
3479
+ submission_id = Column(String, nullable=True)
3480
+ intake_path = Column(String, nullable=True)
3481
+ uploader_email = Column(String, nullable=True)
3468
3482
 
3469
3483
  @staticmethod
3470
3484
  @with_default_session
3471
- def create(trial_id: str, status: str, version: int, pending: Boolean = False, session: Session = None):
3472
- new_job = IngestionJobs(trial_id=trial_id, status=status, version=version, pending=pending)
3485
+ def create(
3486
+ trial_id: str,
3487
+ status: str,
3488
+ version: int,
3489
+ error_status: str = None,
3490
+ pending: Boolean = False,
3491
+ job_type: str = "clinical",
3492
+ assay_type: str = None,
3493
+ batch_id: str = None,
3494
+ submission_id: str = None,
3495
+ intake_path: str = None,
3496
+ start_date: datetime = None,
3497
+ uploader_email: str = None,
3498
+ session: Session = None,
3499
+ ):
3500
+ new_job = IngestionJobs(
3501
+ trial_id=trial_id,
3502
+ status=status,
3503
+ error_status=error_status,
3504
+ version=version,
3505
+ pending=pending,
3506
+ job_type=job_type,
3507
+ assay_type=assay_type,
3508
+ batch_id=batch_id,
3509
+ submission_id=submission_id,
3510
+ intake_path=intake_path,
3511
+ start_date=start_date,
3512
+ uploader_email=uploader_email,
3513
+ )
3473
3514
  new_job.insert(session=session)
3474
3515
  return new_job
3475
3516
 
@@ -3494,29 +3535,43 @@ class IngestionJobs(CommonColumns):
3494
3535
 
3495
3536
  @classmethod
3496
3537
  @with_default_session
3497
- def get_jobs_by_trial(cls, trial_id: str, session: Session = None) -> list["IngestionJobs"]:
3498
- return session.query(cls).filter(cls.trial_id == trial_id).order_by(cls.version.desc()).all()
3538
+ def get_jobs_by_trial(
3539
+ cls, trial_id: str, job_type: str = "clinical", session: Session = None
3540
+ ) -> list["IngestionJobs"]:
3541
+ return (
3542
+ session.query(cls)
3543
+ .filter(cls.trial_id == trial_id, cls.job_type == job_type)
3544
+ .order_by(cls.version.desc())
3545
+ .all()
3546
+ )
3499
3547
 
3500
3548
  @classmethod
3501
3549
  @with_default_session
3502
- def get_open_job_by_trial(cls, trial_id: str, session: Session = None) -> Optional["IngestionJobs"]:
3550
+ def get_open_job_by_trial(
3551
+ cls, trial_id: str, job_type: str = "clinical", session: Session = None
3552
+ ) -> Optional["IngestionJobs"]:
3503
3553
  """Return the open job for a given trial if it exists."""
3504
3554
  return (
3505
3555
  session.query(cls)
3506
3556
  .filter(
3507
3557
  cls.trial_id == trial_id,
3558
+ cls.job_type == job_type,
3508
3559
  cls.status.notin_(FINAL_JOB_STATUS),
3509
3560
  )
3510
3561
  .order_by(cls._created.desc())
3511
3562
  .first()
3512
3563
  )
3513
3564
 
3565
+ @classmethod
3566
+ def get_jobs_for_user(cls, user: Users, job_type: str = None) -> list["IngestionJobs"]:
3567
+ return cls.get_assay_jobs_for_user(user) if job_type == "assay" else cls.get_clinical_jobs_for_user(user)
3568
+
3514
3569
  @classmethod
3515
3570
  @with_default_session
3516
- def get_open_jobs_for_user(cls, user: Users, session: Session = None) -> list["IngestionJobs"]:
3571
+ def get_clinical_jobs_for_user(cls, user: Users, session: Session = None) -> list["IngestionJobs"]:
3517
3572
  if user.role not in [CIDCRole.ADMIN.value, CIDCRole.CLINICAL_TRIAL_USER.value]:
3518
3573
  return []
3519
- job_query = session.query(cls).filter(cls.status.notin_(["DRAFT"]))
3574
+ job_query = session.query(cls).filter(cls.status.notin_(["DRAFT"]), cls.job_type == "clinical")
3520
3575
  if (
3521
3576
  user.role != CIDCRole.ADMIN.value
3522
3577
  and not session.query(Permissions)
@@ -3539,6 +3594,81 @@ class IngestionJobs(CommonColumns):
3539
3594
  job_query = job_query.filter(cls.trial_id.in_(map(lambda x: x.trial_id, authorized_trials)))
3540
3595
  return job_query.order_by(cls._created.desc()).all()
3541
3596
 
3597
+ @classmethod
3598
+ @with_default_session
3599
+ def get_assay_jobs_for_user(cls, user: Users, session: Session = None) -> list["IngestionJobs"]:
3600
+ # TODO allow more than just Admin role and get authorized trials based on permissions
3601
+ if user.role not in [CIDCRole.ADMIN.value]:
3602
+ return []
3603
+ return session.query(cls).filter(cls.job_type == "assay").order_by(cls._created.desc()).all()
3604
+
3605
+ @classmethod
3606
+ @with_default_session
3607
+ def get_unique_assay_job(
3608
+ cls,
3609
+ trial_id: str,
3610
+ assay_type: str,
3611
+ batch_id: str,
3612
+ session: Session = None,
3613
+ ) -> Optional["IngestionJobs"]:
3614
+ """Look for unique assay job with matching trial_id/assay_type/batch_id combination."""
3615
+ return (
3616
+ session.query(cls)
3617
+ .filter(
3618
+ cls.job_type == "assay",
3619
+ cls.trial_id == trial_id,
3620
+ cls.assay_type == assay_type,
3621
+ cls.batch_id == batch_id,
3622
+ )
3623
+ .first()
3624
+ )
3625
+
3626
+ @classmethod
3627
+ @with_default_session
3628
+ def next_assay_submission_id(cls, trial_id: str, assay_type: str, session: Session = None) -> str:
3629
+ """
3630
+ Generate the next CIDC Submission ID for an assay job.
3631
+
3632
+ Format:
3633
+ <trial_id>-<assay_type>-<yyyymmdd> (first submission of the day)
3634
+ <trial_id>-<assay_type>-<yyyymmdd>-<#> (subsequent submissions on same day)
3635
+
3636
+ Uses only the most recent matching submission_id to determine the next suffix.
3637
+ """
3638
+ today_str = datetime.now().strftime("%Y%m%d")
3639
+ base_submission_id = f"{trial_id}-{assay_type}-{today_str}"
3640
+
3641
+ # Get the most recent submission_id matching this prefix
3642
+ latest = (
3643
+ session.query(cls.submission_id)
3644
+ .filter(
3645
+ cls.trial_id == trial_id,
3646
+ cls.assay_type == assay_type,
3647
+ cls.submission_id.like(f"{base_submission_id}%"),
3648
+ )
3649
+ .order_by(cls._created.desc())
3650
+ .first()
3651
+ )
3652
+
3653
+ # No existing submission for this prefix -> start at 1
3654
+ if not latest or not latest[0]:
3655
+ return base_submission_id
3656
+
3657
+ last_id = latest[0]
3658
+ # Case 1: the latest is exactly the prefix (i.e., first submission today)
3659
+ if last_id == base_submission_id:
3660
+ return f"{base_submission_id}-2"
3661
+
3662
+ # Case 2: latest already has a suffix
3663
+ try:
3664
+ _, last_suffix = last_id.rsplit("-", 1)
3665
+ n = int(last_suffix)
3666
+ return f"{base_submission_id}-{n + 1}"
3667
+ except Exception as e:
3668
+ # If malformed, restart numbering for safety
3669
+ logger.error("Unexpected error parsing Submission ID in next_assay_submission_id: %s", e)
3670
+ return f"{base_submission_id}-2"
3671
+
3542
3672
 
3543
3673
  class JobFileCategories(CommonColumns):
3544
3674
  __tablename__ = "job_file_categories"
@@ -3613,6 +3743,7 @@ class CategoryDataElements(CommonColumns):
3613
3743
  name = Column(String, nullable=False)
3614
3744
  is_custom = Column(Boolean, nullable=False, default=False, server_default="false")
3615
3745
  element_type = Column(String, nullable=False)
3746
+ data_type = Column(String, nullable=True)
3616
3747
  cardinality = Column(String, nullable=True)
3617
3748
 
3618
3749
  @classmethod
@@ -15,11 +15,11 @@ class AdditionalTreatment(Base):
15
15
  )
16
16
 
17
17
  # Number of days from the enrollment date to the first recorded administration or occurrence of the treatment modality.
18
- days_to_start: NonNegativeInt | None = None
18
+ additional_treatment_days_to_start: NonNegativeInt | None = None
19
19
 
20
20
  # Number of days from the enrollment date to the last recorded administration or occurrence of the treatment modality.
21
- days_to_end: NonNegativeInt | None = None
21
+ additional_treatment_days_to_end: NonNegativeInt | None = None
22
22
 
23
23
  # Description of the prior treatment such as its full generic name if it is a type of therapy agent, radiotherapy procedure
24
24
  # name and location, or surgical procedure name and location.
25
- description: str
25
+ additional_treatment_description: str
@@ -6,7 +6,11 @@ import copy
6
6
 
7
7
  class Base(BaseModel):
8
8
 
9
- model_config = ConfigDict(validate_assignment=True, from_attributes=True)
9
+ model_config = ConfigDict(
10
+ validate_assignment=True,
11
+ from_attributes=True,
12
+ # extra="forbid" # TODO: enable me one stage1 models are implemented
13
+ )
10
14
 
11
15
  # Validates the new state and updates the object if valid
12
16
  def update(self, **kwargs):
@@ -68,15 +68,15 @@ class Demographic(Base):
68
68
 
69
69
  # The body mass index of the participant at the enrollment date.
70
70
  # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=2006410%20and%20ver_nr=3
71
- body_mass_index: PositiveFloat
71
+ body_mass_index: PositiveFloat | None = None
72
72
 
73
73
  # A decimal number that represents the measure of the 2-dimensional extent of the body surface (i.e., the skin) of the participant at the enrollment date.
74
74
  # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=6606197%20and%20ver_nr=1
75
- body_surface_area: PositiveFloat
75
+ body_surface_area: PositiveFloat | None = None
76
76
 
77
77
  # Unit of measurement for body surface area of the participant at the enrollment date. e.g. "m2"
78
78
  # https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=15114329%20and%20ver_nr=1
79
- body_surface_area_units: BodySurfaceAreaUnits
79
+ body_surface_area_units: BodySurfaceAreaUnits | None = None
80
80
 
81
81
  # The occupation/job category of the participant. e.g. "Manager"
82
82
  # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=6617540%20and%20ver_nr=1
@@ -113,3 +113,11 @@ class Demographic(Base):
113
113
  if age_in_years >= 90:
114
114
  raise ValueError('"age_at_enrollment" cannot represent a value greater than 90 years of age.')
115
115
  return self
116
+
117
+ @model_validator(mode="after")
118
+ def validate_body_surface_area_units_cr(self) -> Self:
119
+ if self.body_surface_area and not self.body_surface_area_units:
120
+ raise ValueError(
121
+ 'If "body_surface_area" is provided then "body_surface_area_units_other" must also be provided.'
122
+ )
123
+ return self
@@ -17,28 +17,32 @@ class OtherMalignancy(Base):
17
17
  medical_history_id: int | None = None
18
18
 
19
19
  # The location within the body from where the prior malignancy originated as captured in the Uberon anatomical term.
20
- primary_disease_site: UberonAnatomicalTerm
20
+ other_malignancy_primary_disease_site: UberonAnatomicalTerm
21
21
 
22
22
  # The ICD-O-3 code which identifies the specific appearance of cells and tissues (normal and abnormal) used
23
23
  # to define the presence and nature of disease.
24
- morphological_code: ICDO3MorphologicalCode | None = None
24
+ other_malignancy_morphological_code: ICDO3MorphologicalCode | None = None
25
25
 
26
26
  # The ICD-O-3 textual label which identifies the specific appearance of cells and tissues (normal and abnormal) used
27
27
  # to define the presence and nature of disease.
28
- morphological_term: ICDO3MorphologicalTerm | None = None
28
+ other_malignancy_morphological_term: ICDO3MorphologicalTerm | None = None
29
29
 
30
30
  # Description of the cancer type as recorded in the trial.
31
- malignancy_description: str | None = None
31
+ other_malignancy_description: str | None = None
32
32
 
33
33
  # Number of days since original diagnosis from the enrollment date. This may be a negative number.
34
- days_since_diagnosis: NonPositiveInt | None = None
34
+ other_malignancy_days_since_diagnosis: NonPositiveInt | None = None
35
35
 
36
36
  # Indicates the participant’s current clinical state regarding the cancer diagnosis.
37
- malignancy_status: MalignancyStatus | None = None
37
+ other_malignancy_status: MalignancyStatus | None = None
38
38
 
39
39
  @model_validator(mode="after")
40
40
  def validate_code_or_term_or_description_cr(self) -> Self:
41
- if not self.morphological_code and not self.morphological_term and not self.malignancy_description:
41
+ if (
42
+ not self.other_malignancy_morphological_code
43
+ and not self.other_malignancy_morphological_term
44
+ and not self.other_malignancy_description
45
+ ):
42
46
  raise ValueError(
43
47
  'Please provide at least one of "morphological_code", "morphological_term" or "malignancy_description".'
44
48
  )
@@ -1,6 +1,6 @@
1
- from typing import Self
1
+ from typing import Self, Annotated, List
2
2
 
3
- from pydantic import NonPositiveInt, NonNegativeInt, model_validator
3
+ from pydantic import NonPositiveInt, NegativeInt, model_validator, BeforeValidator
4
4
 
5
5
  from .base import Base
6
6
  from cidc_api.models.types import PriorTreatmentType, ConditioningRegimenType, StemCellDonorType
@@ -18,35 +18,35 @@ class PriorTreatment(Base):
18
18
 
19
19
  # Number of days from the enrollment date to the first recorded administration or occurrence of
20
20
  # the treatment modality.
21
- days_to_start: NonPositiveInt | None = None
21
+ prior_treatment_days_to_start: NonPositiveInt | None = None
22
22
 
23
23
  # Number of days from the enrollment date to the last recorded administration or occurrence of
24
24
  # the treatment modality.
25
- days_to_end: NonPositiveInt | None = None
25
+ prior_treatment_days_to_end: NonPositiveInt | None = None
26
26
 
27
27
  # Specifies the category or kind of prior treatment modality a participant received.
28
- type: PriorTreatmentType
28
+ prior_treatment_type: Annotated[List[PriorTreatmentType], BeforeValidator(Base.split_list)]
29
29
 
30
30
  # Description of the prior treatment such as its full generic name if it is a type of therapy agent,
31
31
  # radiotherapy procedure name and location, or surgical procedure name and location.
32
- description: str | None = None
32
+ prior_treatment_description: str | None = None
33
33
 
34
34
  # Best response from any response assessment system to the prior treatment if available or applicable.
35
- best_response: str | None = None
35
+ prior_treatment_best_response: str | None = None
36
36
 
37
37
  # If the prior treatment is "Conditioning therapy" received before a stem cell transplant, specifies what
38
38
  # type of conditioning regimen used.
39
- conditioning_regimen_type: ConditioningRegimenType | None = None
39
+ prior_treatment_conditioning_regimen_type: ConditioningRegimenType | None = None
40
40
 
41
41
  # If prior treatment is "Stem cell transplant", indicates what stem cell donor type used.
42
- stem_cell_donor_type: StemCellDonorType | None = None
42
+ prior_treatment_stem_cell_donor_type: StemCellDonorType | None = None
43
43
 
44
44
  # If prior treatment is "Stem cell transplant", indicates the number of days from the transplant
45
45
  # date to the start of the current treatment.
46
- days_from_transplant_to_treatment_initiation: NonNegativeInt | None = None
46
+ prior_treatment_days_to_prior_transplant: NegativeInt | None = None
47
47
 
48
48
  @model_validator(mode="after")
49
49
  def validate_description_cr(self) -> Self:
50
- if self.type == "Other therapy" and not self.description:
50
+ if "Other therapy" in self.prior_treatment_type and not self.prior_treatment_description:
51
51
  raise ValueError('If type is "Other therapy", please provide description.')
52
52
  return self
@@ -22,7 +22,7 @@ class Response(Base):
22
22
  survival_status: SurvivalStatus
23
23
 
24
24
  # Number of days from enrollment date to death date.
25
- overall_survival: NonNegativeInt | None = None
25
+ overall_survival: NonNegativeInt
26
26
 
27
27
  # Indicator for whether there was an abscopal effect on disease after local therapy.
28
28
  abscopal_response: YNUNA | None = None
@@ -43,14 +43,8 @@ class Response(Base):
43
43
  # Indicates whether participant was evaluable for efficacy (for example, response, PFS, OS, etc.) overall.
44
44
  evaluable_for_efficacy: bool
45
45
 
46
- # Days from enrollment date to the last time patient had follow-up.
47
- days_to_last_follow_up: NonNegativeInt | None = None
48
-
49
- @model_validator(mode="after")
50
- def validate_overall_survival_cr(self) -> Self:
51
- if self.survival_status != "Unknown" and not self.overall_survival:
52
- raise ValueError('If survival_status is not "Unknown" then overall_survival is required.')
53
- return self
46
+ # Days from enrollment date to the last time the patient's vital status was verified.
47
+ days_to_last_vital_status: NonNegativeInt | None = None
54
48
 
55
49
  @model_validator(mode="after")
56
50
  def validate_cause_of_death_cr(self) -> Self: