nci-cidc-api-modules 1.2.29__py3-none-any.whl → 1.2.45__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cidc_api/__init__.py +1 -0
- cidc_api/config/db.py +21 -1
- cidc_api/config/settings.py +1 -0
- cidc_api/models/__init__.py +0 -2
- cidc_api/models/data.py +17 -4
- cidc_api/models/db/stage1/__init__.py +56 -0
- cidc_api/models/db/stage1/additional_treatment_orm.py +22 -0
- cidc_api/models/db/stage1/adverse_event_orm.py +46 -0
- cidc_api/models/db/stage1/base_orm.py +7 -0
- cidc_api/models/db/stage1/baseline_clinical_assessment_orm.py +22 -0
- cidc_api/models/db/stage1/comorbidity_orm.py +23 -0
- cidc_api/models/db/stage1/consent_group_orm.py +32 -0
- cidc_api/models/db/stage1/demographic_orm.py +47 -0
- cidc_api/models/db/stage1/disease_orm.py +52 -0
- cidc_api/models/db/stage1/exposure_orm.py +22 -0
- cidc_api/models/db/stage1/gvhd_diagnosis_acute_orm.py +34 -0
- cidc_api/models/db/stage1/gvhd_diagnosis_chronic_orm.py +36 -0
- cidc_api/models/db/stage1/gvhd_organ_acute_orm.py +21 -0
- cidc_api/models/db/stage1/gvhd_organ_chronic_orm.py +21 -0
- cidc_api/models/db/stage1/medical_history_orm.py +30 -0
- cidc_api/models/db/stage1/other_malignancy_orm.py +29 -0
- cidc_api/models/db/stage1/participant_orm.py +77 -0
- cidc_api/models/db/stage1/prior_treatment_orm.py +29 -0
- cidc_api/models/db/stage1/radiotherapy_dose_orm.py +39 -0
- cidc_api/models/db/stage1/response_by_system_orm.py +30 -0
- cidc_api/models/db/stage1/response_orm.py +28 -0
- cidc_api/models/db/stage1/specimen_orm.py +46 -0
- cidc_api/models/db/stage1/stem_cell_transplant_orm.py +25 -0
- cidc_api/models/db/stage1/surgery_orm.py +27 -0
- cidc_api/models/db/stage1/therapy_agent_dose_orm.py +31 -0
- cidc_api/models/db/stage1/treatment_orm.py +38 -0
- cidc_api/models/db/stage1/trial_orm.py +35 -0
- cidc_api/models/db/stage2/additional_treatment_orm.py +8 -8
- cidc_api/models/db/stage2/administrative_person_orm.py +4 -4
- cidc_api/models/db/stage2/administrative_role_assignment_orm.py +4 -4
- cidc_api/models/db/stage2/adverse_event_orm.py +12 -13
- cidc_api/models/db/stage2/arm_orm.py +3 -3
- cidc_api/models/db/stage2/base_orm.py +7 -0
- cidc_api/models/db/stage2/baseline_clinical_assessment_orm.py +6 -7
- cidc_api/models/db/stage2/cohort_orm.py +3 -3
- cidc_api/models/db/stage2/comorbidity_orm.py +7 -8
- cidc_api/models/db/stage2/consent_group_orm.py +5 -4
- cidc_api/models/db/stage2/contact_orm.py +16 -20
- cidc_api/models/db/stage2/demographic_orm.py +11 -8
- cidc_api/models/db/stage2/disease_orm.py +13 -14
- cidc_api/models/db/stage2/exposure_orm.py +5 -4
- cidc_api/models/db/stage2/file_orm.py +6 -9
- cidc_api/models/db/stage2/gvhd_diagnosis_acute_orm.py +5 -4
- cidc_api/models/db/stage2/gvhd_diagnosis_chronic_orm.py +5 -6
- cidc_api/models/db/stage2/gvhd_organ_acute_orm.py +4 -3
- cidc_api/models/db/stage2/gvhd_organ_chronic_orm.py +4 -3
- cidc_api/models/db/stage2/institution_orm.py +7 -7
- cidc_api/models/db/stage2/medical_history_orm.py +10 -9
- cidc_api/models/db/stage2/other_clinical_endpoint_orm.py +8 -12
- cidc_api/models/db/stage2/other_malignancy_orm.py +10 -11
- cidc_api/models/db/stage2/participant_orm.py +28 -28
- cidc_api/models/db/stage2/prior_treatment_orm.py +15 -14
- cidc_api/models/db/stage2/publication_orm.py +9 -11
- cidc_api/models/db/stage2/radiotherapy_dose_orm.py +9 -9
- cidc_api/models/db/stage2/response_by_system_orm.py +5 -3
- cidc_api/models/db/stage2/response_orm.py +6 -5
- cidc_api/models/db/stage2/shipment_orm.py +17 -17
- cidc_api/models/db/stage2/shipment_specimen_orm.py +4 -4
- cidc_api/models/db/stage2/specimen_orm.py +7 -6
- cidc_api/models/db/stage2/stem_cell_transplant_orm.py +7 -7
- cidc_api/models/db/stage2/surgery_orm.py +7 -7
- cidc_api/models/db/stage2/therapy_agent_dose_orm.py +8 -8
- cidc_api/models/db/stage2/treatment_orm.py +16 -15
- cidc_api/models/db/stage2/trial_orm.py +34 -33
- cidc_api/models/files/facets.py +4 -0
- cidc_api/models/models.py +154 -9
- cidc_api/models/pydantic/{stage2/base.py → base.py} +19 -1
- cidc_api/models/pydantic/stage1/__init__.py +56 -0
- cidc_api/models/pydantic/stage1/additional_treatment.py +23 -0
- cidc_api/models/pydantic/stage1/adverse_event.py +100 -0
- cidc_api/models/pydantic/stage1/baseline_clinical_assessment.py +23 -0
- cidc_api/models/pydantic/stage1/comorbidity.py +36 -0
- cidc_api/models/pydantic/stage1/consent_group.py +30 -0
- cidc_api/models/pydantic/stage1/demographic.py +123 -0
- cidc_api/models/pydantic/stage1/disease.py +158 -0
- cidc_api/models/pydantic/stage1/exposure.py +32 -0
- cidc_api/models/pydantic/stage1/gvhd_diagnosis_acute.py +33 -0
- cidc_api/models/pydantic/stage1/gvhd_diagnosis_chronic.py +32 -0
- cidc_api/models/pydantic/stage1/gvhd_organ_acute.py +22 -0
- cidc_api/models/pydantic/stage1/gvhd_organ_chronic.py +23 -0
- cidc_api/models/pydantic/stage1/medical_history.py +36 -0
- cidc_api/models/pydantic/stage1/other_malignancy.py +49 -0
- cidc_api/models/pydantic/stage1/participant.py +51 -0
- cidc_api/models/pydantic/stage1/prior_treatment.py +45 -0
- cidc_api/models/pydantic/stage1/radiotherapy_dose.py +79 -0
- cidc_api/models/pydantic/stage1/response.py +65 -0
- cidc_api/models/pydantic/stage1/response_by_system.py +112 -0
- cidc_api/models/pydantic/stage1/specimen.py +31 -0
- cidc_api/models/pydantic/stage1/stem_cell_transplant.py +35 -0
- cidc_api/models/pydantic/stage1/surgery.py +49 -0
- cidc_api/models/pydantic/stage1/therapy_agent_dose.py +67 -0
- cidc_api/models/pydantic/stage1/treatment.py +50 -0
- cidc_api/models/pydantic/stage1/trial.py +45 -0
- cidc_api/models/pydantic/stage2/additional_treatment.py +5 -5
- cidc_api/models/pydantic/stage2/administrative_person.py +1 -1
- cidc_api/models/pydantic/stage2/administrative_role_assignment.py +2 -2
- cidc_api/models/pydantic/stage2/adverse_event.py +2 -2
- cidc_api/models/pydantic/stage2/arm.py +2 -2
- cidc_api/models/pydantic/stage2/baseline_clinical_assessment.py +2 -2
- cidc_api/models/pydantic/stage2/cohort.py +1 -1
- cidc_api/models/pydantic/stage2/comorbidity.py +1 -1
- cidc_api/models/pydantic/stage2/consent_group.py +2 -2
- cidc_api/models/pydantic/stage2/contact.py +1 -1
- cidc_api/models/pydantic/stage2/demographic.py +27 -18
- cidc_api/models/pydantic/stage2/disease.py +33 -19
- cidc_api/models/pydantic/stage2/exposure.py +3 -3
- cidc_api/models/pydantic/stage2/file.py +2 -2
- cidc_api/models/pydantic/stage2/gvhd_diagnosis_acute.py +2 -2
- cidc_api/models/pydantic/stage2/gvhd_diagnosis_chronic.py +2 -2
- cidc_api/models/pydantic/stage2/gvhd_organ_acute.py +1 -1
- cidc_api/models/pydantic/stage2/gvhd_organ_chronic.py +1 -1
- cidc_api/models/pydantic/stage2/institution.py +1 -1
- cidc_api/models/pydantic/stage2/medical_history.py +2 -2
- cidc_api/models/pydantic/stage2/other_clinical_endpoint.py +1 -1
- cidc_api/models/pydantic/stage2/other_malignancy.py +12 -8
- cidc_api/models/pydantic/stage2/participant.py +10 -6
- cidc_api/models/pydantic/stage2/prior_treatment.py +14 -23
- cidc_api/models/pydantic/stage2/publication.py +2 -2
- cidc_api/models/pydantic/stage2/radiotherapy_dose.py +2 -2
- cidc_api/models/pydantic/stage2/response.py +5 -11
- cidc_api/models/pydantic/stage2/response_by_system.py +10 -7
- cidc_api/models/pydantic/stage2/shipment.py +2 -2
- cidc_api/models/pydantic/stage2/shipment_specimen.py +1 -1
- cidc_api/models/pydantic/stage2/specimen.py +8 -5
- cidc_api/models/pydantic/stage2/stem_cell_transplant.py +2 -2
- cidc_api/models/pydantic/stage2/surgery.py +1 -1
- cidc_api/models/pydantic/stage2/therapy_agent_dose.py +1 -1
- cidc_api/models/pydantic/stage2/treatment.py +2 -2
- cidc_api/models/pydantic/stage2/trial.py +19 -15
- cidc_api/models/types.py +45 -42
- cidc_api/shared/assay_handling.py +68 -0
- cidc_api/shared/auth.py +5 -5
- cidc_api/shared/file_handling.py +16 -4
- cidc_api/shared/gcloud_client.py +78 -16
- cidc_api/shared/utils.py +18 -9
- cidc_api/telemetry.py +101 -0
- {nci_cidc_api_modules-1.2.29.dist-info → nci_cidc_api_modules-1.2.45.dist-info}/METADATA +25 -14
- nci_cidc_api_modules-1.2.45.dist-info/RECORD +165 -0
- cidc_api/models/db/base_orm.py +0 -25
- nci_cidc_api_modules-1.2.29.dist-info/RECORD +0 -109
- {nci_cidc_api_modules-1.2.29.dist-info → nci_cidc_api_modules-1.2.45.dist-info}/WHEEL +0 -0
- {nci_cidc_api_modules-1.2.29.dist-info → nci_cidc_api_modules-1.2.45.dist-info}/licenses/LICENSE +0 -0
- {nci_cidc_api_modules-1.2.29.dist-info → nci_cidc_api_modules-1.2.45.dist-info}/top_level.txt +0 -0
cidc_api/shared/gcloud_client.py
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
"""Utilities for interacting with the Google Cloud Platform APIs."""
|
|
2
2
|
|
|
3
|
-
# pylint: disable=logging-fstring-interpolation,too-many-lines
|
|
3
|
+
# pylint: disable=logging-fstring-interpolation,too-many-lines, broad-exception-raised
|
|
4
4
|
|
|
5
|
+
import asyncio
|
|
5
6
|
import base64
|
|
6
7
|
import datetime
|
|
7
8
|
import hashlib
|
|
8
9
|
import io
|
|
9
10
|
import json
|
|
10
11
|
import os
|
|
12
|
+
import re
|
|
11
13
|
import warnings
|
|
12
14
|
from collections import namedtuple
|
|
13
15
|
from concurrent.futures import Future
|
|
@@ -25,6 +27,8 @@ from typing import (
|
|
|
25
27
|
)
|
|
26
28
|
|
|
27
29
|
import googleapiclient.discovery
|
|
30
|
+
from gcloud.aio.storage import Storage
|
|
31
|
+
from pandas.core.frame import DataFrame
|
|
28
32
|
import pandas as pd
|
|
29
33
|
import requests
|
|
30
34
|
from cidc_schemas.prism.constants import ASSAY_TO_FILEPATH
|
|
@@ -56,6 +60,7 @@ from ..config.settings import (
|
|
|
56
60
|
GOOGLE_GRANT_DOWNLOAD_PERMISSIONS_TOPIC,
|
|
57
61
|
GOOGLE_HL_CLINICAL_VALIDATION_TOPIC,
|
|
58
62
|
GOOGLE_DL_CLINICAL_VALIDATION_TOPIC,
|
|
63
|
+
GOOGLE_ASSAY_METADATA_VALIDATION_TOPIC,
|
|
59
64
|
TESTING,
|
|
60
65
|
ENV,
|
|
61
66
|
IS_EMAIL_ON,
|
|
@@ -361,15 +366,34 @@ def get_intake_bucket_name(user_email: str) -> str:
|
|
|
361
366
|
return bucket_name
|
|
362
367
|
|
|
363
368
|
|
|
364
|
-
def
|
|
369
|
+
def get_trial_intake_bucket_name(trial_id: str) -> str:
|
|
365
370
|
"""
|
|
366
|
-
|
|
371
|
+
Return a sanitized GCS bucket name for a given trial_id.
|
|
372
|
+
|
|
373
|
+
Produces: <GOOGLE_INTAKE_BUCKET>-<sanitized_trial_id>
|
|
374
|
+
where the trial_id segment is lowercased and restricted to [a-z0-9-].
|
|
375
|
+
"""
|
|
376
|
+
# Replace non-allowed bucket chars with "-"
|
|
377
|
+
sanitized_id = re.sub(r"[^a-z0-9-]", "-", trial_id.lower())
|
|
378
|
+
# Collapse repeated "-" and trim from both ends
|
|
379
|
+
sanitized_id = re.sub(r"-+", "-", sanitized_id).strip("-")
|
|
380
|
+
|
|
381
|
+
return f"{GOOGLE_INTAKE_BUCKET}-{sanitized_id}"
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
def create_intake_bucket(user_email: str, trial_id: str = None) -> storage.Bucket:
|
|
385
|
+
"""
|
|
386
|
+
Create (or retrieve) the appropriate data intake bucket.
|
|
387
|
+
If a trial_id is provided, a trial-specific bucket is used;
|
|
388
|
+
otherwise a user-specific intake bucket is used.
|
|
389
|
+
|
|
367
390
|
Grant the user GCS object admin permissions on the bucket, or refresh those
|
|
368
391
|
permissions if they've already been granted.
|
|
369
392
|
Created with uniform bucket-level IAM access, so expiring permission.
|
|
370
393
|
"""
|
|
371
394
|
storage_client = _get_storage_client()
|
|
372
|
-
|
|
395
|
+
# Get trial-specific bucket name if trial_id is given, otherwise a user-specific bucket name.
|
|
396
|
+
bucket_name = get_trial_intake_bucket_name(trial_id) if trial_id else get_intake_bucket_name(user_email)
|
|
373
397
|
bucket = storage_client.bucket(bucket_name)
|
|
374
398
|
|
|
375
399
|
if not bucket.exists():
|
|
@@ -423,25 +447,50 @@ def upload_xlsx_to_intake_bucket(user_email: str, trial_id: str, upload_type: st
|
|
|
423
447
|
return f"https://console.cloud.google.com/storage/browser/_details/{bucket_name}/{blob_name}"
|
|
424
448
|
|
|
425
449
|
|
|
426
|
-
def
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
if blob_name[-3:] == "csv":
|
|
432
|
-
return strip_whitespaces(pd.read_csv(temp_file))
|
|
433
|
-
elif blob_name[-4:] == "xlsx":
|
|
434
|
-
return strip_whitespaces(pd.read_excel(temp_file))
|
|
450
|
+
def prepare_dataframe(extension, bytes) -> DataFrame:
|
|
451
|
+
if extension == "csv":
|
|
452
|
+
return strip_whitespaces(pd.read_csv(bytes, dtype=str, keep_default_na=False))
|
|
453
|
+
elif extension == "xlsx":
|
|
454
|
+
return strip_whitespaces(pd.read_excel(bytes, dtype=str, keep_default_na=False))
|
|
435
455
|
else:
|
|
436
456
|
raise Exception("Can only read csv or xlsx files")
|
|
437
457
|
|
|
438
458
|
|
|
459
|
+
def gcs_xlsx_or_csv_file_to_pandas_dataframe(bucket_name: str, blob_name: str) -> DataFrame:
|
|
460
|
+
"""Reads an XLSX or CSV file from Google Cloud Storage into a Pandas DataFrame."""
|
|
461
|
+
contents = get_file_bytes_from_gcs(bucket_name, blob_name)
|
|
462
|
+
extension = blob_name.split(".")[-1]
|
|
463
|
+
return prepare_dataframe(extension, contents)
|
|
464
|
+
|
|
465
|
+
|
|
439
466
|
def get_file_bytes_from_gcs(bucket_name: str, blob_name: str) -> io.BytesIO:
|
|
440
467
|
"""Reads a file from Google Cloud Storage and returns it as BytesIO."""
|
|
441
468
|
sheet_data = storage.Client().bucket(bucket_name).blob(blob_name).download_as_bytes()
|
|
442
469
|
return io.BytesIO(sheet_data)
|
|
443
470
|
|
|
444
471
|
|
|
472
|
+
async def async_gcs_files_to_pandas_dataframes(bucket_name: str, blob_names: List[str]) -> List[DataFrame]:
|
|
473
|
+
"""Async reads a XLSX or CSV files from Google Cloud Storage into a list of Pandas DataFrames."""
|
|
474
|
+
|
|
475
|
+
all_contents = await asyncio.gather(
|
|
476
|
+
*[async_get_file_bytes_from_gcs(bucket_name, blob_name) for blob_name in blob_names]
|
|
477
|
+
)
|
|
478
|
+
dataframes = []
|
|
479
|
+
|
|
480
|
+
for blob_name, contents in zip(blob_names, all_contents):
|
|
481
|
+
extension = blob_name.split(".")[-1]
|
|
482
|
+
dataframes.append(prepare_dataframe(extension, contents))
|
|
483
|
+
return dataframes
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
async def async_get_file_bytes_from_gcs(bucket_name: str, blob_name: str) -> io.BytesIO:
|
|
487
|
+
"""Async reads a file from Google Cloud Storage and returns it as BytesIO."""
|
|
488
|
+
|
|
489
|
+
async with Storage() as client:
|
|
490
|
+
sheet_data = await client.download(bucket_name, blob_name)
|
|
491
|
+
return io.BytesIO(sheet_data)
|
|
492
|
+
|
|
493
|
+
|
|
445
494
|
def _execute_multiblob_acl_change(
|
|
446
495
|
user_email_list: List[str],
|
|
447
496
|
blob_list: List[storage.Blob],
|
|
@@ -614,6 +663,7 @@ def _build_trial_upload_prefixes(
|
|
|
614
663
|
trial_set: Set[str] = set()
|
|
615
664
|
upload_set: Set[str] = set()
|
|
616
665
|
if not trial_id:
|
|
666
|
+
# import is here becasue of circular import
|
|
617
667
|
from ..models.models import TrialMetadata
|
|
618
668
|
|
|
619
669
|
trial_set = {str(t.trial_id) for t in session.query(TrialMetadata).add_columns(TrialMetadata.trial_id)}
|
|
@@ -886,6 +936,7 @@ def get_signed_url(
|
|
|
886
936
|
bucket_name: str = GOOGLE_ACL_DATA_BUCKET,
|
|
887
937
|
method: str = "GET",
|
|
888
938
|
expiry_mins: int = 30,
|
|
939
|
+
use_short_filename: bool = False,
|
|
889
940
|
) -> str:
|
|
890
941
|
"""
|
|
891
942
|
Generate a signed URL for `object_name` to give a client temporary access.
|
|
@@ -900,7 +951,11 @@ def get_signed_url(
|
|
|
900
951
|
|
|
901
952
|
# Generate the signed URL, allowing a client to use `method` for `expiry_mins` minutes
|
|
902
953
|
expiration = datetime.timedelta(minutes=expiry_mins)
|
|
903
|
-
|
|
954
|
+
if use_short_filename:
|
|
955
|
+
filename = os.path.basename(object_name)
|
|
956
|
+
else:
|
|
957
|
+
# full filename with path included
|
|
958
|
+
filename = object_name.replace("/", "_").replace('"', "_").replace(" ", "_")
|
|
904
959
|
other_kwargs = {}
|
|
905
960
|
if os.environ.get("DEV_GOOGLE_STORAGE", None):
|
|
906
961
|
other_kwargs["api_access_endpoint"] = (os.environ.get("DEV_GOOGLE_STORAGE") or "") + (
|
|
@@ -910,7 +965,7 @@ def get_signed_url(
|
|
|
910
965
|
version="v2",
|
|
911
966
|
expiration=expiration,
|
|
912
967
|
method=method,
|
|
913
|
-
response_disposition=f'attachment; filename="{
|
|
968
|
+
response_disposition=f'attachment; filename="{filename}"',
|
|
914
969
|
**other_kwargs,
|
|
915
970
|
)
|
|
916
971
|
logger.info(f"generated signed URL for {object_name}: {url}")
|
|
@@ -920,7 +975,8 @@ def get_signed_url(
|
|
|
920
975
|
|
|
921
976
|
def _encode_and_publish(content: str, topic: str) -> Future:
|
|
922
977
|
"""Convert `content` to bytes and publish it to `topic`."""
|
|
923
|
-
|
|
978
|
+
publisher_options = pubsub.types.PublisherOptions(enable_open_telemetry_tracing=ENV == "dev-int")
|
|
979
|
+
pubsub_publisher = pubsub.PublisherClient(publisher_options=publisher_options)
|
|
924
980
|
topic = pubsub_publisher.topic_path(GOOGLE_CLOUD_PROJECT, topic)
|
|
925
981
|
data = bytes(content, "utf-8")
|
|
926
982
|
|
|
@@ -994,6 +1050,12 @@ def publish_detailed_validation(job_id: int) -> None:
|
|
|
994
1050
|
_report = _encode_and_publish(str(job_id), GOOGLE_DL_CLINICAL_VALIDATION_TOPIC)
|
|
995
1051
|
|
|
996
1052
|
|
|
1053
|
+
def publish_assay_metadata_validation(job_id: int) -> None:
|
|
1054
|
+
"""Publish to the assay_metadata_validation topic that a job's assay metadata file is ready to be validated."""
|
|
1055
|
+
# Start validation asynchronously
|
|
1056
|
+
_report = _encode_and_publish(str(job_id), GOOGLE_ASSAY_METADATA_VALIDATION_TOPIC)
|
|
1057
|
+
|
|
1058
|
+
|
|
997
1059
|
def send_email(to_emails: List[str], subject: str, html_content: str, **kw) -> None:
|
|
998
1060
|
"""
|
|
999
1061
|
Publish an email-to-send to the emails topic.
|
cidc_api/shared/utils.py
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
from cidc_api.telemetry import trace_
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def _stripper(x):
|
|
5
|
+
if x and isinstance(x, str):
|
|
6
|
+
return x.strip()
|
|
7
|
+
else:
|
|
8
|
+
return x
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@trace_("sheet")
|
|
12
|
+
def strip_whitespaces(df, sheet=None):
|
|
13
|
+
if sheet:
|
|
14
|
+
df = df[sheet]
|
|
15
|
+
|
|
16
|
+
df.rename(columns=_stripper, inplace=True)
|
|
17
|
+
df = df.map(_stripper)
|
|
18
|
+
df.replace("", None, inplace=True)
|
|
10
19
|
|
|
11
20
|
return df
|
cidc_api/telemetry.py
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# standard modules
|
|
2
|
+
from functools import wraps
|
|
3
|
+
|
|
4
|
+
# external modules
|
|
5
|
+
from opentelemetry import trace
|
|
6
|
+
from opentelemetry.sdk.resources import Resource
|
|
7
|
+
from opentelemetry.sdk.trace import TracerProvider
|
|
8
|
+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
9
|
+
|
|
10
|
+
# local modules
|
|
11
|
+
from .config.settings import ENV, TESTING
|
|
12
|
+
|
|
13
|
+
# pylint: disable=import-outside-toplevel
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def instrument_flask(app):
|
|
17
|
+
from opentelemetry.instrumentation.flask import FlaskInstrumentor
|
|
18
|
+
from opentelemetry.propagate import set_global_textmap
|
|
19
|
+
from opentelemetry.propagators.cloud_trace_propagator import CloudTraceFormatPropagator
|
|
20
|
+
|
|
21
|
+
FlaskInstrumentor().instrument_app(app)
|
|
22
|
+
|
|
23
|
+
# use the X-Cloud-Trace-Context header
|
|
24
|
+
set_global_textmap(CloudTraceFormatPropagator())
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def instrument_requests():
|
|
28
|
+
from opentelemetry.instrumentation.requests import RequestsInstrumentor
|
|
29
|
+
|
|
30
|
+
def _request_hook(span, request_obj):
|
|
31
|
+
span.update_name(f"requests {request_obj.method}")
|
|
32
|
+
|
|
33
|
+
RequestsInstrumentor().instrument(request_hook=_request_hook)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def instrument_sqlachemy(engine):
|
|
37
|
+
from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor
|
|
38
|
+
|
|
39
|
+
SQLAlchemyInstrumentor().instrument(engine=engine)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
resource = Resource(attributes={"service.name": f"CIDC-{ENV}"})
|
|
43
|
+
provider = TracerProvider(resource=resource)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
if ENV == "dev" and not TESTING:
|
|
47
|
+
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
|
|
48
|
+
|
|
49
|
+
COLLECTOR_ENDPOINT = "127.0.0.1"
|
|
50
|
+
COLLECTOR_GRPC_PORT = 6004
|
|
51
|
+
|
|
52
|
+
# send spans to local exporter
|
|
53
|
+
# 1. download latest version from https://github.com/open-telemetry/opentelemetry-collector-releases/releases (otelcol-contrib_0.140.1_darwin_arm64)
|
|
54
|
+
# 2. start exporter from otel folder with `./otelcol-contrib --config=config.yaml`
|
|
55
|
+
# 3. download and start Jeager (all-in-one image) - https://www.jaegertracing.io/download/
|
|
56
|
+
exporter = OTLPSpanExporter(endpoint=f"http://{COLLECTOR_ENDPOINT}:{COLLECTOR_GRPC_PORT}", insecure=True)
|
|
57
|
+
processor = BatchSpanProcessor(exporter)
|
|
58
|
+
provider.add_span_processor(processor)
|
|
59
|
+
|
|
60
|
+
if ENV == "dev-int":
|
|
61
|
+
from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
|
|
62
|
+
|
|
63
|
+
# send span to Cloud Trace service - https://console.cloud.google.com/traces/explorer
|
|
64
|
+
exporter = CloudTraceSpanExporter()
|
|
65
|
+
processor = BatchSpanProcessor(exporter)
|
|
66
|
+
provider.add_span_processor(processor)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# NOTE: we don't run telemetry in upper tiers; no span processor is noop
|
|
70
|
+
|
|
71
|
+
trace.set_tracer_provider(provider)
|
|
72
|
+
tracer = trace.get_tracer(__name__)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def trace_(*args):
|
|
76
|
+
def decorator_factory(func):
|
|
77
|
+
|
|
78
|
+
@wraps(func)
|
|
79
|
+
def wrapper(*args_, **kwargs_):
|
|
80
|
+
func_name = f"{func.__module__.split(".")[-1]}.{func.__name__}"
|
|
81
|
+
|
|
82
|
+
with tracer.start_as_current_span(func_name) as span:
|
|
83
|
+
for arg in args:
|
|
84
|
+
value = kwargs_.get(arg)
|
|
85
|
+
|
|
86
|
+
# track id of argument if exists
|
|
87
|
+
if hasattr(value, "id"):
|
|
88
|
+
value = getattr(value, "id")
|
|
89
|
+
|
|
90
|
+
span.set_attributes({arg: value})
|
|
91
|
+
|
|
92
|
+
result = func(*args_, **kwargs_)
|
|
93
|
+
|
|
94
|
+
if isinstance(result, (str, int, float, bool)):
|
|
95
|
+
span.set_attribute("result", result)
|
|
96
|
+
|
|
97
|
+
return result
|
|
98
|
+
|
|
99
|
+
return wrapper
|
|
100
|
+
|
|
101
|
+
return decorator_factory
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nci_cidc_api_modules
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.45
|
|
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,41 @@ 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.
|
|
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
|
-
Requires-Dist:
|
|
16
|
-
Requires-Dist:
|
|
17
|
-
Requires-Dist: google-
|
|
18
|
-
Requires-Dist: google-
|
|
19
|
-
Requires-Dist: google-cloud-
|
|
20
|
-
Requires-Dist: google-cloud-
|
|
15
|
+
Requires-Dist: flask-talisman>=0.7.0
|
|
16
|
+
Requires-Dist: gcloud-aio-storage~=9.6.1
|
|
17
|
+
Requires-Dist: google-auth==2.45.0
|
|
18
|
+
Requires-Dist: google-api-python-client>=2.187.0
|
|
19
|
+
Requires-Dist: google-cloud-bigquery>=3.39.0
|
|
20
|
+
Requires-Dist: google-cloud-pubsub>=2.34.0
|
|
21
|
+
Requires-Dist: google-cloud-secret-manager>=2.26.0
|
|
22
|
+
Requires-Dist: google-cloud-storage>=3.7.0
|
|
21
23
|
Requires-Dist: jinja2>=3.1.6
|
|
22
|
-
Requires-Dist:
|
|
24
|
+
Requires-Dist: joserfc>=1.6.0
|
|
25
|
+
Requires-Dist: marshmallow>=4.1.2
|
|
23
26
|
Requires-Dist: marshmallow-sqlalchemy>=1.4.2
|
|
24
|
-
Requires-Dist: numpy>=2.
|
|
27
|
+
Requires-Dist: numpy>=2.4.0
|
|
25
28
|
Requires-Dist: packaging>=25.0
|
|
26
29
|
Requires-Dist: pandas>=2.3.3
|
|
27
30
|
Requires-Dist: pyarrow>=22.0.0
|
|
28
|
-
Requires-Dist: pydantic~=2.12.
|
|
31
|
+
Requires-Dist: pydantic~=2.12.5
|
|
29
32
|
Requires-Dist: python-dotenv>=1.2.1
|
|
30
33
|
Requires-Dist: requests>=2.32.5
|
|
31
|
-
Requires-Dist: sqlalchemy>=2.0.
|
|
34
|
+
Requires-Dist: sqlalchemy>=2.0.45
|
|
32
35
|
Requires-Dist: sqlalchemy-mixins~=2.0.5
|
|
33
|
-
Requires-Dist: werkzeug>=3.1.
|
|
34
|
-
Requires-Dist:
|
|
36
|
+
Requires-Dist: werkzeug>=3.1.4
|
|
37
|
+
Requires-Dist: opentelemetry-api>=1.39.1
|
|
38
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.39.1
|
|
39
|
+
Requires-Dist: opentelemetry-sdk>=1.39.1
|
|
40
|
+
Requires-Dist: opentelemetry-instrumentation-flask>=0.59b0
|
|
41
|
+
Requires-Dist: opentelemetry-instrumentation-requests>=0.59b0
|
|
42
|
+
Requires-Dist: opentelemetry-instrumentation-sqlalchemy>=0.59b0
|
|
43
|
+
Requires-Dist: opentelemetry-exporter-gcp-trace>=1.11.0
|
|
44
|
+
Requires-Dist: opentelemetry-propagator-gcp>=1.11.0
|
|
45
|
+
Requires-Dist: nci-cidc-schemas==0.28.11
|
|
35
46
|
Dynamic: description
|
|
36
47
|
Dynamic: description-content-type
|
|
37
48
|
Dynamic: home-page
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
cidc_api/__init__.py,sha256=TdZZy40X_55kxtHKjwbGqPrDr5qQe_uUz_Fvup_EuNI,23
|
|
2
|
+
cidc_api/telemetry.py,sha256=LuZWkG8CKCn23O41RTNxEOQwMmfpp-fQ6zSInZhVJg8,3333
|
|
3
|
+
cidc_api/config/__init__.py,sha256=5mX8GAPxUKV84iS-aGOoE-4m68LsOCGCDptXNdlgvj0,148
|
|
4
|
+
cidc_api/config/db.py,sha256=mEz8ugjvRNGylCqDYHaaMqaZfDh7sbd76BowmfBvq5c,2428
|
|
5
|
+
cidc_api/config/logging.py,sha256=abhVYtn8lfhIt0tyV2WHFgSmp_s2eeJh7kodB6LH4J0,1149
|
|
6
|
+
cidc_api/config/secrets.py,sha256=jRFj7W43pWuPf9DZQLCKF7WPXf5cUv-BAaS3ASqhV_Q,1481
|
|
7
|
+
cidc_api/config/settings.py,sha256=Zql6Gxb5MNBW-rxcDNIPUqPiYHnD9nxd2-ievHaEYcI,4744
|
|
8
|
+
cidc_api/models/__init__.py,sha256=bl445G8Zic9YbhZ8ZBni07wtBMhLJRMBA-JqjLxx2bw,66
|
|
9
|
+
cidc_api/models/data.py,sha256=TyVXk5jJO1NN05CLqejLf5BPp6yLSNNxPmFOgXUnA1M,1313
|
|
10
|
+
cidc_api/models/migrations.py,sha256=UlS5How3J4ryaRuZT6F5VQtAKikkl0LTv9MgMO_ltiQ,11161
|
|
11
|
+
cidc_api/models/models.py,sha256=DTt0eFkFVVxVn23Aqr6TA8CQ7qb2hdqQ0xVJ3RakBBw,153684
|
|
12
|
+
cidc_api/models/schemas.py,sha256=6IE2dJoEMcMbi0Vr1V3cYKnPKU0hv9vRKBixOZHe88s,2766
|
|
13
|
+
cidc_api/models/types.py,sha256=WVOTEH61FH5aGVwRbEcfNOce8NLjiEnl1ixtPWav2OA,30058
|
|
14
|
+
cidc_api/models/db/stage1/__init__.py,sha256=zsxOSoogzL_xZ8B5OwcwLXvAmm6g2GYx1Zf6LLw8dq8,1917
|
|
15
|
+
cidc_api/models/db/stage1/additional_treatment_orm.py,sha256=GCMzsYZl_B-7-TWYDBUXbt_Gri6YDv8XkYRheDLh3pc,926
|
|
16
|
+
cidc_api/models/db/stage1/adverse_event_orm.py,sha256=32Kjpg6fvByp4gEVy6K28MlgMWQryG6GPh3un1F8x64,1914
|
|
17
|
+
cidc_api/models/db/stage1/base_orm.py,sha256=izKizTf2W1fCK2CRUeyuErJbOaxNp6d299n4gqKWHDQ,246
|
|
18
|
+
cidc_api/models/db/stage1/baseline_clinical_assessment_orm.py,sha256=pGanJlwnAm38LPVTu6XF4qP_mw-SqYP8AC3O8w8XPnw,911
|
|
19
|
+
cidc_api/models/db/stage1/comorbidity_orm.py,sha256=C4P3kcpNpnt1ICgU2Xm5S-ou6Xhx6yr690g6F_hBoZ0,881
|
|
20
|
+
cidc_api/models/db/stage1/consent_group_orm.py,sha256=O7oZr7-Rvmzn8o4kS_40e270sF2e-KX85VkXemsa2MM,1111
|
|
21
|
+
cidc_api/models/db/stage1/demographic_orm.py,sha256=JR6CXCVLEvFTgElQazuNEgopIuf5Ik1w0m1kSkxp4Q0,1693
|
|
22
|
+
cidc_api/models/db/stage1/disease_orm.py,sha256=Ni1kxQxgVi0MKUlovcsnmpR9v1TwKWcO6tpEr1oZcsE,1965
|
|
23
|
+
cidc_api/models/db/stage1/exposure_orm.py,sha256=u6YKhAAX_0uYHMOYf8sQQFy3l9KluRykaIiggn9v_EY,811
|
|
24
|
+
cidc_api/models/db/stage1/gvhd_diagnosis_acute_orm.py,sha256=0ItEmNE2H2Xmh4W3t0DNg3W764Uk00d5gni6maMQ3N0,1470
|
|
25
|
+
cidc_api/models/db/stage1/gvhd_diagnosis_chronic_orm.py,sha256=seH3WO9IzQmau47N7zjJOa6OCSYi9_25WE5jOvxl6q8,1552
|
|
26
|
+
cidc_api/models/db/stage1/gvhd_organ_acute_orm.py,sha256=knzkKz2qkRU0R6HjdtfClOuRpGEYEsLxbhqYUmOAjSg,838
|
|
27
|
+
cidc_api/models/db/stage1/gvhd_organ_chronic_orm.py,sha256=mkhS1jFgCt_2NRXZfoqHWZh1ShkzLoPLR9W8ac_wzGs,862
|
|
28
|
+
cidc_api/models/db/stage1/medical_history_orm.py,sha256=nyNOG_odEvPWqgu2DmiHT3K-FBB1ltI536iiNwCF0wA,1282
|
|
29
|
+
cidc_api/models/db/stage1/other_malignancy_orm.py,sha256=wfoSCPUIzfw4anDi6FeqyhTzYrwTNlpDRCvL608zmXM,1303
|
|
30
|
+
cidc_api/models/db/stage1/participant_orm.py,sha256=3-s6F0yTFzBYFZrDKv2xJMv5p3VBt5EL1Quu9cK4sd8,3541
|
|
31
|
+
cidc_api/models/db/stage1/prior_treatment_orm.py,sha256=SNa_JOIF5gS61N0HFEfM7BHv3JYsflt6LQz03WLb8Lo,1325
|
|
32
|
+
cidc_api/models/db/stage1/radiotherapy_dose_orm.py,sha256=dLp_ENJAq-_f6MAspaGK-6R6ngHceFKpsrjoBM8yviI,1500
|
|
33
|
+
cidc_api/models/db/stage1/response_by_system_orm.py,sha256=pOQSE5g-EFUApgEDOXwxyQCmvoC6M9atSfBDsF9f3KI,1524
|
|
34
|
+
cidc_api/models/db/stage1/response_orm.py,sha256=P9a0ZVq_hJ3dipRgJTFcdjuWi9ueyGd0oQYHRiACNpc,1163
|
|
35
|
+
cidc_api/models/db/stage1/specimen_orm.py,sha256=m1cq5SfkUETk6dk4s3uYLyXohpZgE8iU1Rzh0xVRTmw,1354
|
|
36
|
+
cidc_api/models/db/stage1/stem_cell_transplant_orm.py,sha256=CqOAo-Pnj11XqR9a0CeaIGyLn5Ar42Hl_10tqEllnO0,1097
|
|
37
|
+
cidc_api/models/db/stage1/surgery_orm.py,sha256=DCggc6xbjGhm-G93bueY5u43t896aBPTvRFTk3Gq8ys,1018
|
|
38
|
+
cidc_api/models/db/stage1/therapy_agent_dose_orm.py,sha256=y8vaJazcoJ5mb0dmGXiAN8dQPP6yyDGpAOs_wDlH3SY,1306
|
|
39
|
+
cidc_api/models/db/stage1/treatment_orm.py,sha256=gRhCswnYYr7DLHbUzz-Lyg3pDVJy6j0UjBZ8SQX3C9k,1625
|
|
40
|
+
cidc_api/models/db/stage1/trial_orm.py,sha256=bS2zIngkv8ruXdXskinSwz8H1EeAgs9aHnteUWqaplE,1266
|
|
41
|
+
cidc_api/models/db/stage2/__init__.py,sha256=R33BM1VDKJya5uuyYnPoGFVfhSViclIOklSoHH-EtBQ,2691
|
|
42
|
+
cidc_api/models/db/stage2/additional_treatment_orm.py,sha256=G8_3EgGWH0vf3Rt5hTmM9xFids4NPcEBkQSS7hsrIdI,924
|
|
43
|
+
cidc_api/models/db/stage2/administrative_person_orm.py,sha256=yjBktBwIjzHwqIbs1BAqJhh3y8f6swmEJRGs-XDQ_OI,1016
|
|
44
|
+
cidc_api/models/db/stage2/administrative_role_assignment_orm.py,sha256=9X3Fkecj8_pxui99LpvA7WIMuWcagYW-QiRcvI7gAHg,1291
|
|
45
|
+
cidc_api/models/db/stage2/adverse_event_orm.py,sha256=lsou-Ej7F_LW7D4pZbgAoR3BLPkW-KJkNjPPv2RtlY0,1914
|
|
46
|
+
cidc_api/models/db/stage2/arm_orm.py,sha256=5jSoHENJXpqW36UrECmBphz_MRQUcYIXGF0fvhMDMWY,707
|
|
47
|
+
cidc_api/models/db/stage2/base_orm.py,sha256=nk9q0wlHxbuC7vzMtPCsnqeIRQufh3MCniMxu-h7__w,246
|
|
48
|
+
cidc_api/models/db/stage2/baseline_clinical_assessment_orm.py,sha256=4V8RuiWGNf2c8Plzeikusslk8pZGhedDm_oXMMDcRbc,911
|
|
49
|
+
cidc_api/models/db/stage2/cohort_orm.py,sha256=ag3Epvnr8__3yfmyUjR7n9fBfMnBlpU1wPyvFZFIWpo,710
|
|
50
|
+
cidc_api/models/db/stage2/comorbidity_orm.py,sha256=EbjqUj9vsFEL0KJFqsc04I-KFGjILje2H71WD2uP3ZQ,881
|
|
51
|
+
cidc_api/models/db/stage2/consent_group_orm.py,sha256=d6r00XxWf7wHwYDAhBsEjSq3Ma2jixAa5l5mNDePNFk,1111
|
|
52
|
+
cidc_api/models/db/stage2/contact_orm.py,sha256=__YFzOrYnMs_TNC1IAI1EL-Xx2stRJTUkcru5GDYleY,1267
|
|
53
|
+
cidc_api/models/db/stage2/demographic_orm.py,sha256=qTO8w0AVTP7NpryfeinaR2X22ll6qA_jxCVGXmAjN60,1693
|
|
54
|
+
cidc_api/models/db/stage2/disease_orm.py,sha256=-PVtbDHFI9PmlYTOsry8LFbuR2YVMq_NrVNkDSZMbLo,1965
|
|
55
|
+
cidc_api/models/db/stage2/exposure_orm.py,sha256=LLuGsaW-dA8B5e__LP9LGAaU7QH5fo5-4Btx28mpE3A,811
|
|
56
|
+
cidc_api/models/db/stage2/file_orm.py,sha256=Zn6HzTz_UcsZRAJUi3OvcASMMtYNh4AFLQTcq_NuG3A,1253
|
|
57
|
+
cidc_api/models/db/stage2/gvhd_diagnosis_acute_orm.py,sha256=n1FtHoUzpKEhDkC5z9VQ_pMKj-M-RpPb3tOerDYwIe4,1470
|
|
58
|
+
cidc_api/models/db/stage2/gvhd_diagnosis_chronic_orm.py,sha256=tA-upQ9q755klfu01HQyRVxBZq7RX_WclZWHuGHGBiw,1552
|
|
59
|
+
cidc_api/models/db/stage2/gvhd_organ_acute_orm.py,sha256=3ShOfSGKgrRBmu83KkpHY3-tCbLL60UWtpcbLqqnq9Y,838
|
|
60
|
+
cidc_api/models/db/stage2/gvhd_organ_chronic_orm.py,sha256=1oVQal-jDylHhfbop43UKZ86YQzrSMu9qCiF8_ELXnY,862
|
|
61
|
+
cidc_api/models/db/stage2/institution_orm.py,sha256=gE0tceyc8mOqZRoOtOAJIAPJUSwJcDaU8L6J4HuUSYM,1248
|
|
62
|
+
cidc_api/models/db/stage2/medical_history_orm.py,sha256=4g-0nk8TIRpzrqwYTAlj9w6o_bPwzic0ygX6sK4x9SU,1282
|
|
63
|
+
cidc_api/models/db/stage2/other_clinical_endpoint_orm.py,sha256=k2Vglc8jASKzSBYBc6C5HCfKUD-cC-HKgvNmuxMFOQc,1091
|
|
64
|
+
cidc_api/models/db/stage2/other_malignancy_orm.py,sha256=qcPL29e8RwAGquMWEp2-ZGSecJGhlgpKdfYFNIHXHvI,1303
|
|
65
|
+
cidc_api/models/db/stage2/participant_orm.py,sha256=U2OICb5OUPpMuh7SPeQJ9GsX4uq5MDc2UYMt52BJYb4,3695
|
|
66
|
+
cidc_api/models/db/stage2/prior_treatment_orm.py,sha256=pvtB3DD6UPtS7GQpAinvJi64mlZjEwWVcp0bFaHpASo,1305
|
|
67
|
+
cidc_api/models/db/stage2/publication_orm.py,sha256=EMAq83WtgFYy5yBESgaajruB6fzYfMTLNyZDZiIJBLM,1040
|
|
68
|
+
cidc_api/models/db/stage2/radiotherapy_dose_orm.py,sha256=QBNmehh5VsKzkc59u_CHsFIgWYKsEp4lFyxp5HPMysM,1500
|
|
69
|
+
cidc_api/models/db/stage2/response_by_system_orm.py,sha256=FzbxFkcIt-IGzwejVITHVFZ5qYA5Oece3yEBqhzjPHw,1524
|
|
70
|
+
cidc_api/models/db/stage2/response_orm.py,sha256=p4xtydLvuZovVwcMvq3-WdLsKeKtIl6KTklGlWGVBSA,1163
|
|
71
|
+
cidc_api/models/db/stage2/shipment_orm.py,sha256=dDmj_PK2yAq23oh60sAcT2dkw5PjWmBoqO55YtFtExc,2007
|
|
72
|
+
cidc_api/models/db/stage2/shipment_specimen_orm.py,sha256=0ufXOQPDjgucu5qXQWDAKnRXajvuldsZezj5ez6hsgg,909
|
|
73
|
+
cidc_api/models/db/stage2/specimen_orm.py,sha256=-UDfQ0IlbmCs6GxCwVIF2eiFPgsjdgq_OAV-X58lH_U,4165
|
|
74
|
+
cidc_api/models/db/stage2/stem_cell_transplant_orm.py,sha256=YxiDGUXIiEtHyBU0zieniG1Ey8cTozuuRym6fv_8DsA,1097
|
|
75
|
+
cidc_api/models/db/stage2/surgery_orm.py,sha256=68g7__ZncQ6Yui5nGhSOHZjWIXWrb5PRAZRS6FCWD18,1018
|
|
76
|
+
cidc_api/models/db/stage2/therapy_agent_dose_orm.py,sha256=dRgXJqlv_EAGaPZ99xFR3xSXBiCPcC-G5e5eJSxqiVY,1306
|
|
77
|
+
cidc_api/models/db/stage2/treatment_orm.py,sha256=ualcYhXrl2obJ-wXDRx5riQsgOWEbdOmmKY8YNiPdZY,1919
|
|
78
|
+
cidc_api/models/db/stage2/trial_orm.py,sha256=7_5kA1Yv80GFQykK8AIlFC0vtrsb2H8xLstlgt8J370,2855
|
|
79
|
+
cidc_api/models/files/__init__.py,sha256=8BMTnUSHzUbz0lBeEQY6NvApxDD3GMWMduoVMos2g4Y,213
|
|
80
|
+
cidc_api/models/files/details.py,sha256=sZkGM7iEV4-J6IDQCdiMV6KBDLbPxCOqUMaU3aY9rX8,65153
|
|
81
|
+
cidc_api/models/files/facets.py,sha256=vieZ3z_tYB29NqtvNzvKqajVwxM5ZLLZKeyQTq5lheU,33776
|
|
82
|
+
cidc_api/models/pydantic/base.py,sha256=6Lsf4fekIS1E-DwZmgCXlfm3Qq9_23dA_v3iz1w2JoA,1427
|
|
83
|
+
cidc_api/models/pydantic/stage1/__init__.py,sha256=H-NDjCd8isHTgZ7sqz-MIbzC-PpW1kEtR-x-Dyc8r6Q,1667
|
|
84
|
+
cidc_api/models/pydantic/stage1/additional_treatment.py,sha256=TFVzjd1NPLSfH9UnL2W3aZhpZSzDsg97j9IK8t882YA,1050
|
|
85
|
+
cidc_api/models/pydantic/stage1/adverse_event.py,sha256=zPy02xoRQeyaXBSmqDdQt4BaRTD6OHBjycVHVtBaAow,3880
|
|
86
|
+
cidc_api/models/pydantic/stage1/baseline_clinical_assessment.py,sha256=5FYvtOVf_nIK1h3xTs3vQgJe2ivQSVHt_wfrTSDgVxU,1119
|
|
87
|
+
cidc_api/models/pydantic/stage1/comorbidity.py,sha256=dk4SJnkaaju-boexf2SW_rNNGXl-Os2LR5lnIxCb-dA,1413
|
|
88
|
+
cidc_api/models/pydantic/stage1/consent_group.py,sha256=aP_nd0GKK6K7VH-6IZRSDDX2RxFM_j9B36FIRGwysOU,1216
|
|
89
|
+
cidc_api/models/pydantic/stage1/demographic.py,sha256=X0YoFdK7S8JQ9p_Jm3l-R5HgEl9sZnZVFXrECA2i_zw,6007
|
|
90
|
+
cidc_api/models/pydantic/stage1/disease.py,sha256=fwK1FSxTm33BzViGTNsb6AahoDc2BTTXMitCGY3KyDk,7650
|
|
91
|
+
cidc_api/models/pydantic/stage1/exposure.py,sha256=ERoVQLuNWynw2zugh5bVdUT0NzNbJ6fIUmKhPSCQfqk,1306
|
|
92
|
+
cidc_api/models/pydantic/stage1/gvhd_diagnosis_acute.py,sha256=jVMoWuLfspOZtOpC7rg1EzdvEAg8qEabcTaS6RRobZ8,1395
|
|
93
|
+
cidc_api/models/pydantic/stage1/gvhd_diagnosis_chronic.py,sha256=SRwkAL07YyIZM4bYCqm01aKqSvj3yRmpsqFKxAZEZoM,1382
|
|
94
|
+
cidc_api/models/pydantic/stage1/gvhd_organ_acute.py,sha256=VxlNGRJYjm9tW2lyLll8pD0t9JZs18gicnH-Ci_nR2I,771
|
|
95
|
+
cidc_api/models/pydantic/stage1/gvhd_organ_chronic.py,sha256=Fnp1Qm-ZDDtDLrgOAnEOUnQVNWI9WrTSomiFPStGmjc,810
|
|
96
|
+
cidc_api/models/pydantic/stage1/medical_history.py,sha256=IXtEvXrrLhTt6JEsj2MpDiZtLAkmrrsUS4aoe7sxans,1697
|
|
97
|
+
cidc_api/models/pydantic/stage1/other_malignancy.py,sha256=V-Jru6uukipocKs7lDbmkGyJsHBxlM3A3NJoTShjJ9I,2188
|
|
98
|
+
cidc_api/models/pydantic/stage1/participant.py,sha256=iDQrwYYtJY_XrkdbhsRNZuL44ighvW8JHCGxH-qo8jk,2199
|
|
99
|
+
cidc_api/models/pydantic/stage1/prior_treatment.py,sha256=axhyPHwYCoIvcIonjyPJ95HUyaAXqIuOd6hhoDM3LJU,2101
|
|
100
|
+
cidc_api/models/pydantic/stage1/radiotherapy_dose.py,sha256=c5q0TxPOrYHX9KTd9he5B01zirKgcCxMnvW_7adzCrI,3327
|
|
101
|
+
cidc_api/models/pydantic/stage1/response.py,sha256=rPqfYZhaZRcA1E7dkGOaHe9f2_YIcIg9-KtIPSTh1s8,2886
|
|
102
|
+
cidc_api/models/pydantic/stage1/response_by_system.py,sha256=f8ZnLfNXGJLCfFL1X2jxlSUJPGvJKnOCf6PYbJVMXW8,4909
|
|
103
|
+
cidc_api/models/pydantic/stage1/specimen.py,sha256=scDekZ-RtXOQTTLburhqT3RF4KM34iY9NAV1wYi_HSg,1281
|
|
104
|
+
cidc_api/models/pydantic/stage1/stem_cell_transplant.py,sha256=XsDVUksqbIprPxHwLlwHGyji4jsIFNMcIk-S0H4rDnQ,1228
|
|
105
|
+
cidc_api/models/pydantic/stage1/surgery.py,sha256=53NrET_kNOlXXPP-mH5ecIPrNqDpDQt5s9WfsjPDM-s,2149
|
|
106
|
+
cidc_api/models/pydantic/stage1/therapy_agent_dose.py,sha256=Y2L0vAqkfA5eI2qg7iQrqzCORwbkjyVEsthc6f5HKas,3021
|
|
107
|
+
cidc_api/models/pydantic/stage1/treatment.py,sha256=1TeBaDJ352IfB10AtJH2iREdex3SZgDRXNUkhT0FZMo,2033
|
|
108
|
+
cidc_api/models/pydantic/stage1/trial.py,sha256=EFsMVMxxHbPeaBb6JG9JpX1qjtoho2t-GZnaI0gsYrY,1859
|
|
109
|
+
cidc_api/models/pydantic/stage2/__init__.py,sha256=OQRG5wFkNsyAU_0KI1W5PDn8pBDe1EJDcgKZ19shh_g,2331
|
|
110
|
+
cidc_api/models/pydantic/stage2/additional_treatment.py,sha256=TFVzjd1NPLSfH9UnL2W3aZhpZSzDsg97j9IK8t882YA,1050
|
|
111
|
+
cidc_api/models/pydantic/stage2/administrative_person.py,sha256=3UYRgGLP7RukwZYTvQEnviDxBvWXj1uqditsoLJOw0s,1552
|
|
112
|
+
cidc_api/models/pydantic/stage2/administrative_role_assignment.py,sha256=kWUciVSnczjejdBSlynsVxSQ4dytDdgw9OxSvgzParg,536
|
|
113
|
+
cidc_api/models/pydantic/stage2/adverse_event.py,sha256=zPy02xoRQeyaXBSmqDdQt4BaRTD6OHBjycVHVtBaAow,3880
|
|
114
|
+
cidc_api/models/pydantic/stage2/arm.py,sha256=I_gyRUkjyA-Eds3BOu-PUlBGdeGeKiG92ERM8WqA2n8,481
|
|
115
|
+
cidc_api/models/pydantic/stage2/baseline_clinical_assessment.py,sha256=5FYvtOVf_nIK1h3xTs3vQgJe2ivQSVHt_wfrTSDgVxU,1119
|
|
116
|
+
cidc_api/models/pydantic/stage2/cohort.py,sha256=NVlgp8D93nXGPDMSyrAJe-QbmrQfudyuTsc400WyOpg,493
|
|
117
|
+
cidc_api/models/pydantic/stage2/comorbidity.py,sha256=dk4SJnkaaju-boexf2SW_rNNGXl-Os2LR5lnIxCb-dA,1413
|
|
118
|
+
cidc_api/models/pydantic/stage2/consent_group.py,sha256=aP_nd0GKK6K7VH-6IZRSDDX2RxFM_j9B36FIRGwysOU,1216
|
|
119
|
+
cidc_api/models/pydantic/stage2/contact.py,sha256=Nfyy5Zn-n9_LiXG-CzC7OsQo7JrzdPcYjZIielpZiM0,883
|
|
120
|
+
cidc_api/models/pydantic/stage2/demographic.py,sha256=X0YoFdK7S8JQ9p_Jm3l-R5HgEl9sZnZVFXrECA2i_zw,6007
|
|
121
|
+
cidc_api/models/pydantic/stage2/disease.py,sha256=fwK1FSxTm33BzViGTNsb6AahoDc2BTTXMitCGY3KyDk,7650
|
|
122
|
+
cidc_api/models/pydantic/stage2/exposure.py,sha256=ERoVQLuNWynw2zugh5bVdUT0NzNbJ6fIUmKhPSCQfqk,1306
|
|
123
|
+
cidc_api/models/pydantic/stage2/file.py,sha256=MjZQAII_QqakLBhyfP1bq_Mn6au4yvVuwY0p0A5c664,1336
|
|
124
|
+
cidc_api/models/pydantic/stage2/gvhd_diagnosis_acute.py,sha256=jVMoWuLfspOZtOpC7rg1EzdvEAg8qEabcTaS6RRobZ8,1395
|
|
125
|
+
cidc_api/models/pydantic/stage2/gvhd_diagnosis_chronic.py,sha256=SRwkAL07YyIZM4bYCqm01aKqSvj3yRmpsqFKxAZEZoM,1382
|
|
126
|
+
cidc_api/models/pydantic/stage2/gvhd_organ_acute.py,sha256=VxlNGRJYjm9tW2lyLll8pD0t9JZs18gicnH-Ci_nR2I,771
|
|
127
|
+
cidc_api/models/pydantic/stage2/gvhd_organ_chronic.py,sha256=Fnp1Qm-ZDDtDLrgOAnEOUnQVNWI9WrTSomiFPStGmjc,810
|
|
128
|
+
cidc_api/models/pydantic/stage2/institution.py,sha256=41Lod9ryjB3x2jySHp_g3b7g1sj41Q4zwcNsGgXMGZ4,268
|
|
129
|
+
cidc_api/models/pydantic/stage2/medical_history.py,sha256=IXtEvXrrLhTt6JEsj2MpDiZtLAkmrrsUS4aoe7sxans,1697
|
|
130
|
+
cidc_api/models/pydantic/stage2/other_clinical_endpoint.py,sha256=bxZV3qIrrieX4xy3HbKyHdgfpwBcT-abQNlSodVCMns,1093
|
|
131
|
+
cidc_api/models/pydantic/stage2/other_malignancy.py,sha256=V-Jru6uukipocKs7lDbmkGyJsHBxlM3A3NJoTShjJ9I,2188
|
|
132
|
+
cidc_api/models/pydantic/stage2/participant.py,sha256=x7gKHaw46-BbqNCgKWPLnp7U8L2pnAkh7hdByKvG_Kk,2185
|
|
133
|
+
cidc_api/models/pydantic/stage2/prior_treatment.py,sha256=G5Cd8PSYRe3gdeApjQWn15QAErB4nDahMKcVRsr88_c,2011
|
|
134
|
+
cidc_api/models/pydantic/stage2/publication.py,sha256=GBuvqBf0lyOoopN1S-3qX310xFxhixk7oDJLuGzLuiw,1817
|
|
135
|
+
cidc_api/models/pydantic/stage2/radiotherapy_dose.py,sha256=c5q0TxPOrYHX9KTd9he5B01zirKgcCxMnvW_7adzCrI,3327
|
|
136
|
+
cidc_api/models/pydantic/stage2/response.py,sha256=rPqfYZhaZRcA1E7dkGOaHe9f2_YIcIg9-KtIPSTh1s8,2886
|
|
137
|
+
cidc_api/models/pydantic/stage2/response_by_system.py,sha256=f8ZnLfNXGJLCfFL1X2jxlSUJPGvJKnOCf6PYbJVMXW8,4909
|
|
138
|
+
cidc_api/models/pydantic/stage2/shipment.py,sha256=dsZcDPikCRS3cjr58EGHHJ2gjir78J4cdHh_1SwFyrQ,1595
|
|
139
|
+
cidc_api/models/pydantic/stage2/shipment_specimen.py,sha256=exR7joXsH3Xd-o5vJV_Z-az33Edr8BBm5LCDv01iMI4,488
|
|
140
|
+
cidc_api/models/pydantic/stage2/specimen.py,sha256=JchTeb4QSyPplZmP_gMxEsaIXVDlGI_z85xR5JG4JYY,8524
|
|
141
|
+
cidc_api/models/pydantic/stage2/stem_cell_transplant.py,sha256=XsDVUksqbIprPxHwLlwHGyji4jsIFNMcIk-S0H4rDnQ,1228
|
|
142
|
+
cidc_api/models/pydantic/stage2/surgery.py,sha256=53NrET_kNOlXXPP-mH5ecIPrNqDpDQt5s9WfsjPDM-s,2149
|
|
143
|
+
cidc_api/models/pydantic/stage2/therapy_agent_dose.py,sha256=Y2L0vAqkfA5eI2qg7iQrqzCORwbkjyVEsthc6f5HKas,3021
|
|
144
|
+
cidc_api/models/pydantic/stage2/treatment.py,sha256=dr23yeK5x0dKYZV32hgECFe_Y-GkSvdf4P3FdVn6F1Q,2039
|
|
145
|
+
cidc_api/models/pydantic/stage2/trial.py,sha256=PftvFY27s3quVBg1Sau1JdskUSMM0huIeGP-018fi5o,4020
|
|
146
|
+
cidc_api/reference/ctcae.py,sha256=H5JvDQ5R5kYbK37UxjhmXMnKD3d40HmG0DONxfhNxnE,871
|
|
147
|
+
cidc_api/reference/gvhd.py,sha256=r5jbHEa5yos0tmghjiruAeXI-r-4lU81JKCUpMHtO14,194
|
|
148
|
+
cidc_api/reference/icd10cm.py,sha256=K1vbTQB75uAQeKgj0U9izhtMKVb2vqp69_hyx3z_jro,300
|
|
149
|
+
cidc_api/reference/icdo3.py,sha256=A19yNX5-9Gs3X83kXcTlGgsXDTTJ9yR2dxEIoBVmpmU,296
|
|
150
|
+
cidc_api/reference/uberon.py,sha256=BO2mYNDvPzZyLdhL_ZjCyEgHSLHuVifnTJvfktUfVWA,148
|
|
151
|
+
cidc_api/shared/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
152
|
+
cidc_api/shared/assay_handling.py,sha256=zzWSqQ-ddLVzX5IuHvsaSib2H1lnjXpo9LbxaoqaHHs,2897
|
|
153
|
+
cidc_api/shared/auth.py,sha256=EIP9AKokLNrI79Fkpv3P7WdzaddJIsuGGICc1W494X0,9110
|
|
154
|
+
cidc_api/shared/email_layout.html,sha256=pBoTNw3ACHH-ncZFaNvcy5bXMqPwizR78usb0uCYtIc,7670
|
|
155
|
+
cidc_api/shared/emails.py,sha256=8kNFEaSnKpY-GX_iE59QUhSp3c4_uzy3SpHYt2QjuqI,6121
|
|
156
|
+
cidc_api/shared/file_handling.py,sha256=ObsLvBrkwHo6Nv48GvFXDKElNNl4inGpxv--001H_xc,5843
|
|
157
|
+
cidc_api/shared/gcloud_client.py,sha256=0B13MRF_CUMbzaKtKVDd9fxErNdNGBpxfkknQ5deu7w,39972
|
|
158
|
+
cidc_api/shared/jose.py,sha256=-qzGzEDAlokEp9E7WtBtQkXyyfPWTYXlwYpCqVJWmqM,1830
|
|
159
|
+
cidc_api/shared/rest_utils.py,sha256=RwR30WOUAYCxL7V-i2totEyeriG30GbBDvBcpLXhM9w,6594
|
|
160
|
+
cidc_api/shared/utils.py,sha256=-gLnzxCR9E6h0plt2xrNisUG5_Y6GhhVwz3DgDIzpvs,367
|
|
161
|
+
nci_cidc_api_modules-1.2.45.dist-info/licenses/LICENSE,sha256=pNYWVTHaYonnmJyplmeAp7tQAjosmDpAWjb34jjv7Xs,1102
|
|
162
|
+
nci_cidc_api_modules-1.2.45.dist-info/METADATA,sha256=ierSCHEAC0omx7bg4gjb-XPMPRTK_Qs6VMJXdW65C6A,40270
|
|
163
|
+
nci_cidc_api_modules-1.2.45.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
164
|
+
nci_cidc_api_modules-1.2.45.dist-info/top_level.txt,sha256=rNiRzL0lJGi5Q9tY9uSoMdTbJ-7u5c_D2E86KA94yRA,9
|
|
165
|
+
nci_cidc_api_modules-1.2.45.dist-info/RECORD,,
|
cidc_api/models/db/base_orm.py
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
from typing import Self
|
|
2
|
-
|
|
3
|
-
from sqlalchemy_mixins import SerializeMixin, ReprMixin
|
|
4
|
-
|
|
5
|
-
from cidc_api.config.db import db
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class BaseORM(db.Model, ReprMixin, SerializeMixin):
|
|
9
|
-
__abstract__ = True
|
|
10
|
-
__repr__ = ReprMixin.__repr__
|
|
11
|
-
|
|
12
|
-
def merge(self, d: dict) -> Self:
|
|
13
|
-
"""Merge keys and values from dict d into this model, overwriting as necessary."""
|
|
14
|
-
for key, value in d.items():
|
|
15
|
-
setattr(self, key, value)
|
|
16
|
-
return self
|
|
17
|
-
|
|
18
|
-
def clone(self) -> "BaseORM":
|
|
19
|
-
"""Clones a SQLAlchemy ORM object, excluding primary keys."""
|
|
20
|
-
mapper = self.__mapper__
|
|
21
|
-
new_instance = self.__class__()
|
|
22
|
-
for column in mapper.columns:
|
|
23
|
-
if not column.primary_key:
|
|
24
|
-
setattr(new_instance, column.key, getattr(self, column.key))
|
|
25
|
-
return new_instance
|