endoreg-db 0.5.3__py3-none-any.whl → 0.6.1__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.
Potentially problematic release.
This version of endoreg-db might be problematic. Click here for more details.
- endoreg_db/admin.py +90 -1
- endoreg_db/case_generator/case_generator.py +159 -0
- endoreg_db/case_generator/lab_sample_factory.py +33 -0
- endoreg_db/case_generator/utils.py +30 -0
- endoreg_db/data/__init__.py +50 -4
- endoreg_db/data/ai_model/data.yaml +7 -0
- endoreg_db/data/{label → ai_model_label}/label/data.yaml +27 -1
- endoreg_db/data/ai_model_label/label-set/data.yaml +21 -0
- endoreg_db/data/ai_model_meta/default_multilabel_classification.yaml +5 -0
- endoreg_db/data/ai_model_video_segmentation_label/base_segmentation.yaml +176 -0
- endoreg_db/data/ai_model_video_segmentation_labelset/data.yaml +20 -0
- endoreg_db/data/center/data.yaml +35 -5
- endoreg_db/data/contraindication/bleeding.yaml +11 -0
- endoreg_db/data/distribution/numeric/data.yaml +14 -0
- endoreg_db/data/endoscope/data.yaml +93 -0
- endoreg_db/data/examination_indication/endoscopy.yaml +8 -0
- endoreg_db/data/examination_indication_classification/endoscopy.yaml +8 -0
- endoreg_db/data/examination_indication_classification_choice/endoscopy.yaml +101 -0
- endoreg_db/data/finding/data.yaml +141 -0
- endoreg_db/data/finding_intervention/endoscopy.yaml +138 -0
- endoreg_db/data/finding_intervention_type/endoscopy.yaml +15 -0
- endoreg_db/data/finding_location_classification/colonoscopy.yaml +46 -0
- endoreg_db/data/finding_location_classification_choice/colonoscopy.yaml +240 -0
- endoreg_db/data/finding_morphology_classification/colonoscopy.yaml +48 -0
- endoreg_db/data/finding_morphology_classification_choice/colon_lesion_circularity_default.yaml +34 -0
- endoreg_db/data/finding_morphology_classification_choice/colon_lesion_nice.yaml +20 -0
- endoreg_db/data/finding_morphology_classification_choice/colon_lesion_paris.yaml +65 -0
- endoreg_db/data/finding_morphology_classification_choice/colon_lesion_planarity_default.yaml +56 -0
- endoreg_db/data/finding_morphology_classification_choice/colon_lesion_surface_intact_default.yaml +39 -0
- endoreg_db/data/finding_morphology_classification_choice/colonoscopy_size.yaml +57 -0
- endoreg_db/data/finding_morphology_classification_type/colonoscopy.yaml +79 -0
- endoreg_db/data/finding_type/data.yaml +30 -0
- endoreg_db/data/gender/data.yaml +17 -0
- endoreg_db/data/lab_value/cardiac_enzymes.yaml +7 -1
- endoreg_db/data/lab_value/coagulation.yaml +6 -1
- endoreg_db/data/lab_value/electrolytes.yaml +39 -1
- endoreg_db/data/lab_value/gastrointestinal_function.yaml +12 -0
- endoreg_db/data/lab_value/hematology.yaml +17 -2
- endoreg_db/data/lab_value/hormones.yaml +6 -0
- endoreg_db/data/lab_value/lipids.yaml +12 -3
- endoreg_db/data/lab_value/misc.yaml +5 -2
- endoreg_db/data/lab_value/renal_function.yaml +2 -1
- endoreg_db/data/lx_client_tag/base.yaml +54 -0
- endoreg_db/data/lx_client_type/base.yaml +30 -0
- endoreg_db/data/lx_permission/base.yaml +24 -0
- endoreg_db/data/lx_permission/endoreg.yaml +52 -0
- endoreg_db/data/medication_indication/anticoagulation.yaml +44 -49
- endoreg_db/data/names_first/first_names.yaml +51 -0
- endoreg_db/data/names_last/last_names.yaml +51 -0
- endoreg_db/data/network_device/data.yaml +30 -0
- endoreg_db/data/organ/data.yaml +29 -0
- endoreg_db/data/pdf_type/data.yaml +2 -1
- endoreg_db/data/report_reader_flag/ukw-examination-generic.yaml +4 -0
- endoreg_db/forms/__init__.py +3 -1
- endoreg_db/forms/examination_form.py +11 -0
- endoreg_db/forms/patient_finding_intervention_form.py +19 -0
- endoreg_db/forms/patient_form.py +26 -0
- endoreg_db/management/commands/__init__.py +0 -0
- endoreg_db/management/commands/load_ai_model_data.py +57 -23
- endoreg_db/management/commands/load_ai_model_label_data.py +59 -0
- endoreg_db/management/commands/load_base_db_data.py +160 -118
- endoreg_db/management/commands/{load_endoscope_type_data.py → load_contraindication_data.py} +3 -7
- endoreg_db/management/commands/load_disease_data.py +29 -7
- endoreg_db/management/commands/load_endoscope_data.py +68 -0
- endoreg_db/management/commands/load_examination_indication_data.py +65 -0
- endoreg_db/management/commands/load_finding_data.py +171 -0
- endoreg_db/management/commands/load_lab_value_data.py +3 -3
- endoreg_db/management/commands/load_lx_data.py +64 -0
- endoreg_db/management/commands/load_medication_data.py +83 -21
- endoreg_db/management/commands/load_name_data.py +37 -0
- endoreg_db/management/commands/{load_endoscopy_processor_data.py → load_organ_data.py} +7 -9
- endoreg_db/migrations/0001_initial.py +1206 -728
- endoreg_db/migrations/0002_alter_frame_image_alter_rawframe_image.py +23 -0
- endoreg_db/migrations/0003_alter_frame_image_alter_rawframe_image.py +23 -0
- endoreg_db/migrations/0004_alter_rawvideofile_file_alter_video_file.py +25 -0
- endoreg_db/migrations/0005_rawvideofile_frame_count_and_more.py +33 -0
- endoreg_db/migrations/0006_frame_extracted_rawframe_extracted.py +23 -0
- endoreg_db/migrations/0007_rename_pseudo_patient_video_patient_and_more.py +24 -0
- endoreg_db/migrations/0008_remove_reportfile_patient_examination_and_more.py +48 -0
- endoreg_db/models/__init__.py +331 -28
- endoreg_db/models/ai_model/__init__.py +1 -0
- endoreg_db/models/ai_model/ai_model.py +103 -0
- endoreg_db/models/ai_model/lightning/__init__.py +3 -0
- endoreg_db/models/ai_model/lightning/inference_dataset.py +53 -0
- endoreg_db/models/ai_model/lightning/multilabel_classification_net.py +155 -0
- endoreg_db/models/ai_model/lightning/postprocess.py +53 -0
- endoreg_db/models/ai_model/lightning/predict.py +172 -0
- endoreg_db/models/ai_model/lightning/prediction_visualizer.py +55 -0
- endoreg_db/models/ai_model/lightning/preprocess.py +68 -0
- endoreg_db/models/ai_model/lightning/run_visualizer.py +21 -0
- endoreg_db/models/ai_model/model_meta.py +232 -6
- endoreg_db/models/ai_model/model_type.py +13 -3
- endoreg_db/models/annotation/__init__.py +31 -2
- endoreg_db/models/annotation/anonymized_image_annotation.py +73 -18
- endoreg_db/models/annotation/binary_classification_annotation_task.py +94 -57
- endoreg_db/models/annotation/image_classification.py +73 -14
- endoreg_db/models/annotation/video_segmentation_annotation.py +52 -0
- endoreg_db/models/annotation/video_segmentation_labelset.py +20 -0
- endoreg_db/models/case/__init__.py +1 -0
- endoreg_db/models/{persons/patient/case → case}/case.py +4 -0
- endoreg_db/models/case_template/__init__.py +10 -1
- endoreg_db/models/case_template/case_template.py +57 -13
- endoreg_db/models/case_template/case_template_rule.py +5 -5
- endoreg_db/models/case_template/case_template_rule_value.py +19 -4
- endoreg_db/models/center/__init__.py +7 -0
- endoreg_db/models/center/center.py +31 -5
- endoreg_db/models/center/center_product.py +0 -1
- endoreg_db/models/center/center_resource.py +16 -2
- endoreg_db/models/center/center_waste.py +6 -1
- endoreg_db/models/contraindication/__init__.py +21 -0
- endoreg_db/models/data_file/__init__.py +38 -5
- endoreg_db/models/data_file/base_classes/__init__.py +6 -1
- endoreg_db/models/data_file/base_classes/abstract_frame.py +64 -15
- endoreg_db/models/data_file/base_classes/abstract_pdf.py +136 -0
- endoreg_db/models/data_file/base_classes/abstract_video.py +744 -138
- endoreg_db/models/data_file/base_classes/frame_helpers.py +17 -0
- endoreg_db/models/data_file/base_classes/prepare_bulk_frames.py +19 -0
- endoreg_db/models/data_file/base_classes/utils.py +80 -0
- endoreg_db/models/data_file/frame.py +22 -38
- endoreg_db/models/data_file/import_classes/__init__.py +4 -18
- endoreg_db/models/data_file/import_classes/raw_pdf.py +162 -90
- endoreg_db/models/data_file/import_classes/raw_video.py +239 -294
- endoreg_db/models/data_file/metadata/__init__.py +10 -0
- endoreg_db/models/data_file/metadata/pdf_meta.py +4 -0
- endoreg_db/models/data_file/metadata/sensitive_meta.py +265 -6
- endoreg_db/models/data_file/metadata/video_meta.py +116 -50
- endoreg_db/models/data_file/report_file.py +30 -63
- endoreg_db/models/data_file/video/__init__.py +6 -2
- endoreg_db/models/data_file/video/video.py +187 -16
- endoreg_db/models/data_file/video_segment.py +162 -55
- endoreg_db/models/disease.py +25 -2
- endoreg_db/models/emission/__init__.py +5 -1
- endoreg_db/models/emission/emission_factor.py +71 -6
- endoreg_db/models/event.py +51 -0
- endoreg_db/models/examination/__init__.py +6 -1
- endoreg_db/models/examination/examination.py +53 -12
- endoreg_db/models/examination/examination_indication.py +170 -0
- endoreg_db/models/examination/examination_time.py +31 -5
- endoreg_db/models/examination/examination_time_type.py +28 -4
- endoreg_db/models/examination/examination_type.py +28 -6
- endoreg_db/models/finding/__init__.py +11 -0
- endoreg_db/models/finding/finding.py +75 -0
- endoreg_db/models/finding/finding_intervention.py +60 -0
- endoreg_db/models/finding/finding_location_classification.py +94 -0
- endoreg_db/models/finding/finding_morphology_classification.py +89 -0
- endoreg_db/models/finding/finding_type.py +22 -0
- endoreg_db/models/hardware/endoscope.py +16 -0
- endoreg_db/models/hardware/endoscopy_processor.py +31 -19
- endoreg_db/models/label/label.py +35 -7
- endoreg_db/models/laboratory/lab_value.py +12 -3
- endoreg_db/models/logging/__init__.py +8 -1
- endoreg_db/models/lx/__init__.py +4 -0
- endoreg_db/models/lx/client.py +57 -0
- endoreg_db/models/lx/identity.py +34 -0
- endoreg_db/models/lx/permission.py +18 -0
- endoreg_db/models/lx/user.py +16 -0
- endoreg_db/models/medication/__init__.py +19 -1
- endoreg_db/models/medication/medication.py +7 -122
- endoreg_db/models/medication/medication_indication.py +50 -0
- endoreg_db/models/medication/medication_indication_type.py +34 -0
- endoreg_db/models/medication/medication_intake_time.py +26 -0
- endoreg_db/models/medication/medication_schedule.py +37 -0
- endoreg_db/models/network/__init__.py +7 -1
- endoreg_db/models/network/network_device.py +13 -8
- endoreg_db/models/organ/__init__.py +38 -0
- endoreg_db/models/other/__init__.py +19 -1
- endoreg_db/models/other/distribution/__init__.py +44 -0
- endoreg_db/models/other/distribution/base_value_distribution.py +20 -0
- endoreg_db/models/other/distribution/date_value_distribution.py +91 -0
- endoreg_db/models/other/distribution/multiple_categorical_value_distribution.py +32 -0
- endoreg_db/models/other/distribution/numeric_value_distribution.py +97 -0
- endoreg_db/models/other/distribution/single_categorical_value_distribution.py +22 -0
- endoreg_db/models/other/distribution.py +1 -211
- endoreg_db/models/other/material.py +4 -0
- endoreg_db/models/other/transport_route.py +2 -1
- endoreg_db/models/patient/__init__.py +24 -0
- endoreg_db/models/patient/patient_examination.py +182 -0
- endoreg_db/models/patient/patient_finding.py +143 -0
- endoreg_db/models/patient/patient_finding_intervention.py +26 -0
- endoreg_db/models/patient/patient_finding_location.py +120 -0
- endoreg_db/models/patient/patient_finding_morphology.py +166 -0
- endoreg_db/models/persons/__init__.py +29 -2
- endoreg_db/models/persons/examiner/examiner.py +48 -4
- endoreg_db/models/persons/patient/__init__.py +1 -1
- endoreg_db/models/persons/patient/patient.py +227 -54
- endoreg_db/models/persons/patient/patient_disease.py +6 -0
- endoreg_db/models/persons/patient/patient_event.py +31 -1
- endoreg_db/models/persons/patient/patient_examination_indication.py +32 -0
- endoreg_db/models/persons/patient/patient_lab_sample.py +4 -2
- endoreg_db/models/persons/patient/patient_lab_value.py +37 -16
- endoreg_db/models/persons/patient/patient_medication.py +27 -12
- endoreg_db/models/persons/patient/patient_medication_schedule.py +62 -2
- endoreg_db/models/prediction/__init__.py +7 -1
- endoreg_db/models/prediction/image_classification.py +20 -6
- endoreg_db/models/prediction/video_prediction_meta.py +151 -89
- endoreg_db/models/product/__init__.py +10 -1
- endoreg_db/models/product/product.py +15 -2
- endoreg_db/models/product/product_group.py +8 -0
- endoreg_db/models/product/product_material.py +4 -0
- endoreg_db/models/product/product_weight.py +12 -0
- endoreg_db/models/product/reference_product.py +19 -3
- endoreg_db/models/quiz/__init__.py +8 -1
- endoreg_db/models/report_reader/__init__.py +6 -1
- endoreg_db/serializers/__init__.py +1 -1
- endoreg_db/serializers/annotation.py +2 -5
- endoreg_db/serializers/frame.py +1 -5
- endoreg_db/serializers/patient.py +26 -3
- endoreg_db/serializers/prediction.py +2 -7
- endoreg_db/serializers/raw_video_meta_validation.py +13 -0
- endoreg_db/serializers/video.py +6 -13
- endoreg_db/serializers/video_segmentation.py +492 -0
- endoreg_db/templates/admin/patient_finding_intervention.html +253 -0
- endoreg_db/templates/admin/start_examination.html +12 -0
- endoreg_db/templates/timeline.html +176 -0
- endoreg_db/urls.py +173 -0
- endoreg_db/utils/__init__.py +36 -1
- endoreg_db/utils/dataloader.py +45 -19
- endoreg_db/utils/dates.py +39 -0
- endoreg_db/utils/hashs.py +122 -4
- endoreg_db/utils/names.py +74 -0
- endoreg_db/utils/parse_and_generate_yaml.py +46 -0
- endoreg_db/utils/pydantic_models/__init__.py +6 -0
- endoreg_db/utils/pydantic_models/db_config.py +57 -0
- endoreg_db/utils/validate_endo_roi.py +19 -0
- endoreg_db/utils/validate_subcategory_dict.py +91 -0
- endoreg_db/utils/video/__init__.py +13 -0
- endoreg_db/utils/video/extract_frames.py +121 -0
- endoreg_db/utils/video/transcode_videofile.py +111 -0
- endoreg_db/views/__init__.py +2 -0
- endoreg_db/views/csrf.py +7 -0
- endoreg_db/views/patient_views.py +90 -0
- endoreg_db/views/raw_video_meta_validation_views.py +38 -0
- endoreg_db/views/report_views.py +96 -0
- endoreg_db/views/video_segmentation_views.py +149 -0
- endoreg_db/views/views_for_timeline.py +46 -0
- endoreg_db/views.py +0 -3
- endoreg_db-0.6.1.dist-info/METADATA +151 -0
- endoreg_db-0.6.1.dist-info/RECORD +420 -0
- {endoreg_db-0.5.3.dist-info → endoreg_db-0.6.1.dist-info}/WHEEL +1 -1
- endoreg_db/data/active_model/data.yaml +0 -3
- endoreg_db/data/label/label-set/data.yaml +0 -18
- endoreg_db/management/commands/delete_legacy_images.py +0 -19
- endoreg_db/management/commands/delete_legacy_videos.py +0 -17
- endoreg_db/management/commands/extract_legacy_video_frames.py +0 -18
- endoreg_db/management/commands/import_legacy_images.py +0 -94
- endoreg_db/management/commands/import_legacy_videos.py +0 -76
- endoreg_db/management/commands/load_label_data.py +0 -67
- endoreg_db/migrations/0002_anonymizedimagelabel_anonymousimageannotation_and_more.py +0 -55
- endoreg_db/migrations/0003_anonymousimageannotation_original_image_url_and_more.py +0 -39
- endoreg_db/migrations/0004_alter_rawpdffile_file.py +0 -20
- endoreg_db/migrations/0005_uploadedfile_alter_rawpdffile_file_anonymizedfile.py +0 -40
- endoreg_db/migrations/0006_alter_rawpdffile_file.py +0 -20
- endoreg_db/migrations/0007_networkdevicelogentry_datetime_and_more.py +0 -43
- endoreg_db/migrations/0008_networkdevicelogentry_aglnet_ip_and_more.py +0 -28
- endoreg_db/migrations/0009_alter_networkdevicelogentry_vpn_service_status.py +0 -18
- endoreg_db/migrations/0010_remove_networkdevicelogentry_hostname.py +0 -17
- endoreg_db/models/legacy_data/__init__.py +0 -3
- endoreg_db/models/legacy_data/image.py +0 -34
- endoreg_db/models/patient_examination/__init__.py +0 -35
- endoreg_db/utils/video_metadata.py +0 -87
- endoreg_db-0.5.3.dist-info/METADATA +0 -28
- endoreg_db-0.5.3.dist-info/RECORD +0 -319
- /endoreg_db/{models/persons/patient/case → case_generator}/__init__.py +0 -0
- /endoreg_db/data/{label → ai_model_label}/label-type/data.yaml +0 -0
- /endoreg_db/data/{model_type → ai_model_type}/data.yaml +0 -0
- /endoreg_db/{data/distribution/numeric/.init → management/__init__.py} +0 -0
- /endoreg_db/management/commands/{load_report_reader_flag.py → load_report_reader_flag_data.py} +0 -0
- {endoreg_db-0.5.3.dist-info → endoreg_db-0.6.1.dist-info}/licenses/LICENSE +0 -0
endoreg_db/utils/dataloader.py
CHANGED
|
@@ -2,10 +2,13 @@ import os
|
|
|
2
2
|
import yaml
|
|
3
3
|
from django.core.exceptions import ObjectDoesNotExist
|
|
4
4
|
|
|
5
|
+
from icecream import ic
|
|
6
|
+
|
|
7
|
+
|
|
5
8
|
def load_model_data_from_yaml(command, model_name, metadata, verbose):
|
|
6
9
|
"""
|
|
7
10
|
Load model data from YAML files.
|
|
8
|
-
|
|
11
|
+
|
|
9
12
|
Args:
|
|
10
13
|
command: Command object for stdout writing.
|
|
11
14
|
model_name: Name of the model being loaded.
|
|
@@ -19,19 +22,24 @@ def load_model_data_from_yaml(command, model_name, metadata, verbose):
|
|
|
19
22
|
foreign_keys = metadata["foreign_keys"]
|
|
20
23
|
foreign_key_models = metadata["foreign_key_models"]
|
|
21
24
|
|
|
22
|
-
_files = [f for f in os.listdir(dir_path) if f.endswith(
|
|
25
|
+
_files = [f for f in os.listdir(dir_path) if f.endswith(".yaml")]
|
|
23
26
|
# sort
|
|
24
27
|
_files.sort()
|
|
25
28
|
for file in _files:
|
|
26
|
-
with open(os.path.join(dir_path, file),
|
|
29
|
+
with open(os.path.join(dir_path, file), "r", encoding="utf-8") as file:
|
|
27
30
|
yaml_data = yaml.safe_load(file)
|
|
28
|
-
|
|
29
|
-
load_data_with_foreign_keys(command, model, yaml_data, foreign_keys, foreign_key_models, verbose)
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
load_data_with_foreign_keys(
|
|
33
|
+
command, model, yaml_data, foreign_keys, foreign_key_models, verbose
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def load_data_with_foreign_keys(
|
|
38
|
+
command, model, yaml_data, foreign_keys, foreign_key_models, verbose
|
|
39
|
+
):
|
|
32
40
|
"""
|
|
33
41
|
Load data handling foreign keys and many-to-many relationships.
|
|
34
|
-
|
|
42
|
+
|
|
35
43
|
Args:
|
|
36
44
|
command: Command object for stdout writing.
|
|
37
45
|
model: The Django model for the data.
|
|
@@ -41,20 +49,24 @@ def load_data_with_foreign_keys(command, model, yaml_data, foreign_keys, foreign
|
|
|
41
49
|
verbose: Boolean indicating whether to print verbose output.
|
|
42
50
|
"""
|
|
43
51
|
for entry in yaml_data:
|
|
44
|
-
fields = entry.get(
|
|
45
|
-
name = fields.pop(
|
|
52
|
+
fields = entry.get("fields", {})
|
|
53
|
+
name = fields.pop("name", None)
|
|
46
54
|
m2m_relationships = {} # Store many-to-many relationships
|
|
47
|
-
print(entry)
|
|
55
|
+
# print(entry)
|
|
48
56
|
|
|
49
57
|
# Handle foreign keys and many-to-many relationships
|
|
50
58
|
for fk_field, fk_model in zip(foreign_keys, foreign_key_models):
|
|
51
|
-
print(fk_field, fk_model)
|
|
59
|
+
# print(fk_field, fk_model)
|
|
52
60
|
target_keys = fields.pop(fk_field, None)
|
|
53
|
-
|
|
61
|
+
|
|
54
62
|
# Ensure the foreign key exists
|
|
55
63
|
if target_keys is None:
|
|
56
64
|
if verbose:
|
|
57
|
-
command.stdout.write(
|
|
65
|
+
command.stdout.write(
|
|
66
|
+
command.style.WARNING(
|
|
67
|
+
f"Foreign key {fk_field} not found in fields"
|
|
68
|
+
)
|
|
69
|
+
)
|
|
58
70
|
continue # Skip if no foreign key provided
|
|
59
71
|
|
|
60
72
|
# Process many-to-many fields or foreign keys
|
|
@@ -63,29 +75,43 @@ def load_data_with_foreign_keys(command, model, yaml_data, foreign_keys, foreign
|
|
|
63
75
|
for key in target_keys:
|
|
64
76
|
obj, created = fk_model.objects.get_or_create(name=key)
|
|
65
77
|
if created and verbose:
|
|
66
|
-
command.stdout.write(
|
|
78
|
+
command.stdout.write(
|
|
79
|
+
command.style.SUCCESS(f"Created {fk_model.__name__} {key}")
|
|
80
|
+
)
|
|
67
81
|
related_objects.append(obj)
|
|
68
82
|
m2m_relationships[fk_field] = related_objects
|
|
69
83
|
else: # Single foreign key relationship
|
|
70
84
|
try:
|
|
71
85
|
if model == "endoreg_db.case_template_rule":
|
|
72
|
-
print(fk_model, target_keys)
|
|
86
|
+
# print(fk_model, target_keys)
|
|
87
|
+
pass
|
|
73
88
|
obj = fk_model.objects.get_by_natural_key(target_keys)
|
|
74
89
|
except ObjectDoesNotExist:
|
|
75
90
|
if verbose:
|
|
76
|
-
command.stdout.write(
|
|
91
|
+
command.stdout.write(
|
|
92
|
+
command.style.WARNING(
|
|
93
|
+
f"{fk_model.__name__} with key {target_keys} not found"
|
|
94
|
+
)
|
|
95
|
+
)
|
|
77
96
|
continue
|
|
78
97
|
fields[fk_field] = obj
|
|
79
|
-
|
|
98
|
+
|
|
80
99
|
# Create or update the main object
|
|
81
100
|
if name is None:
|
|
82
101
|
obj, created = model.objects.get_or_create(**fields)
|
|
83
102
|
else:
|
|
84
103
|
obj, created = model.objects.update_or_create(defaults=fields, name=name)
|
|
85
104
|
if created and verbose:
|
|
86
|
-
command.stdout.write(
|
|
105
|
+
command.stdout.write(
|
|
106
|
+
command.style.SUCCESS(f"Created {model.__name__} {name}")
|
|
107
|
+
)
|
|
87
108
|
elif verbose:
|
|
88
|
-
|
|
109
|
+
pass
|
|
110
|
+
# command.stdout.write(
|
|
111
|
+
# command.style.WARNING(
|
|
112
|
+
# f"Skipped {model.__name__} {name}, already exists"
|
|
113
|
+
# )
|
|
114
|
+
# )
|
|
89
115
|
|
|
90
116
|
# Set many-to-many relationships
|
|
91
117
|
for field_name, related_objs in m2m_relationships.items():
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from datetime import datetime, date, timedelta
|
|
2
|
+
from random import randint
|
|
3
|
+
from calendar import monthrange
|
|
4
|
+
|
|
5
|
+
# TODO replace used random_day_by_year function implementation when
|
|
6
|
+
# creating pseudo patients with new function "random date by age_at_date and examination_date"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def random_day_by_age_at_date(age_at_date: int, examination_date: date) -> date:
|
|
10
|
+
"""
|
|
11
|
+
Return a random birth day for a patient with the specified age at the specified examination date.
|
|
12
|
+
"""
|
|
13
|
+
examination_year = examination_date.year
|
|
14
|
+
latest_birthdate = examination_date.replace(year=examination_year - age_at_date)
|
|
15
|
+
valid_dates = [latest_birthdate - timedelta(days=i) for i in range(365)]
|
|
16
|
+
|
|
17
|
+
select = randint(0, len(valid_dates) - 1)
|
|
18
|
+
birth_date = valid_dates[select]
|
|
19
|
+
|
|
20
|
+
return birth_date
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def random_day_by_year(year: int) -> date:
|
|
24
|
+
"""
|
|
25
|
+
Return a random birth day within the specified year.
|
|
26
|
+
"""
|
|
27
|
+
month = randint(1, 12)
|
|
28
|
+
day = randint(1, monthrange(year, month)[1])
|
|
29
|
+
|
|
30
|
+
return date(year, month, day)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def random_day_by_month_year(month: int, year) -> date:
|
|
34
|
+
"""
|
|
35
|
+
Return a random birth day within the specified month and year.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
day = randint(1, monthrange(year, month)[1])
|
|
39
|
+
return date(year, month, day)
|
endoreg_db/utils/hashs.py
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import hashlib
|
|
2
2
|
from pathlib import Path
|
|
3
|
+
from datetime import datetime, date
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
SALT = os.getenv("DJANGO_SALT", "default_salt")
|
|
8
|
+
|
|
3
9
|
|
|
4
10
|
def get_video_hash(video_path):
|
|
5
11
|
"""
|
|
6
12
|
Get the hash of a video file.
|
|
7
13
|
"""
|
|
8
14
|
# Open the video file in read-binary mode:
|
|
9
|
-
with open(video_path,
|
|
15
|
+
with open(video_path, "rb") as f:
|
|
10
16
|
# Create the hash object, passing in the video contents for hashing:
|
|
11
17
|
hash_object = hashlib.sha256(f.read())
|
|
12
18
|
# Get the hexadecimal representation of the hash
|
|
@@ -15,14 +21,15 @@ def get_video_hash(video_path):
|
|
|
15
21
|
|
|
16
22
|
return video_hash
|
|
17
23
|
|
|
18
|
-
|
|
24
|
+
|
|
25
|
+
def get_pdf_hash(pdf_path: Path):
|
|
19
26
|
"""
|
|
20
27
|
Get the hash of a pdf file.
|
|
21
28
|
"""
|
|
22
29
|
pdf_hash = None
|
|
23
30
|
|
|
24
31
|
# Open the file in binary mode and read its contents
|
|
25
|
-
with open(pdf_path,
|
|
32
|
+
with open(pdf_path, "rb") as f:
|
|
26
33
|
pdf_contents = f.read()
|
|
27
34
|
# Create a hash object using SHA-256 algorithm
|
|
28
35
|
|
|
@@ -31,4 +38,115 @@ def get_pdf_hash(pdf_path:Path):
|
|
|
31
38
|
pdf_hash = hash_object.hexdigest()
|
|
32
39
|
assert len(pdf_hash) <= 255, "Hash length exceeds 255 characters"
|
|
33
40
|
|
|
34
|
-
return pdf_hash
|
|
41
|
+
return pdf_hash
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _get_date_hash_string(date_obj: date) -> str:
|
|
45
|
+
# if date is datetime object, convert to date
|
|
46
|
+
if isinstance(date_obj, datetime):
|
|
47
|
+
# warnings.warn("Date is a datetime object. Converting to date object.")
|
|
48
|
+
date_obj = date_obj.date()
|
|
49
|
+
elif isinstance(date_obj, str):
|
|
50
|
+
# warnings.warn(f"Date is a string ({date_obj}). Converting to date object.")
|
|
51
|
+
date_obj = datetime.strptime(date_obj, "%Y-%m-%d").date()
|
|
52
|
+
|
|
53
|
+
assert isinstance(date_obj, date), "Date must be a date object"
|
|
54
|
+
# if date is 1900-01-01, make it an empty string
|
|
55
|
+
if date_obj == date(1900, 1, 1):
|
|
56
|
+
date_str = ""
|
|
57
|
+
else:
|
|
58
|
+
date_str = date_obj.strftime("%Y-%m-%d")
|
|
59
|
+
|
|
60
|
+
return date_str
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def get_hash_string(
|
|
64
|
+
first_name: str = "",
|
|
65
|
+
last_name: str = "",
|
|
66
|
+
dob: date = date(1900, 1, 1),
|
|
67
|
+
center_name: str = "",
|
|
68
|
+
examination_date: date = date(1900, 1, 1),
|
|
69
|
+
endoscope_sn: str = "",
|
|
70
|
+
salt: str = "",
|
|
71
|
+
):
|
|
72
|
+
"""
|
|
73
|
+
Get the string to be hashed for a patient's first name, last name, date of birth, examination date, and endoscope serial number.
|
|
74
|
+
"""
|
|
75
|
+
if not salt:
|
|
76
|
+
salt = SALT
|
|
77
|
+
|
|
78
|
+
examination_date_str = _get_date_hash_string(examination_date)
|
|
79
|
+
dob_str = _get_date_hash_string(dob)
|
|
80
|
+
|
|
81
|
+
# Concatenate the patient's first name, last name, date of birth, examination date, endoscope serial number, and salt:
|
|
82
|
+
hash_str = f"{first_name}{last_name}{dob_str}{center_name}{dob_str}{examination_date_str}{endoscope_sn}{salt}"
|
|
83
|
+
return hash_str
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def get_patient_hash(
|
|
87
|
+
first_name: str, last_name: str, dob: date, center: str, salt: str = ""
|
|
88
|
+
):
|
|
89
|
+
"""
|
|
90
|
+
Get the hash of a patient's first name, last name, and date of birth.
|
|
91
|
+
"""
|
|
92
|
+
# Concatenate the patient's first name, last name, date of birth, and salt:
|
|
93
|
+
hash_str = get_hash_string(
|
|
94
|
+
first_name=first_name,
|
|
95
|
+
last_name=last_name,
|
|
96
|
+
dob=dob,
|
|
97
|
+
center_name=center,
|
|
98
|
+
salt=salt,
|
|
99
|
+
)
|
|
100
|
+
# Create a hash object using SHA-256 algorithm
|
|
101
|
+
hash_object = hashlib.sha256(hash_str.encode())
|
|
102
|
+
# Get the hexadecimal representation of the hash
|
|
103
|
+
patient_hash = hash_object.hexdigest()
|
|
104
|
+
|
|
105
|
+
return patient_hash
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def get_patient_examination_hash(
|
|
109
|
+
first_name: str,
|
|
110
|
+
last_name: str,
|
|
111
|
+
dob: date,
|
|
112
|
+
center: str,
|
|
113
|
+
examination_date: date,
|
|
114
|
+
salt: str = "",
|
|
115
|
+
):
|
|
116
|
+
"""
|
|
117
|
+
Get the hash of a patient's first name, last name, date of birth, and examination date.
|
|
118
|
+
"""
|
|
119
|
+
# Concatenate the patient's first name, last name, date of birth, examination date, and salt:
|
|
120
|
+
hash_str = get_hash_string(
|
|
121
|
+
first_name=first_name,
|
|
122
|
+
last_name=last_name,
|
|
123
|
+
center_name=center,
|
|
124
|
+
dob=dob,
|
|
125
|
+
examination_date=examination_date,
|
|
126
|
+
salt=salt,
|
|
127
|
+
)
|
|
128
|
+
# Create a hash object using SHA-256 algorithm
|
|
129
|
+
hash_object = hashlib.sha256(hash_str.encode())
|
|
130
|
+
# Get the hexadecimal representation of the hash
|
|
131
|
+
patient_examination_hash = hash_object.hexdigest()
|
|
132
|
+
|
|
133
|
+
return patient_examination_hash
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def get_examiner_hash(first_name, last_name, center_name, salt):
|
|
137
|
+
"""
|
|
138
|
+
Get the hash of an examiner's first name, last name, and center name.
|
|
139
|
+
"""
|
|
140
|
+
# Concatenate the examiner's first name, last name, center name, and salt:
|
|
141
|
+
hash_str = get_hash_string(
|
|
142
|
+
first_name=first_name,
|
|
143
|
+
last_name=last_name,
|
|
144
|
+
center_name=center_name,
|
|
145
|
+
salt=salt,
|
|
146
|
+
)
|
|
147
|
+
# Create a hash object using SHA-256 algorithm
|
|
148
|
+
hash_object = hashlib.sha256(hash_str.encode())
|
|
149
|
+
# Get the hexadecimal representation of the hash
|
|
150
|
+
examiner_hash = hash_object.hexdigest()
|
|
151
|
+
|
|
152
|
+
return examiner_hash
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Use faker library to generate fake names by gender
|
|
2
|
+
# Use german names by default
|
|
3
|
+
|
|
4
|
+
from faker import Faker
|
|
5
|
+
import gender_guesser.detector as gender_detector
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def create_mock_examiner_name() -> tuple[str, str]:
|
|
9
|
+
"""
|
|
10
|
+
Generate a mock examiner's name using the Faker library.
|
|
11
|
+
This function creates a tuple with a first name and a last name for a mock examiner. It utilizes the "de_DE" locale for generating German names.
|
|
12
|
+
Returns:
|
|
13
|
+
tuple[str, str]: A tuple containing the first name and the last name.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
fake = Faker("de_DE")
|
|
17
|
+
first_name = fake.first_name()
|
|
18
|
+
last_name = fake.last_name()
|
|
19
|
+
return first_name, last_name
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def create_mock_patient_name(gender: str) -> tuple[str, str]:
|
|
23
|
+
"""
|
|
24
|
+
Generate a mock patient's name based on the provided gender using the Faker library.
|
|
25
|
+
This function creates a tuple with a first name and a last name for a mock patient. It utilizes the "de_DE" locale for generating German names. When the input gender string is checked:
|
|
26
|
+
- If it contains "male", a male name is generated.
|
|
27
|
+
- If it contains "female", a female name is generated.
|
|
28
|
+
- Otherwise, a generic name is generated without considering gender.
|
|
29
|
+
Parameters:
|
|
30
|
+
gender (str): A string indicating the gender to be used for generating the name.
|
|
31
|
+
Returns:
|
|
32
|
+
tuple[str, str]: A tuple containing the first name and the last name.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
fake = Faker("de_DE")
|
|
36
|
+
|
|
37
|
+
if "male" in gender.lower():
|
|
38
|
+
gender = "male"
|
|
39
|
+
elif "female" in gender.lower():
|
|
40
|
+
gender = "female"
|
|
41
|
+
|
|
42
|
+
if gender == "male":
|
|
43
|
+
first_name = fake.first_name_male()
|
|
44
|
+
last_name = fake.last_name_male()
|
|
45
|
+
|
|
46
|
+
elif gender == "female":
|
|
47
|
+
first_name = fake.first_name_female()
|
|
48
|
+
last_name = fake.last_name_female()
|
|
49
|
+
|
|
50
|
+
else:
|
|
51
|
+
first_name = fake.first_name()
|
|
52
|
+
last_name = fake.last_name()
|
|
53
|
+
|
|
54
|
+
return first_name, last_name
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def guess_name_gender(name: str) -> str:
|
|
58
|
+
"""
|
|
59
|
+
Guesses the gender for a given name by using a gender detector and retrieving the corresponding Gender model instance.
|
|
60
|
+
Parameters:
|
|
61
|
+
name (str): The name for which the gender is to be determined.
|
|
62
|
+
Returns:
|
|
63
|
+
Gender: The Gender object corresponding to the detected gender name.
|
|
64
|
+
Raises:
|
|
65
|
+
Gender.DoesNotExist: If no Gender object matching the detected gender is found.
|
|
66
|
+
Exception: For any other exceptions that occur during gender detection or database lookup.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
from endoreg_db.models import Gender
|
|
70
|
+
|
|
71
|
+
detector = gender_detector.Detector(case_sensitive=False)
|
|
72
|
+
gender_name = detector.get_gender(name)
|
|
73
|
+
gender = Gender.objects.get(name=gender_name)
|
|
74
|
+
return gender
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import yaml
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
# get this files path
|
|
5
|
+
file_path = Path(__file__)
|
|
6
|
+
module_root = file_path.parent.parent
|
|
7
|
+
data_dir = module_root / "data"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def collect_center_names(
|
|
11
|
+
):
|
|
12
|
+
input_file_path = data_dir / "center/data.yaml"
|
|
13
|
+
fist_name_dir = data_dir / "names_first"
|
|
14
|
+
last_name_dir = data_dir / "names_last"
|
|
15
|
+
# Load the input YAML file
|
|
16
|
+
with open(input_file_path, 'r', encoding='utf-8') as file:
|
|
17
|
+
data = yaml.safe_load(file)
|
|
18
|
+
|
|
19
|
+
# Containers for first and last names
|
|
20
|
+
first_names_set = set()
|
|
21
|
+
last_names_set = set()
|
|
22
|
+
|
|
23
|
+
# Extract first and last names from the YAML data
|
|
24
|
+
for entry in data:
|
|
25
|
+
fields = entry.get('fields', {})
|
|
26
|
+
first_names_set.update(fields.get('first_names', []))
|
|
27
|
+
last_names_set.update(fields.get('last_names', []))
|
|
28
|
+
|
|
29
|
+
# Create a list of dictionaries for first and last names
|
|
30
|
+
first_names_data = [
|
|
31
|
+
{"model": "endoreg_db.first_name", "fields": {"name": name}}
|
|
32
|
+
for name in sorted(first_names_set)
|
|
33
|
+
]
|
|
34
|
+
last_names_data = [
|
|
35
|
+
{"model": "endoreg_db.last_name", "fields": {"name": name}}
|
|
36
|
+
for name in sorted(last_names_set)
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
# Write the data to separate YAML files
|
|
40
|
+
with open(fist_name_dir/"first_names.yaml", "w", encoding='utf-8') as first_file:
|
|
41
|
+
yaml.dump(first_names_data, first_file, allow_unicode=True, sort_keys=False)
|
|
42
|
+
|
|
43
|
+
with open(last_name_dir/"last_names.yaml", "w", encoding='utf-8') as last_file:
|
|
44
|
+
yaml.dump(last_names_data, last_file, allow_unicode=True, sort_keys=False)
|
|
45
|
+
|
|
46
|
+
# print("Generated first_names.yaml and last_names.yaml successfully.")
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Optional, Union
|
|
3
|
+
import yaml
|
|
4
|
+
from icecream import ic
|
|
5
|
+
from pydantic import BaseModel
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DbConfig(BaseModel):
|
|
9
|
+
"""Database configuration model."""
|
|
10
|
+
|
|
11
|
+
engine: str = "django.db.backends.postgresql"
|
|
12
|
+
host: str
|
|
13
|
+
port: int
|
|
14
|
+
user: str
|
|
15
|
+
password: Optional[str] = None
|
|
16
|
+
password_file: str = "/etc/secrets/vault/SCRT_local_password_maintenance_password"
|
|
17
|
+
name: str
|
|
18
|
+
|
|
19
|
+
# class options should allow for unused excess data
|
|
20
|
+
|
|
21
|
+
@classmethod
|
|
22
|
+
def from_file(cls, path: Union[Path, str]) -> "DbConfig":
|
|
23
|
+
"""Create a DbConfig instance from a YAML configuration file."""
|
|
24
|
+
if isinstance(path, str):
|
|
25
|
+
filepath = Path(path)
|
|
26
|
+
else:
|
|
27
|
+
filepath = path
|
|
28
|
+
assert filepath.exists(), f"Missing Config {filepath}"
|
|
29
|
+
|
|
30
|
+
with open(filepath, "r", encoding="utf-8") as f:
|
|
31
|
+
cfg = yaml.safe_load(f)
|
|
32
|
+
|
|
33
|
+
obj = cls(**cfg)
|
|
34
|
+
|
|
35
|
+
return obj
|
|
36
|
+
|
|
37
|
+
def sync_password(self):
|
|
38
|
+
"""Load the password from the configured password file."""
|
|
39
|
+
with open(self.password_file, "r", encoding="utf-8") as f:
|
|
40
|
+
self.password = f.read().strip()
|
|
41
|
+
|
|
42
|
+
def validate(self):
|
|
43
|
+
"""Fully validate all database configuration fields."""
|
|
44
|
+
self.sync_password()
|
|
45
|
+
|
|
46
|
+
assert self.host, "Missing Host"
|
|
47
|
+
assert self.port, "Missing Port"
|
|
48
|
+
assert self.user, "Missing User"
|
|
49
|
+
assert self.password, "Missing Password"
|
|
50
|
+
assert self.name, "Missing Database"
|
|
51
|
+
|
|
52
|
+
def to_file(self, target: str = "./conf/db.yml", ask_override: bool = True):
|
|
53
|
+
"""Export the configuration to a YAML file."""
|
|
54
|
+
ic(target)
|
|
55
|
+
|
|
56
|
+
with open(target, "w") as f:
|
|
57
|
+
yaml.safe_dump(self.model_dump(), f)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
def validate_endo_roi(endo_roi_dict:dict):
|
|
2
|
+
"""
|
|
3
|
+
Validate endoscope ROI dictionary. The dictionary must have the following
|
|
4
|
+
keys: x, y, width, height. The values must be greater than or equal to 0
|
|
5
|
+
for x and y, and greater than 0 for width and height.
|
|
6
|
+
"""
|
|
7
|
+
for key, value in endo_roi_dict.items():
|
|
8
|
+
if key == "x":
|
|
9
|
+
assert value >= 0, f"Endoscope ROI x value must be greater than or equal to 0. Got {value}"
|
|
10
|
+
elif key == "y":
|
|
11
|
+
assert value >= 0, f"Endoscope ROI y value must be greater than or equal to 0. Got {value}"
|
|
12
|
+
elif key == "width":
|
|
13
|
+
assert value > 0, f"Endoscope ROI width value must be greater than 0. Got {value}"
|
|
14
|
+
elif key == "height":
|
|
15
|
+
assert value > 0, f"Endoscope ROI height value must be greater than 0. Got {value}"
|
|
16
|
+
else:
|
|
17
|
+
raise ValueError(f"Endoscope ROI key {key} not recognized")
|
|
18
|
+
|
|
19
|
+
return True
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
from endoreg_db.models import Unit
|
|
2
|
+
|
|
3
|
+
def validate_subcategory_dict(self, subcategory_dict:dict=None):
|
|
4
|
+
if subcategory_dict is None:
|
|
5
|
+
return False
|
|
6
|
+
|
|
7
|
+
if not isinstance(subcategory_dict, dict):
|
|
8
|
+
return False
|
|
9
|
+
|
|
10
|
+
# check if key choices exists and is a list of strings
|
|
11
|
+
if "choices" not in subcategory_dict:
|
|
12
|
+
return False
|
|
13
|
+
|
|
14
|
+
if not isinstance(subcategory_dict["choices"], list):
|
|
15
|
+
return False
|
|
16
|
+
|
|
17
|
+
for choice in subcategory_dict["choices"]:
|
|
18
|
+
if not isinstance(choice, str):
|
|
19
|
+
return False
|
|
20
|
+
|
|
21
|
+
# check if key default exists and is a string
|
|
22
|
+
if "default" not in subcategory_dict:
|
|
23
|
+
return False
|
|
24
|
+
|
|
25
|
+
if not isinstance(subcategory_dict["default"], str):
|
|
26
|
+
return False
|
|
27
|
+
|
|
28
|
+
# check if default is in choices
|
|
29
|
+
if subcategory_dict["default"] not in subcategory_dict["choices"]:
|
|
30
|
+
return False
|
|
31
|
+
|
|
32
|
+
if not subcategory_dict["required"]:
|
|
33
|
+
return False
|
|
34
|
+
|
|
35
|
+
return True
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def validate_numerical_descriptor(self, numerical_descriptor_dict:dict=None):
|
|
39
|
+
# Check if numerical_descriptor_dict is None
|
|
40
|
+
error_message = ""
|
|
41
|
+
if numerical_descriptor_dict is None:
|
|
42
|
+
error_message = "numerical_descriptor_dict is None"
|
|
43
|
+
return False, error_message
|
|
44
|
+
|
|
45
|
+
# Check if numerical_descriptor_dict is a dictionary
|
|
46
|
+
if not isinstance(numerical_descriptor_dict, dict):
|
|
47
|
+
error_message = "numerical_descriptor_dict is not a dictionary"
|
|
48
|
+
return False, error_message
|
|
49
|
+
|
|
50
|
+
# if key unit exists and is a string and Unit object with that name exists
|
|
51
|
+
if "unit" not in numerical_descriptor_dict:
|
|
52
|
+
error_message = "unit key does not exist in numerical_descriptor_dict"
|
|
53
|
+
return False, error_message
|
|
54
|
+
|
|
55
|
+
elif not isinstance(numerical_descriptor_dict["unit"], str):
|
|
56
|
+
error_message = "unit key is not a string"
|
|
57
|
+
return False, error_message
|
|
58
|
+
|
|
59
|
+
elif not Unit.objects.filter(name=numerical_descriptor_dict["unit"]).exists():
|
|
60
|
+
error_message = "Unit object with that name does not exist"
|
|
61
|
+
return False, error_message
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
if not "required" in numerical_descriptor_dict:
|
|
65
|
+
error_message = "required key does not exist in numerical_descriptor_dict"
|
|
66
|
+
return False, error_message
|
|
67
|
+
|
|
68
|
+
elif not isinstance(numerical_descriptor_dict["required"], bool):
|
|
69
|
+
error_message = "required key is not a boolean"
|
|
70
|
+
return False, error_message
|
|
71
|
+
|
|
72
|
+
# check if min, max, mean, std exist and are either None or float
|
|
73
|
+
for key in ["min", "max", "mean", "std", "default"]:
|
|
74
|
+
if key not in numerical_descriptor_dict:
|
|
75
|
+
error_message = f"{key} key does not exist in numerical_descriptor_dict"
|
|
76
|
+
return False, error_message
|
|
77
|
+
|
|
78
|
+
if numerical_descriptor_dict[key] is not None and not isinstance(numerical_descriptor_dict[key], float):
|
|
79
|
+
error_message = f"{key} key is not a float"
|
|
80
|
+
return False, error_message
|
|
81
|
+
|
|
82
|
+
# check if distribution exists and is either "normal" or "uniform"
|
|
83
|
+
if "distribution" not in numerical_descriptor_dict:
|
|
84
|
+
error_message = "distribution key does not exist in numerical_descriptor_dict"
|
|
85
|
+
return False, error_message
|
|
86
|
+
|
|
87
|
+
if numerical_descriptor_dict["distribution"] not in ["normal", "uniform"]:
|
|
88
|
+
error_message = "distribution key is not either 'normal' or 'uniform'"
|
|
89
|
+
return False, error_message
|
|
90
|
+
|
|
91
|
+
return True, None
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from .transcode_videofile import (
|
|
2
|
+
transcode_videofile,
|
|
3
|
+
transcode_videofile_if_required,
|
|
4
|
+
)
|
|
5
|
+
|
|
6
|
+
from .extract_frames import extract_frames, initialize_frame_objects
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"extract_frames",
|
|
10
|
+
"initialize_frame_objects",
|
|
11
|
+
"transcode_videofile",
|
|
12
|
+
"transcode_videofile_if_required",
|
|
13
|
+
]
|