nci-cidc-api-modules 1.2.18__py3-none-any.whl → 1.2.25__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 (89) hide show
  1. cidc_api/models/__init__.py +2 -0
  2. cidc_api/models/data.py +15 -0
  3. cidc_api/models/db/base_orm.py +25 -0
  4. cidc_api/models/db/stage2/__init__.py +78 -0
  5. cidc_api/models/db/stage2/additional_treatment_orm.py +22 -0
  6. cidc_api/models/db/stage2/administrative_person_orm.py +25 -0
  7. cidc_api/models/db/stage2/administrative_role_assignment_orm.py +28 -0
  8. cidc_api/models/db/stage2/adverse_event_orm.py +47 -0
  9. cidc_api/models/db/stage2/arm_orm.py +23 -0
  10. cidc_api/models/db/stage2/baseline_clinical_assessment_orm.py +23 -0
  11. cidc_api/models/db/stage2/cohort_orm.py +23 -0
  12. cidc_api/models/db/stage2/comorbidity_orm.py +24 -0
  13. cidc_api/models/db/stage2/consent_group_orm.py +31 -0
  14. cidc_api/models/db/stage2/contact_orm.py +32 -0
  15. cidc_api/models/db/stage2/demographic_orm.py +44 -0
  16. cidc_api/models/db/stage2/disease_orm.py +53 -0
  17. cidc_api/models/db/stage2/exposure_orm.py +21 -0
  18. cidc_api/models/db/stage2/file_orm.py +38 -0
  19. cidc_api/models/db/stage2/gvhd_diagnosis_acute_orm.py +33 -0
  20. cidc_api/models/db/stage2/gvhd_diagnosis_chronic_orm.py +37 -0
  21. cidc_api/models/db/stage2/gvhd_organ_acute_orm.py +20 -0
  22. cidc_api/models/db/stage2/gvhd_organ_chronic_orm.py +20 -0
  23. cidc_api/models/db/stage2/institution_orm.py +33 -0
  24. cidc_api/models/db/stage2/medical_history_orm.py +29 -0
  25. cidc_api/models/db/stage2/other_clinical_endpoint_orm.py +28 -0
  26. cidc_api/models/db/stage2/other_malignancy_orm.py +30 -0
  27. cidc_api/models/db/stage2/participant_orm.py +79 -0
  28. cidc_api/models/db/stage2/prior_treatment_orm.py +28 -0
  29. cidc_api/models/db/stage2/publication_orm.py +31 -0
  30. cidc_api/models/db/stage2/radiotherapy_dose_orm.py +39 -0
  31. cidc_api/models/db/stage2/response_by_system_orm.py +28 -0
  32. cidc_api/models/db/stage2/response_orm.py +27 -0
  33. cidc_api/models/db/stage2/shipment_orm.py +47 -0
  34. cidc_api/models/db/stage2/shipment_specimen_orm.py +24 -0
  35. cidc_api/models/db/stage2/specimen_orm.py +100 -0
  36. cidc_api/models/db/stage2/stem_cell_transplant_orm.py +25 -0
  37. cidc_api/models/db/stage2/surgery_orm.py +27 -0
  38. cidc_api/models/db/stage2/therapy_agent_dose_orm.py +31 -0
  39. cidc_api/models/db/stage2/treatment_orm.py +39 -0
  40. cidc_api/models/db/stage2/trial_orm.py +60 -0
  41. cidc_api/models/files/facets.py +5 -0
  42. cidc_api/models/migrations.py +12 -39
  43. cidc_api/models/models.py +12 -0
  44. cidc_api/models/pydantic/stage2/__init__.py +78 -0
  45. cidc_api/models/pydantic/stage2/additional_treatment.py +23 -0
  46. cidc_api/models/pydantic/stage2/administrative_person.py +30 -0
  47. cidc_api/models/pydantic/stage2/administrative_role_assignment.py +16 -0
  48. cidc_api/models/pydantic/stage2/adverse_event.py +100 -0
  49. cidc_api/models/pydantic/stage2/arm.py +16 -0
  50. cidc_api/models/pydantic/stage2/base.py +30 -0
  51. cidc_api/models/pydantic/stage2/baseline_clinical_assessment.py +23 -0
  52. cidc_api/models/pydantic/stage2/cohort.py +16 -0
  53. cidc_api/models/pydantic/stage2/comorbidity.py +36 -0
  54. cidc_api/models/pydantic/stage2/consent_group.py +30 -0
  55. cidc_api/models/pydantic/stage2/contact.py +35 -0
  56. cidc_api/models/pydantic/stage2/demographic.py +114 -0
  57. cidc_api/models/pydantic/stage2/disease.py +144 -0
  58. cidc_api/models/pydantic/stage2/exposure.py +32 -0
  59. cidc_api/models/pydantic/stage2/file.py +44 -0
  60. cidc_api/models/pydantic/stage2/gvhd_diagnosis_acute.py +33 -0
  61. cidc_api/models/pydantic/stage2/gvhd_diagnosis_chronic.py +32 -0
  62. cidc_api/models/pydantic/stage2/gvhd_organ_acute.py +22 -0
  63. cidc_api/models/pydantic/stage2/gvhd_organ_chronic.py +23 -0
  64. cidc_api/models/pydantic/stage2/institution.py +10 -0
  65. cidc_api/models/pydantic/stage2/medical_history.py +36 -0
  66. cidc_api/models/pydantic/stage2/other_clinical_endpoint.py +32 -0
  67. cidc_api/models/pydantic/stage2/other_malignancy.py +45 -0
  68. cidc_api/models/pydantic/stage2/participant.py +47 -0
  69. cidc_api/models/pydantic/stage2/prior_treatment.py +52 -0
  70. cidc_api/models/pydantic/stage2/publication.py +37 -0
  71. cidc_api/models/pydantic/stage2/radiotherapy_dose.py +79 -0
  72. cidc_api/models/pydantic/stage2/response.py +71 -0
  73. cidc_api/models/pydantic/stage2/response_by_system.py +109 -0
  74. cidc_api/models/pydantic/stage2/shipment.py +48 -0
  75. cidc_api/models/pydantic/stage2/shipment_specimen.py +15 -0
  76. cidc_api/models/pydantic/stage2/specimen.py +211 -0
  77. cidc_api/models/pydantic/stage2/stem_cell_transplant.py +35 -0
  78. cidc_api/models/pydantic/stage2/surgery.py +49 -0
  79. cidc_api/models/pydantic/stage2/therapy_agent_dose.py +67 -0
  80. cidc_api/models/pydantic/stage2/treatment.py +50 -0
  81. cidc_api/models/pydantic/stage2/trial.py +85 -0
  82. cidc_api/models/types.py +1439 -0
  83. cidc_api/shared/utils.py +4 -1
  84. {nci_cidc_api_modules-1.2.18.dist-info → nci_cidc_api_modules-1.2.25.dist-info}/METADATA +6 -4
  85. nci_cidc_api_modules-1.2.25.dist-info/RECORD +104 -0
  86. nci_cidc_api_modules-1.2.18.dist-info/RECORD +0 -26
  87. {nci_cidc_api_modules-1.2.18.dist-info → nci_cidc_api_modules-1.2.25.dist-info}/WHEEL +0 -0
  88. {nci_cidc_api_modules-1.2.18.dist-info → nci_cidc_api_modules-1.2.25.dist-info}/licenses/LICENSE +0 -0
  89. {nci_cidc_api_modules-1.2.18.dist-info → nci_cidc_api_modules-1.2.25.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,39 @@
1
+ from typing import List, Optional
2
+
3
+ from sqlalchemy import ForeignKey
4
+ from sqlalchemy.orm import Mapped, mapped_column, relationship
5
+
6
+ from cidc_api.models.db.base_orm import BaseORM
7
+ from cidc_api.models.types import YNU, OffTreatmentReason
8
+
9
+
10
+ class TreatmentORM(BaseORM):
11
+ __tablename__ = "treatment"
12
+ __repr_attrs__ = ["treatment_id", "participant_id", "treatment_description"]
13
+ __table_args__ = {"schema": "stage2"}
14
+
15
+ treatment_id: Mapped[int] = mapped_column(primary_key=True)
16
+ participant_id: Mapped[int] = mapped_column(ForeignKey("stage2.participant.participant_id", ondelete="CASCADE"))
17
+ arm_id: Mapped[Optional[int]] = mapped_column(ForeignKey("stage2.arm.arm_id", ondelete="CASCADE"))
18
+ cohort_id: Mapped[Optional[int]] = mapped_column(ForeignKey("stage2.cohort.cohort_id", ondelete="CASCADE"))
19
+
20
+ treatment_description: Mapped[str]
21
+ off_treatment: Mapped[YNU]
22
+ off_treatment_reason: Mapped[Optional[OffTreatmentReason]]
23
+ off_treatment_reason_other: Mapped[Optional[str]]
24
+
25
+ participant: Mapped["ParticipantORM"] = relationship(back_populates="treatments", cascade="all, delete")
26
+ arm: Mapped[Optional["ArmORM"]] = relationship(cascade="all, delete")
27
+ cohort: Mapped[Optional["CohortORM"]] = relationship(cascade="all, delete")
28
+ adverse_events: Mapped[List["AdverseEventORM"]] = relationship(back_populates="treatment", cascade="all, delete")
29
+
30
+ therapy_agent_doses: Mapped[List["TherapyAgentDoseORM"]] = relationship(
31
+ back_populates="treatment", cascade="all, delete"
32
+ )
33
+ radiotherapy_doses: Mapped[List["RadiotherapyDoseORM"]] = relationship(
34
+ back_populates="treatment", cascade="all, delete"
35
+ )
36
+ surgeries: Mapped[List["SurgeryORM"]] = relationship(back_populates="treatment", cascade="all, delete")
37
+ stem_cell_transplants: Mapped[List["StemCellTransplantORM"]] = relationship(
38
+ back_populates="treatment", cascade="all, delete"
39
+ )
@@ -0,0 +1,60 @@
1
+ from datetime import datetime
2
+ from typing import List, Optional
3
+
4
+ from sqlalchemy import ForeignKey
5
+ from sqlalchemy.orm import Mapped, mapped_column, relationship
6
+ from sqlalchemy.types import JSON
7
+
8
+ from cidc_api.models.db.base_orm import BaseORM
9
+ from cidc_api.models.types import TrialStatus, AssayType, TrialOrganization, TrialFundingAgency
10
+
11
+
12
+ class TrialORM(BaseORM):
13
+ __tablename__ = "trial"
14
+ __repr_attrs__ = ["trial_id", "version"]
15
+ __table_args__ = {"schema": "stage2"}
16
+
17
+ trial_id: Mapped[str] = mapped_column(primary_key=True)
18
+ version: Mapped[str] = mapped_column(primary_key=True)
19
+
20
+ nct_id: Mapped[Optional[str]]
21
+ nci_id: Mapped[Optional[str]]
22
+ trial_name: Mapped[Optional[str]]
23
+ trial_type: Mapped[Optional[str]]
24
+ trial_description: Mapped[Optional[str]]
25
+ trial_organization: Mapped[Optional[TrialOrganization]]
26
+ grant_or_affiliated_network: Mapped[Optional[TrialFundingAgency]]
27
+ trial_status: Mapped[TrialStatus]
28
+ biobank_institution_id: Mapped[Optional[int]]
29
+ justification: Mapped[Optional[str]]
30
+ 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)
36
+ is_liquid_tumor_trial: Mapped[bool]
37
+ dbgap_study_accession: Mapped[Optional[str]]
38
+
39
+ biobank: Mapped["InstitutionORM"] = relationship(back_populates="trial")
40
+ schema: Mapped[Optional["FileORM"]] = relationship(back_populates="trial", viewonly=True)
41
+ administrative_role_assignments: Mapped[List["AdministrativeRoleAssignmentORM"]] = relationship(
42
+ back_populates="trial", cascade="all, delete", passive_deletes=True
43
+ )
44
+ arms: Mapped[List["ArmORM"]] = relationship(back_populates="trial", cascade="all, delete", passive_deletes=True)
45
+ cohorts: Mapped[List["CohortORM"]] = relationship(
46
+ back_populates="trial", cascade="all, delete", passive_deletes=True
47
+ )
48
+ participants: Mapped[List["ParticipantORM"]] = relationship(
49
+ back_populates="trial", cascade="all, delete", passive_deletes=True
50
+ )
51
+ shipments: Mapped[List["ShipmentORM"]] = relationship(
52
+ back_populates="trial", cascade="all, delete", passive_deletes=True
53
+ )
54
+ files: Mapped[List["FileORM"]] = relationship(back_populates="trial", cascade="all, delete", passive_deletes=True)
55
+ publications: Mapped[List["PublicationORM"]] = relationship(
56
+ back_populates="trial", cascade="all, delete", passive_deletes=True
57
+ )
58
+ consent_groups: Mapped[List["ConsentGroupORM"]] = relationship(
59
+ back_populates="trial", cascade="all, delete", passive_deletes=True
60
+ )
@@ -439,6 +439,11 @@ assay_facets: Facets = {
439
439
  "Analysis files for all samples run on the Olink platform in the trial.",
440
440
  ),
441
441
  },
442
+ "Olink HT": {
443
+ "Batch-Level Combined File": FacetConfig(["/olink_ht/batch_level_combined_file.parquet"]),
444
+ "Study-Level Combined File": FacetConfig(["/olink_ht/study_level_combined_file.parquet"]),
445
+ "Npx Run File": FacetConfig(["/olink_ht/npx_run_file.parquet"]),
446
+ },
442
447
  "IHC": {
443
448
  "Images": FacetConfig(["/ihc/ihc_image."]),
444
449
  "Combined Markers": FacetConfig(["csv|ihc marker combined"]),
@@ -91,15 +91,11 @@ def migration_session():
91
91
  session.close()
92
92
 
93
93
 
94
- def run_metadata_migration(
95
- metadata_migration: Callable[[dict], MigrationResult], use_upload_jobs_table: bool
96
- ):
94
+ def run_metadata_migration(metadata_migration: Callable[[dict], MigrationResult], use_upload_jobs_table: bool):
97
95
  """Migrate trial metadata, upload job patches, and downloadable files according to `metadata_migration`"""
98
96
  with migration_session() as (session, task_queue):
99
97
  try:
100
- _run_metadata_migration(
101
- metadata_migration, use_upload_jobs_table, task_queue, session
102
- )
98
+ _run_metadata_migration(metadata_migration, use_upload_jobs_table, task_queue, session)
103
99
  except:
104
100
  traceback.print_exc()
105
101
  raise
@@ -122,9 +118,7 @@ class ManifestUploads(CommonColumns):
122
118
  __tablename__ = "manifest_uploads"
123
119
 
124
120
 
125
- def _select_successful_assay_uploads(
126
- use_upload_jobs_table: bool, session: Session
127
- ) -> List[UploadJobs]:
121
+ def _select_successful_assay_uploads(use_upload_jobs_table: bool, session: Session) -> List[UploadJobs]:
128
122
  if use_upload_jobs_table:
129
123
  return (
130
124
  session.query(UploadJobs)
@@ -133,21 +127,12 @@ def _select_successful_assay_uploads(
133
127
  .all()
134
128
  )
135
129
 
136
- return (
137
- session.query(AssayUploads)
138
- .filter_by(status=UploadJobStatus.MERGE_COMPLETED.value)
139
- .with_for_update()
140
- .all()
141
- )
130
+ return session.query(AssayUploads).filter_by(status=UploadJobStatus.MERGE_COMPLETED.value).with_for_update().all()
142
131
 
143
132
 
144
- def _select_manifest_uploads(
145
- use_upload_jobs_table: bool, session: Session
146
- ) -> List[UploadJobs]:
133
+ def _select_manifest_uploads(use_upload_jobs_table: bool, session: Session) -> List[UploadJobs]:
147
134
  if use_upload_jobs_table:
148
- return (
149
- session.query(UploadJobs).filter_by(multifile=False).with_for_update().all()
150
- )
135
+ return session.query(UploadJobs).filter_by(multifile=False).with_for_update().all()
151
136
 
152
137
  return session.query(ManifestUploads).with_for_update().all()
153
138
 
@@ -188,21 +173,15 @@ def _run_metadata_migration(
188
173
 
189
174
  # Regenerate additional metadata from the migrated clinical trial
190
175
  # metadata object.
191
- print(
192
- f"Regenerating additional metadata for artifact with uuid {artifact['upload_placeholder']}"
193
- )
176
+ print(f"Regenerating additional metadata for artifact with uuid {artifact['upload_placeholder']}")
194
177
  artifact_path = uuid_path_map[artifact["upload_placeholder"]]
195
- df.additional_metadata = get_source(
196
- migration.result, artifact_path, skip_last=True
197
- )[1]
178
+ df.additional_metadata = get_source(migration.result, artifact_path, skip_last=True)[1]
198
179
 
199
180
  # If the GCS URI has changed, rename the blob
200
181
  # makes call to bucket.rename_blob
201
182
  new_gcs_uri = artifact["object_url"]
202
183
  if old_gcs_uri != new_gcs_uri:
203
- print(
204
- f"Encountered GCS data bucket artifact URI to update: {old_gcs_uri}"
205
- )
184
+ print(f"Encountered GCS data bucket artifact URI to update: {old_gcs_uri}")
206
185
  renamer = PieceOfWork(
207
186
  partial(
208
187
  rename_gcs_blob,
@@ -220,9 +199,7 @@ def _run_metadata_migration(
220
199
  gcs_tasks.schedule(renamer)
221
200
 
222
201
  # Migrate all assay upload successes
223
- successful_assay_uploads = _select_successful_assay_uploads(
224
- use_upload_jobs_table, session
225
- )
202
+ successful_assay_uploads = _select_successful_assay_uploads(use_upload_jobs_table, session)
226
203
  for upload in successful_assay_uploads:
227
204
  print(f"Running metadata migration for assay upload: {upload.id}")
228
205
  if use_upload_jobs_table:
@@ -248,9 +225,7 @@ def _run_metadata_migration(
248
225
  if old_target_uri in migration.file_updates:
249
226
  new_target_uri = migration.file_updates[old_target_uri]["object_url"]
250
227
  if old_target_uri != new_target_uri:
251
- print(
252
- f"Encountered GCS upload bucket artifact URI to update: {old_upload_uri}"
253
- )
228
+ print(f"Encountered GCS upload bucket artifact URI to update: {old_upload_uri}")
254
229
  new_upload_uri = "/".join([new_target_uri, upload_timestamp])
255
230
  renamer = PieceOfWork(
256
231
  partial(
@@ -325,7 +300,5 @@ def republish_artifact_uploads():
325
300
  with migration_session() as (session, _):
326
301
  files = session.query(DownloadableFiles).all()
327
302
  for f in files:
328
- print(
329
- f"Publishing to 'artifact_upload' topic for downloadable file with in bucket url {f.object_url}"
330
- )
303
+ print(f"Publishing to 'artifact_upload' topic for downloadable file with in bucket url {f.object_url}")
331
304
  publish_artifact_upload(f.object_url)
cidc_api/models/models.py CHANGED
@@ -3415,6 +3415,15 @@ class PreprocessedFiles(CommonColumns):
3415
3415
 
3416
3416
  return query.filter(cls.job_id.is_(None))
3417
3417
 
3418
+ @with_default_session
3419
+ def category_description(self, session: Session):
3420
+ category = (
3421
+ session.query(JobFileCategories)
3422
+ .filter(JobFileCategories.job_id == self.job_id, JobFileCategories.category == self.file_category)
3423
+ .first()
3424
+ )
3425
+ return category.description if category else None
3426
+
3418
3427
 
3419
3428
  INGESTION_JOB_STATUSES = [
3420
3429
  "DRAFT",
@@ -3546,6 +3555,7 @@ class JobFileCategories(CommonColumns):
3546
3555
  )
3547
3556
 
3548
3557
  category = Column(String)
3558
+ description = Column(String)
3549
3559
  job_id = Column(Integer, nullable=False)
3550
3560
  type = Column(Enum("required", "optional", name="type"), nullable=False)
3551
3561
  is_custom = Column(Boolean, nullable=False, default=False, server_default="false")
@@ -3556,6 +3566,7 @@ class JobFileCategories(CommonColumns):
3556
3566
  category: str,
3557
3567
  job_id: int,
3558
3568
  type: str,
3569
+ description: str = None,
3559
3570
  is_custom: bool = False,
3560
3571
  session: Session = None,
3561
3572
  ):
@@ -3563,6 +3574,7 @@ class JobFileCategories(CommonColumns):
3563
3574
  category=category,
3564
3575
  job_id=job_id,
3565
3576
  type=type,
3577
+ description=description,
3566
3578
  is_custom=is_custom,
3567
3579
  )
3568
3580
  new_category.insert(session=session)
@@ -0,0 +1,78 @@
1
+ from .additional_treatment import AdditionalTreatment
2
+ from .administrative_person import AdministrativePerson
3
+ from .administrative_role_assignment import AdministrativeRoleAssignment
4
+ from .adverse_event import AdverseEvent
5
+ from .arm import Arm
6
+ from .baseline_clinical_assessment import BaselineClinicalAssessment
7
+ from .cohort import Cohort
8
+ from .comorbidity import Comorbidity
9
+ from .consent_group import ConsentGroup
10
+ from .contact import Contact
11
+ from .demographic import Demographic
12
+ from .disease import Disease
13
+ from .exposure import Exposure
14
+ from .file import File
15
+ from .gvhd_diagnosis_acute import GVHDDiagnosisAcute
16
+ from .gvhd_diagnosis_chronic import GVHDDiagnosisChronic
17
+ from .gvhd_organ_acute import GVHDOrganAcute
18
+ from .gvhd_organ_chronic import GVHDOrganChronic
19
+ from .institution import Institution
20
+ from .medical_history import MedicalHistory
21
+ from .other_clinical_endpoint import OtherClinicalEndpoint
22
+ from .other_malignancy import OtherMalignancy
23
+ from .participant import Participant
24
+ from .prior_treatment import PriorTreatment
25
+ from .publication import Publication
26
+ from .radiotherapy_dose import RadiotherapyDose
27
+ from .response import Response
28
+ from .response_by_system import ResponseBySystem
29
+ from .shipment import Shipment
30
+ from .shipment_specimen import ShipmentSpecimen
31
+ from .specimen import Specimen
32
+ from .stem_cell_transplant import StemCellTransplant
33
+ from .surgery import Surgery
34
+ from .therapy_agent_dose import TherapyAgentDose
35
+ from .treatment import Treatment
36
+ from .trial import Trial
37
+
38
+
39
+ __all__ = [
40
+ "AdditionalTreatment",
41
+ "AdministrativePerson",
42
+ "AdministrativeRoleAssignment",
43
+ "AdverseEvent",
44
+ "Arm",
45
+ "BaselineClinicalAssessment",
46
+ "Cohort",
47
+ "Comorbidity",
48
+ "ConsentGroup",
49
+ "Contact",
50
+ "Demographic",
51
+ "Disease",
52
+ "Exposure",
53
+ "File",
54
+ "GVHDDiagnosisAcute",
55
+ "GVHDOrganAcute",
56
+ "GVHDDiagnosisChronic",
57
+ "GVHDOrganChronic",
58
+ "Institution",
59
+ "MedicalHistory",
60
+ "OtherClinicalEndpoint",
61
+ "OtherMalignancy",
62
+ "Participant",
63
+ "PriorTreatment",
64
+ "Publication",
65
+ "RadiotherapyDose",
66
+ "Response",
67
+ "ResponseBySystem",
68
+ "Shipment",
69
+ "ShipmentSpecimen",
70
+ "Specimen",
71
+ "StemCellTransplant",
72
+ "Surgery",
73
+ "TherapyAgentDose",
74
+ "Treatment",
75
+ "Trial",
76
+ ]
77
+
78
+ all_models = [globals()[cls_name] for cls_name in __all__]
@@ -0,0 +1,23 @@
1
+ from pydantic import NonNegativeInt
2
+ from .base import Base
3
+
4
+
5
+ class AdditionalTreatment(Base):
6
+ __data_category__ = "additional_treatment"
7
+ __cardinality__ = "many"
8
+
9
+ # The unique internal identifier for the AdditionalTreatment record
10
+ additional_treatment_id: int | None = None
11
+
12
+ # The unique internal identifier for the associated Participant record
13
+ participant_id: int | None = None
14
+
15
+ # Number of days from the enrollment date to the first recorded administration or occurrence of the treatment modality.
16
+ days_to_start: NonNegativeInt | None = None
17
+
18
+ # Number of days from the enrollment date to the last recorded administration or occurrence of the treatment modality.
19
+ days_to_end: NonNegativeInt | None = None
20
+
21
+ # Description of the prior treatment such as its full generic name if it is a type of therapy agent, radiotherapy procedure
22
+ # name and location, or surgical procedure name and location.
23
+ description: str
@@ -0,0 +1,30 @@
1
+ from .base import Base
2
+
3
+
4
+ class AdministrativePerson(Base):
5
+
6
+ # The unique internal identifier for the administrative person
7
+ administrative_person_id: int | None = None
8
+
9
+ # The internal identifier for the Institution the administrative person belongs to
10
+ institution_id: int | None = None
11
+
12
+ # The word or group of words indicating a person's first (personal or given) name, e.g. "John"
13
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=2179589%20and%20ver_nr=2
14
+ first_name: str
15
+
16
+ # The word or group of worlds indicating a person's middle name, e.g. "Alan"
17
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=2179590%20and%20ver_nr=2
18
+ middle_name: str | None = None
19
+
20
+ # The means of identifying an individual by using a word or group of words indicating a person's last (family) name, e.g. "Smith"
21
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=2179591%20and%20ver_nr=2
22
+ last_name: str
23
+
24
+ # The string of characters that represents the electronic mail address of a person.
25
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=2517550%20and%20ver_nr=1
26
+ email: str | None = None
27
+
28
+ # The string of digits that represent a telephone number that can be used to contact the person.
29
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=2179593%20and%20ver_nr=3
30
+ phone_number: str | None = None
@@ -0,0 +1,16 @@
1
+ from .base import Base
2
+ from cidc_api.models.types import AdministrativeRole
3
+
4
+
5
+ class AdministrativeRoleAssignment(Base):
6
+ # The unique identifier for the associated trial
7
+ trial_id: int | None = None
8
+
9
+ # The version number of the trial dataset
10
+ version: str | None = None
11
+
12
+ # The unique identifier for the associated administrative person
13
+ administrative_person_id: int
14
+
15
+ # The role the administrative_person is performing for the associated trial
16
+ administrative_role: AdministrativeRole
@@ -0,0 +1,100 @@
1
+ from typing import Self
2
+
3
+ from pydantic import NonNegativeInt, model_validator
4
+
5
+ from .base import Base
6
+ from cidc_api.reference.ctcae import is_ctcae_other_term
7
+ from cidc_api.models.types import (
8
+ CTCAEEventTerm,
9
+ CTCAEEventCode,
10
+ SeverityGradeSystem,
11
+ SeverityGradeSystemVersion,
12
+ SeverityGrade,
13
+ SystemOrganClass,
14
+ AttributionCause,
15
+ AttributionLikelihood,
16
+ YNU,
17
+ )
18
+
19
+
20
+ class AdverseEvent(Base):
21
+ __data_category__ = "adverse_event"
22
+ __cardinality__ = "many"
23
+
24
+ # The unique internal identifier of the adverse event
25
+ adverse_event_id: int | None = None
26
+
27
+ # The unique internal identifier of the associated participant
28
+ participant_id: int | None = None
29
+
30
+ # The unique internal identifier of the attributed treatment, if any
31
+ treatment_id: int | None = None
32
+
33
+ # Text that represents the Common Terminology Criteria for Adverse Events low level term name for an adverse event.
34
+ event_term: CTCAEEventTerm | None = None
35
+
36
+ # A MedDRA code mapped to a CTCAE low level name for an adverse event.
37
+ event_code: CTCAEEventCode | None = None
38
+
39
+ # System used to define and report adverse event severity grade.
40
+ severity_grade_system: SeverityGradeSystem
41
+
42
+ # The version of the adverse event grading system.
43
+ severity_grade_system_version: SeverityGradeSystemVersion
44
+
45
+ # Numerical grade indicating the severity of an adverse event.
46
+ severity_grade: SeverityGrade
47
+
48
+ # A brief description that sufficiently details the event.
49
+ event_other_specify: str | None = None
50
+
51
+ # The highest level of the MedDRA hierarchy, distinguished by anatomical or physiological system, etiology (disease origin) or purpose.
52
+ system_organ_class: SystemOrganClass | None = None
53
+
54
+ # Indicator to identify whether a participant exited the study prematurely due to the adverse event being described.
55
+ discontinuation_due_to_event: bool
56
+
57
+ # Days from enrollment date to date of onset of the adverse event.
58
+ days_to_onset_of_event: NonNegativeInt
59
+
60
+ # Days from enrollment date to date of resolution of the adverse event.
61
+ days_to_resolution_of_event: NonNegativeInt | None = None
62
+
63
+ # Indicates whether the adverse event was a serious adverse event (SAE).
64
+ serious_adverse_event: YNU
65
+
66
+ # Indicates whether the adverse event was a dose-limiting toxicity (DLT).
67
+ dose_limiting_toxicity: YNU
68
+
69
+ # Indicates if the adverse was attributable to the protocol as a whole or to an individual treatment.
70
+ attribution_cause: AttributionCause
71
+
72
+ # The code that indicates whether the adverse event is related to the treatment/intervention.
73
+ attribution_likelihood: AttributionLikelihood
74
+
75
+ # The individual therapy (therapy agent, radiotherapy, surgery, stem cell transplant) in the treatment that is attributed to the adverse event.
76
+ individual_therapy: str | None = None
77
+
78
+ @model_validator(mode="after")
79
+ def validate_term_and_code_cr(self) -> Self:
80
+ if not self.event_term and not self.event_code:
81
+ raise ValueError("Please provide event_term or event_code or both")
82
+ return self
83
+
84
+ @model_validator(mode="after")
85
+ def validate_event_other_specify_cr(self) -> Self:
86
+ if (
87
+ self.severity_grade_system == "CTCAE"
88
+ and is_ctcae_other_term(self.event_term)
89
+ and not self.event_other_specify
90
+ ):
91
+ raise ValueError(
92
+ 'If severity_grade_system is "CTCAE" and the event_code or event_term are of type "Other, specify", please provide event_other_specify'
93
+ )
94
+ return self
95
+
96
+ @model_validator(mode="after")
97
+ def validate_system_organ_class_cr(self) -> Self:
98
+ if self.event_other_specify and not self.system_organ_class:
99
+ raise ValueError("If event_other_specify is provided, please provide system_organ_class.")
100
+ return self
@@ -0,0 +1,16 @@
1
+ from .base import Base
2
+
3
+
4
+ class Arm(Base):
5
+ # The unique internal identifier for the arm
6
+ arm_id: int | None = None
7
+
8
+ # The unique identifier for the associated trial
9
+ trial_id: int | None = None
10
+
11
+ # The version number of the trial dataset
12
+ version: str | None = None
13
+
14
+ # The name of the arm, e.g. "Arm A1"
15
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=2001626%20and%20ver_nr=3
16
+ name: str
@@ -0,0 +1,30 @@
1
+ from pydantic import BaseModel, ConfigDict
2
+ from contextlib import contextmanager
3
+
4
+ import copy
5
+
6
+
7
+ class Base(BaseModel):
8
+
9
+ model_config = ConfigDict(validate_assignment=True, from_attributes=True)
10
+
11
+ # Validates the new state and updates the object if valid
12
+ def update(self, **kwargs):
13
+ self.model_validate(self.__dict__ | kwargs)
14
+ self.__dict__.update(kwargs)
15
+
16
+ # CM that delays validation until all fields are applied.
17
+ # If validation fails the original fields are restored and the ValidationError is raised.
18
+ @contextmanager
19
+ def delay_validation(self):
20
+ original_dict = copy.deepcopy(self.__dict__)
21
+ self.model_config["validate_assignment"] = False
22
+ try:
23
+ yield
24
+ finally:
25
+ self.model_config["validate_assignment"] = True
26
+ try:
27
+ self.model_validate(self.__dict__)
28
+ except:
29
+ self.__dict__.update(original_dict)
30
+ raise
@@ -0,0 +1,23 @@
1
+ from .base import Base
2
+ from cidc_api.models.types import ECOGScore, KarnofskyScore
3
+
4
+
5
+ class BaselineClinicalAssessment(Base):
6
+ __data_category__ = "baseline_clinical_assessment"
7
+ __cardinality__ = "one"
8
+
9
+ # A unique internal identifier for the baseline clinical assessment
10
+ baseline_clinical_assessment_id: int | None = None
11
+
12
+ # The unique identifier for the associated participant
13
+ participant_id: int | None = None
14
+
15
+ # The numerical score that represents the functional capabilities of a participant at the
16
+ # enrollment date using the Eastern Cooperative Oncology Group Performance Status assessment.
17
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=88%20and%20ver_nr=5.1
18
+ ecog_score: ECOGScore | None = None
19
+
20
+ # Score from the Karnofsky Performance status scale, representing the functional capabilities of a participant
21
+ # at the enrollment date.
22
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=2003853%20and%20ver_nr=4.2
23
+ karnofsky_score: KarnofskyScore | None = None
@@ -0,0 +1,16 @@
1
+ from .base import Base
2
+
3
+
4
+ class Cohort(Base):
5
+ # A unique internal identifier for the cohort
6
+ cohort_id: int | None = None
7
+
8
+ # The unique identifier for the associated trial
9
+ trial_id: str | None = None
10
+
11
+ # The version number of the trial dataset
12
+ version: str | None = None
13
+
14
+ # The name of the cohort, e.g. "Cohort A"
15
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=7979585%20and%20ver_nr=1
16
+ name: str
@@ -0,0 +1,36 @@
1
+ from typing import Self
2
+
3
+ from pydantic import model_validator
4
+
5
+ from .base import Base
6
+ from cidc_api.models.types import ICD10CMCode, ICD10CMTerm
7
+
8
+
9
+ class Comorbidity(Base):
10
+ __data_category__ = "comorbidity"
11
+ __cardinality__ = "many"
12
+
13
+ # The unique internal identifier for the comorbidity record
14
+ comorbidity_id: int | None = None
15
+
16
+ # The unique internal identifier for the associated MedicalHistory record
17
+ medical_history_id: int | None = None
18
+
19
+ # The diagnosis, in humans, as captured in the tenth version of the
20
+ # International Classification of Disease (ICD-10-CM, the disease code subset of ICD-10).
21
+ comorbidity_code: ICD10CMCode | None = None
22
+
23
+ # The words from the tenth version of the International Classification of Disease (ICD-10-CM,
24
+ # the disease subset of ICD-10) used to identify the diagnosis in humans.
25
+ comorbidity_term: ICD10CMTerm | None = None
26
+
27
+ # A descriptive string that names or briefly describes the comorbidity.
28
+ comorbidity_other: str | None = None
29
+
30
+ @model_validator(mode="after")
31
+ def validate_code_or_term_or_other_cr(self) -> Self:
32
+ if not self.comorbidity_code and not self.comorbidity_term and not self.comorbidity_other:
33
+ raise ValueError(
34
+ 'Please provide at least one of "comorbidity_code", "comorbidity_term" or "comorbidity_other".'
35
+ )
36
+ return self
@@ -0,0 +1,30 @@
1
+ from pydantic import NonNegativeInt
2
+
3
+ from .base import Base
4
+
5
+
6
+ class ConsentGroup(Base):
7
+ __data_category__ = "consent_group"
8
+ __cardinality__ = "one"
9
+
10
+ # The unique internal identifier for the consent group record
11
+ consent_group_id: int | None = None
12
+
13
+ # The unique internal identifier for the associated Trial record
14
+ trial_id: int | None = None
15
+
16
+ # The version number of the trial dataset
17
+ version: str | None = None
18
+
19
+ # An abbreviated name for the consent group
20
+ consent_group_short_name: str
21
+
22
+ # The words or acronym which describe a set of study participants
23
+ # who have signed the same consent agreement and that will be included in the dbGaP repository.
24
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=14534329%20and%20ver_nr=1.00
25
+ consent_group_name: str
26
+
27
+ # A numeral or string of numerals used to identify the set of study participants who have signed the same consent
28
+ # agreement and that will be included in the dbGaP repository.
29
+ # CDE: https://cadsr.cancer.gov/onedata/dmdirect/NIH/NCI/CO/CDEDD?filter=CDEDD.ITEM_ID=14534330%20and%20ver_nr=1.00
30
+ consent_group_number: NonNegativeInt