OpenREM 1.0.0b2__py3-none-any.whl → 1.0.0b3__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.
- openrem/locale/de/LC_MESSAGES/django.po +1060 -1059
- openrem/locale/django.pot +973 -972
- openrem/locale/es_MX/LC_MESSAGES/django.po +1049 -1048
- openrem/locale/it/LC_MESSAGES/django.po +1044 -1043
- openrem/locale/lt/LC_MESSAGES/django.po +989 -988
- openrem/locale/nb_NO/LC_MESSAGES/django.po +985 -984
- openrem/locale/pt_BR/LC_MESSAGES/django.po +1003 -1002
- openrem/manage.py +10 -10
- openrem/openremproject/__init__.py +1 -1
- openrem/openremproject/local_settings.py.linux +128 -128
- openrem/openremproject/local_settings.py.windows +144 -144
- openrem/openremproject/local_settings.py.windows-sqlite3 +129 -129
- openrem/openremproject/settings.py +278 -278
- openrem/openremproject/urls.py +32 -32
- openrem/openremproject/wsgi.py.example +28 -28
- openrem/remapp/__init__.py +2 -2
- openrem/remapp/admin.py +31 -31
- openrem/remapp/exports/ct_export.py +780 -753
- openrem/remapp/exports/dx_export.py +817 -805
- openrem/remapp/exports/export_common.py +931 -951
- openrem/remapp/exports/export_common_pandas.py +2422 -0
- openrem/remapp/exports/exportviews.py +815 -860
- openrem/remapp/exports/mg_csv_nhsbsp.py +292 -292
- openrem/remapp/exports/mg_export.py +673 -510
- openrem/remapp/exports/nm_export.py +796 -575
- openrem/remapp/exports/rf_export.py +1418 -1431
- openrem/remapp/extractors/ct_philips.py +424 -414
- openrem/remapp/extractors/ct_toshiba.py +2116 -2108
- openrem/remapp/extractors/dx.py +1033 -952
- openrem/remapp/extractors/extract_common.py +817 -817
- openrem/remapp/extractors/import_views.py +426 -426
- openrem/remapp/extractors/mam.py +685 -672
- openrem/remapp/extractors/nm_image.py +439 -431
- openrem/remapp/extractors/ptsizecsv2db.py +368 -368
- openrem/remapp/extractors/rdsr.py +667 -654
- openrem/remapp/extractors/rdsr_methods.py +1771 -1768
- openrem/remapp/extractors/rrdsr_methods.py +630 -622
- openrem/remapp/fixtures/openskin_safelist.json +11 -11
- openrem/remapp/forms.py +2286 -2277
- openrem/remapp/interface/chart_functions.py +2412 -2393
- openrem/remapp/interface/mod_filters.py +1241 -1243
- openrem/remapp/migrations/0001_initial.py.1-0-upgrade +1043 -1043
- openrem/remapp/models.py +3418 -3407
- openrem/remapp/netdicom/dicomviews.py +681 -683
- openrem/remapp/netdicom/qrscu.py +2646 -2646
- openrem/remapp/netdicom/tools.py +134 -134
- openrem/remapp/static/css/bootstrap-theme.css +587 -587
- openrem/remapp/static/css/bootstrap-theme.min.css +4 -4
- openrem/remapp/static/css/bootstrap.css +6800 -6800
- openrem/remapp/static/css/bootstrap.min.css +4 -4
- openrem/remapp/static/css/datepicker3.css +790 -790
- openrem/remapp/static/css/jquery.qtip.min.css +2 -2
- openrem/remapp/static/css/openrem-extra.css +442 -442
- openrem/remapp/static/css/openrem.css +96 -96
- openrem/remapp/static/css/registration.css +34 -34
- openrem/remapp/static/fonts/glyphicons-halflings-regular.svg +287 -287
- openrem/remapp/static/js/bootstrap-datepicker.js +1671 -1671
- openrem/remapp/static/js/bootstrap.js +2363 -2363
- openrem/remapp/static/js/bootstrap.min.js +6 -6
- openrem/remapp/static/js/charts/chartCommonFunctions.js +75 -75
- openrem/remapp/static/js/charts/chartFullScreen.js +41 -41
- openrem/remapp/static/js/charts/ctChartAjax.js +331 -331
- openrem/remapp/static/js/charts/dxChartAjax.js +290 -290
- openrem/remapp/static/js/charts/mgChartAjax.js +144 -144
- openrem/remapp/static/js/charts/nmChartAjax.js +64 -64
- openrem/remapp/static/js/charts/plotly-2.35.2.min.js +8 -0
- openrem/remapp/static/js/charts/rfChartAjax.js +128 -128
- openrem/remapp/static/js/chroma.min.js +32 -32
- openrem/remapp/static/js/datepicker.js +5 -5
- openrem/remapp/static/js/dicom.js +115 -115
- openrem/remapp/static/js/django_reverse/reverse.js +13 -13
- openrem/remapp/static/js/formatDate.js +7 -7
- openrem/remapp/static/js/html5shiv.min.js +8 -8
- openrem/remapp/static/js/jquery-1.11.0.min.js +4 -4
- openrem/remapp/static/js/npm.js +12 -12
- openrem/remapp/static/js/respond.min.js +4 -4
- openrem/remapp/static/js/skin-dose-maps/jquery.qtip.min.js +4 -4
- openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMap3dHUDObject.js +112 -112
- openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMap3dObject.js +367 -367
- openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMap3dPersonObject.js +158 -158
- openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMapColourScaleObject.js +153 -153
- openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMapObject.js +367 -367
- openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMapping.js +584 -584
- openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMapping3d.js +255 -255
- openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMappingAjax.js +267 -212
- openrem/remapp/static/js/skin-dose-maps/three.min.js +835 -835
- openrem/remapp/static/js/sorttable.js +495 -495
- openrem/remapp/templates/base.html +253 -253
- openrem/remapp/templates/registration/changepassword.html +25 -25
- openrem/remapp/templates/registration/changepassworddone.html +12 -12
- openrem/remapp/templates/registration/login.html +42 -42
- openrem/remapp/templates/remapp/backgroundtaskmaximumrows_form.html +29 -29
- openrem/remapp/templates/remapp/base.html +1 -1
- openrem/remapp/templates/remapp/ctdetail.html +235 -235
- openrem/remapp/templates/remapp/ctfiltered.html +310 -310
- openrem/remapp/templates/remapp/dicomdeletesettings_form.html +31 -31
- openrem/remapp/templates/remapp/dicomqr.html +147 -147
- openrem/remapp/templates/remapp/dicomquerydetails.html +83 -83
- openrem/remapp/templates/remapp/dicomqueryimages.html +49 -49
- openrem/remapp/templates/remapp/dicomqueryseries.html +109 -109
- openrem/remapp/templates/remapp/dicomquerysummary.html +48 -48
- openrem/remapp/templates/remapp/dicomremoteqr_confirm_delete.html +60 -60
- openrem/remapp/templates/remapp/dicomremoteqr_form.html +32 -32
- openrem/remapp/templates/remapp/dicomstorescp_confirm_delete.html +53 -53
- openrem/remapp/templates/remapp/dicomstorescp_form.html +48 -48
- openrem/remapp/templates/remapp/dicomsummary.html +257 -257
- openrem/remapp/templates/remapp/displaychartoptions.html +184 -184
- openrem/remapp/templates/remapp/displayhomepageoptions.html +57 -57
- openrem/remapp/templates/remapp/displayname-count.html +6 -6
- openrem/remapp/templates/remapp/displayname-last-date.html +3 -3
- openrem/remapp/templates/remapp/displayname-modality.html +86 -105
- openrem/remapp/templates/remapp/displayname-skinmap.html +18 -18
- openrem/remapp/templates/remapp/displaynameupdate.html +100 -100
- openrem/remapp/templates/remapp/displaynameview.html +222 -219
- openrem/remapp/templates/remapp/dxdetail.html +176 -176
- openrem/remapp/templates/remapp/dxfiltered.html +324 -324
- openrem/remapp/templates/remapp/exports-active.html +25 -25
- openrem/remapp/templates/remapp/exports-complete.html +35 -35
- openrem/remapp/templates/remapp/exports-error.html +26 -26
- openrem/remapp/templates/remapp/exports-queue.html +18 -18
- openrem/remapp/templates/remapp/exports.html +191 -191
- openrem/remapp/templates/remapp/failed_summary_list.html +27 -27
- openrem/remapp/templates/remapp/filteredbase.html +162 -162
- openrem/remapp/templates/remapp/highdosemetricalertsettings_form.html +76 -76
- openrem/remapp/templates/remapp/home-list-modalities.html +94 -94
- openrem/remapp/templates/remapp/home.html +202 -202
- openrem/remapp/templates/remapp/list_filters.html +24 -24
- openrem/remapp/templates/remapp/mgdetail.html +160 -138
- openrem/remapp/templates/remapp/mgfiltered.html +311 -311
- openrem/remapp/templates/remapp/nmdetail.html +300 -300
- openrem/remapp/templates/remapp/nmfiltered.html +255 -255
- openrem/remapp/templates/remapp/notpatient.html +190 -190
- openrem/remapp/templates/remapp/notpatientindicators_form_base.html +81 -81
- openrem/remapp/templates/remapp/notpatientindicatorsid_confirm_delete.html +54 -54
- openrem/remapp/templates/remapp/notpatientindicatorsid_form.html +23 -23
- openrem/remapp/templates/remapp/notpatientindicatorsname_confirm_delete.html +54 -54
- openrem/remapp/templates/remapp/notpatientindicatorsname_form.html +23 -23
- openrem/remapp/templates/remapp/notpatientindicatorsname_form_base.html +85 -85
- openrem/remapp/templates/remapp/openskinsafelist_add.html +130 -130
- openrem/remapp/templates/remapp/openskinsafelist_confirm_delete.html +100 -100
- openrem/remapp/templates/remapp/openskinsafelist_form.html +207 -207
- openrem/remapp/templates/remapp/patientidsettings_form.html +83 -83
- openrem/remapp/templates/remapp/populate_summary_progress.html +83 -83
- openrem/remapp/templates/remapp/populate_summary_progress_error.html +36 -36
- openrem/remapp/templates/remapp/review_failed_imports.html +157 -157
- openrem/remapp/templates/remapp/review_failed_study.html +41 -41
- openrem/remapp/templates/remapp/review_studies_delete_button.html +20 -20
- openrem/remapp/templates/remapp/review_study.html +19 -19
- openrem/remapp/templates/remapp/review_summary_list.html +245 -245
- openrem/remapp/templates/remapp/rf_dose_alert_email_template.html +14 -1
- openrem/remapp/templates/remapp/rfalertnotificationsview.html +59 -59
- openrem/remapp/templates/remapp/rfdetail.html +547 -543
- openrem/remapp/templates/remapp/rfdetailbase.html +18 -18
- openrem/remapp/templates/remapp/rffiltered.html +404 -404
- openrem/remapp/templates/remapp/sizeimports.html +119 -119
- openrem/remapp/templates/remapp/sizeprocess.html +96 -96
- openrem/remapp/templates/remapp/sizeupload.html +110 -110
- openrem/remapp/templates/remapp/skindosemapcalcsettings_form.html +28 -28
- openrem/remapp/templates/remapp/standardname-modality.html +69 -69
- openrem/remapp/templates/remapp/standardnames_confirm_delete.html +71 -71
- openrem/remapp/templates/remapp/standardnames_form.html +87 -87
- openrem/remapp/templates/remapp/standardnamesettings_form.html +41 -41
- openrem/remapp/templates/remapp/standardnamesrefreshall.html +92 -92
- openrem/remapp/templates/remapp/standardnameview.html +103 -103
- openrem/remapp/templates/remapp/study_confirm_delete.html +147 -147
- openrem/remapp/templates/remapp/task_admin.html +265 -265
- openrem/remapp/templates/remapp/tasks.html +76 -76
- openrem/remapp/templatetags/formfilters.py +13 -13
- openrem/remapp/templatetags/proper_paginate.py +38 -38
- openrem/remapp/templatetags/remappduration.py +36 -36
- openrem/remapp/templatetags/sigdig.py +38 -38
- openrem/remapp/templatetags/sort_class_property_value.py +15 -15
- openrem/remapp/templatetags/update_variable.py +20 -20
- openrem/remapp/templatetags/url_replace.py +25 -25
- openrem/remapp/tests/test_charts_common.py +202 -202
- openrem/remapp/tests/test_charts_ct.py +7111 -7111
- openrem/remapp/tests/test_charts_dx.py +3513 -3513
- openrem/remapp/tests/test_charts_mg.py +1116 -1115
- openrem/remapp/tests/test_dcmdatetime.py +189 -189
- openrem/remapp/tests/test_dicom_qr.py +2580 -2580
- openrem/remapp/tests/test_display_name.py +274 -274
- openrem/remapp/tests/test_export_ct_xlsx.py +272 -248
- openrem/remapp/tests/test_export_dx_xlsx.py +137 -134
- openrem/remapp/tests/test_export_mammo_csv.py +242 -242
- openrem/remapp/tests/test_export_rf_xlsx.py +246 -246
- openrem/remapp/tests/test_files/DX-Im-DRGEM.dcm +0 -0
- openrem/remapp/tests/test_files/MG-RDSR-GEPristina-2D.dcm +0 -0
- openrem/remapp/tests/test_files/MG-RDSR-GEPristina-DBT.dcm +0 -0
- openrem/remapp/tests/test_files/MG-RDSR-Giotto-DBT.dcm +0 -0
- openrem/remapp/tests/test_files/skin_map_alphenix.py +590 -590
- openrem/remapp/tests/test_files/skin_map_zee.py +354 -354
- openrem/remapp/tests/test_filters_ct.py +321 -321
- openrem/remapp/tests/test_filters_dx.py +92 -92
- openrem/remapp/tests/test_filters_mammo.py +183 -183
- openrem/remapp/tests/test_filters_rf.py +118 -118
- openrem/remapp/tests/test_get_values.py +72 -72
- openrem/remapp/tests/test_hash_id.py +65 -65
- openrem/remapp/tests/test_import_ct_esr_ge.py +3034 -3034
- openrem/remapp/tests/test_import_ct_philips_rdsr.py +42 -42
- openrem/remapp/tests/test_import_ct_rdsr_multiple.py +256 -256
- openrem/remapp/tests/test_import_ct_rdsr_siemens.py +827 -827
- openrem/remapp/tests/test_import_ct_rdsr_spectrumdynamics.py +91 -91
- openrem/remapp/tests/test_import_ct_rdsr_toshiba_dosecheck.py +67 -67
- openrem/remapp/tests/test_import_ct_rdsr_toshiba_multivaluesd.py +33 -33
- openrem/remapp/tests/test_import_ct_rdsr_toshiba_pixelmed.py +118 -118
- openrem/remapp/tests/test_import_ct_sc_philips.py +44 -44
- openrem/remapp/tests/test_import_dual_rdsr.py +110 -110
- openrem/remapp/tests/test_import_dx.py +1267 -1191
- openrem/remapp/tests/test_import_dx_rdsr.py +1250 -1253
- openrem/remapp/tests/test_import_mam.py +438 -438
- openrem/remapp/tests/test_import_mg_im_hol_proj.py +46 -46
- openrem/remapp/tests/test_import_mg_rdsr.py +586 -586
- openrem/remapp/tests/test_import_nm_image.py +420 -420
- openrem/remapp/tests/test_import_nm_siemens_rdsr.py +396 -396
- openrem/remapp/tests/test_import_px.py +161 -161
- openrem/remapp/tests/test_import_rf_rdsr.py +420 -418
- openrem/remapp/tests/test_missing_date.py +42 -42
- openrem/remapp/tests/test_not_patient.py +60 -60
- openrem/remapp/tests/test_openskin.py +272 -272
- openrem/remapp/tests/test_patient_id_settings.py +72 -72
- openrem/remapp/tests/test_pt_size_import.py +232 -232
- openrem/remapp/tests/test_rf_detail.py +113 -113
- openrem/remapp/tests/test_rf_high_dose_alert.py +361 -361
- openrem/remapp/tools/background.py +361 -361
- openrem/remapp/tools/check_standard_name_status.py +47 -0
- openrem/remapp/tools/check_uid.py +70 -70
- openrem/remapp/tools/dcmdatetime.py +248 -248
- openrem/remapp/tools/default_import.py +44 -47
- openrem/remapp/tools/get_values.py +230 -230
- openrem/remapp/tools/hash_id.py +58 -58
- openrem/remapp/tools/make_skin_map.py +448 -406
- openrem/remapp/tools/not_patient_indicators.py +72 -72
- openrem/remapp/tools/openskin/calc_exp_map.py +173 -173
- openrem/remapp/tools/openskin/geomclass.py +475 -475
- openrem/remapp/tools/openskin/geomfunc.py +433 -432
- openrem/remapp/tools/openskin/skinmap.py +417 -417
- openrem/remapp/tools/populate_summary.py +185 -193
- openrem/remapp/tools/save_skin_map_structure.py +73 -73
- openrem/remapp/tools/send_high_dose_alert_emails.py +238 -207
- openrem/remapp/urls.py +456 -448
- openrem/remapp/version.py +11 -11
- openrem/remapp/views.py +1147 -1052
- openrem/remapp/views_admin.py +3876 -3936
- openrem/remapp/views_charts_ct.py +2110 -2058
- openrem/remapp/views_charts_dx.py +1906 -1836
- openrem/remapp/views_charts_mg.py +1349 -1196
- openrem/remapp/views_charts_nm.py +535 -535
- openrem/remapp/views_charts_rf.py +1219 -1241
- openrem/remapp/views_openskin.py +379 -384
- openrem/sample-config/openrem-consumer.service +12 -12
- openrem/sample-config/openrem-gunicorn.service +13 -13
- openrem/sample-config/openrem-server +14 -13
- openrem/sample-config/openrem_orthanc_config_linux.lua +454 -454
- openrem/sample-config/openrem_orthanc_config_windows.lua +455 -455
- openrem/sample-config/queue-init.bat +73 -73
- openrem/scripts/openrem_ctphilips.py +25 -25
- openrem/scripts/openrem_cttoshiba.py +28 -28
- openrem/scripts/openrem_dx.py +22 -22
- openrem/scripts/openrem_mg.py +22 -22
- openrem/scripts/openrem_nm.py +22 -22
- openrem/scripts/openrem_ptsizecsv.py +17 -17
- openrem/scripts/openrem_qr.py +12 -12
- openrem/scripts/openrem_rdsr.py +25 -25
- {OpenREM-1.0.0b2.dist-info → openrem-1.0.0b3.dist-info}/METADATA +39 -29
- openrem-1.0.0b3.dist-info/RECORD +379 -0
- {OpenREM-1.0.0b2.dist-info → openrem-1.0.0b3.dist-info}/WHEEL +1 -1
- {OpenREM-1.0.0b2.dist-info → openrem-1.0.0b3.dist-info/licenses}/COPYING-GPLv3 +674 -674
- {OpenREM-1.0.0b2.dist-info → openrem-1.0.0b3.dist-info/licenses}/LICENSE +22 -22
- OpenREM-1.0.0b2.dist-info/RECORD +0 -373
- openrem/remapp/static/js/charts/plotly-2.17.1.min.js +0 -8
- {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_ctphilips.py +0 -0
- {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_cttoshiba.py +0 -0
- {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_dx.py +0 -0
- {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_mg.py +0 -0
- {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_nm.py +0 -0
- {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_ptsizecsv.py +0 -0
- {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_qr.py +0 -0
- {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_rdsr.py +0 -0
- {OpenREM-1.0.0b2.dist-info → openrem-1.0.0b3.dist-info}/top_level.txt +0 -0
|
@@ -1,368 +1,368 @@
|
|
|
1
|
-
# OpenREM - Radiation Exposure Monitoring tools for the physicist
|
|
2
|
-
# Copyright (C) 2012,2013 The Royal Marsden NHS Foundation Trust
|
|
3
|
-
#
|
|
4
|
-
# This program is free software: you can redistribute it and/or modify
|
|
5
|
-
# it under the terms of the GNU General Public License as published by
|
|
6
|
-
# the Free Software Foundation, either version 3 of the License, or
|
|
7
|
-
# (at your option) any later version.
|
|
8
|
-
#
|
|
9
|
-
# This program is distributed in the hope that it will be useful,
|
|
10
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
-
# GNU General Public License for more details.
|
|
13
|
-
#
|
|
14
|
-
# Additional permission under section 7 of GPLv3:
|
|
15
|
-
# You shall not make any use of the name of The Royal Marsden NHS
|
|
16
|
-
# Foundation trust in connection with this Program in any press or
|
|
17
|
-
# other public announcement without the prior written consent of
|
|
18
|
-
# The Royal Marsden NHS Foundation Trust.
|
|
19
|
-
#
|
|
20
|
-
# You should have received a copy of the GNU General Public License
|
|
21
|
-
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
22
|
-
|
|
23
|
-
"""
|
|
24
|
-
.. module:: ptsizecsv2db.
|
|
25
|
-
:synopsis: Use to import height and weight data from csv file to existing studies in the database.
|
|
26
|
-
|
|
27
|
-
.. moduleauthor:: Ed McDonagh
|
|
28
|
-
|
|
29
|
-
"""
|
|
30
|
-
import argparse
|
|
31
|
-
import csv
|
|
32
|
-
import datetime
|
|
33
|
-
from decimal import Decimal
|
|
34
|
-
import logging
|
|
35
|
-
import os
|
|
36
|
-
import sys
|
|
37
|
-
import uuid
|
|
38
|
-
|
|
39
|
-
import django
|
|
40
|
-
from django import db
|
|
41
|
-
from django.core.exceptions import ObjectDoesNotExist
|
|
42
|
-
from django.core.files.base import ContentFile
|
|
43
|
-
from openrem.remapp.tools.background import (
|
|
44
|
-
get_or_generate_task_uuid,
|
|
45
|
-
record_task_error_exit,
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
logger = logging.getLogger(__name__)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
basepath = os.path.dirname(__file__)
|
|
53
|
-
projectpath = os.path.abspath(os.path.join(basepath, "..", ".."))
|
|
54
|
-
if projectpath not in sys.path:
|
|
55
|
-
sys.path.insert(1, projectpath)
|
|
56
|
-
os.environ["DJANGO_SETTINGS_MODULE"] = "openremproject.settings"
|
|
57
|
-
django.setup()
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
# Absolute import path to prevent issues with script
|
|
61
|
-
from remapp.models import (
|
|
62
|
-
GeneralStudyModuleAttr,
|
|
63
|
-
SizeUpload,
|
|
64
|
-
) # pylint: disable=wrong-import-position
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def _patientstudymoduleattributes(
|
|
68
|
-
size_upload=None, exam=None, size_dict=None
|
|
69
|
-
): # C.7.2.2
|
|
70
|
-
|
|
71
|
-
log_file = size_upload.logfile
|
|
72
|
-
try:
|
|
73
|
-
patient_attributes = exam.patientstudymoduleattr_set.get()
|
|
74
|
-
except ObjectDoesNotExist:
|
|
75
|
-
error = (
|
|
76
|
-
f"Attempt to import pt size info for study UID {exam.study_instance_uid}/acc. number"
|
|
77
|
-
f" {exam.accession_number} failed due to a failed import"
|
|
78
|
-
)
|
|
79
|
-
logger.error(error)
|
|
80
|
-
record_task_error_exit(error)
|
|
81
|
-
log_file.file.open("a")
|
|
82
|
-
log_file.write(
|
|
83
|
-
"\r\n ********* Failed to insert size - database entry incomplete *********"
|
|
84
|
-
)
|
|
85
|
-
log_file.file.close()
|
|
86
|
-
if size_dict["verbose"]:
|
|
87
|
-
print(
|
|
88
|
-
" ********* Failed to insert size - database entry incomplete *********"
|
|
89
|
-
)
|
|
90
|
-
return
|
|
91
|
-
|
|
92
|
-
if size_dict["height"]:
|
|
93
|
-
if not patient_attributes.patient_size:
|
|
94
|
-
patient_attributes.patient_size = Decimal(size_dict["height"]) / Decimal(
|
|
95
|
-
100.0
|
|
96
|
-
)
|
|
97
|
-
log_file.file.open("a")
|
|
98
|
-
log_file.write(f"\r\n Inserted height of {size_dict['height']} cm")
|
|
99
|
-
log_file.file.close()
|
|
100
|
-
if size_dict["verbose"]:
|
|
101
|
-
print(f" Inserted height of {size_dict['height']} cm")
|
|
102
|
-
elif size_upload.overwrite:
|
|
103
|
-
existing_height = patient_attributes.patient_size * Decimal(100.0)
|
|
104
|
-
patient_attributes.patient_size = Decimal(size_dict["height"]) / Decimal(
|
|
105
|
-
100.0
|
|
106
|
-
)
|
|
107
|
-
log_file.file.open("a")
|
|
108
|
-
log_file.write(
|
|
109
|
-
f"\r\n Inserted height of {size_dict['height']} cm replacing {existing_height:.0f} cm"
|
|
110
|
-
)
|
|
111
|
-
log_file.file.close()
|
|
112
|
-
if size_dict["verbose"]:
|
|
113
|
-
print(
|
|
114
|
-
f" Inserted height of {size_dict['height']} cm replacing {existing_height:.0f} cm"
|
|
115
|
-
)
|
|
116
|
-
else:
|
|
117
|
-
existing_height = patient_attributes.patient_size * Decimal(100.0)
|
|
118
|
-
log_file.file.open("a")
|
|
119
|
-
log_file.write(
|
|
120
|
-
f"\r\n Height of {size_dict['height']} cm not inserted as {existing_height:.0f} cm "
|
|
121
|
-
f"already in the database"
|
|
122
|
-
)
|
|
123
|
-
log_file.file.close()
|
|
124
|
-
if size_dict["verbose"]:
|
|
125
|
-
print(
|
|
126
|
-
f" Height of {size_dict['height']} cm not inserted as {existing_height:.0f} cm already in "
|
|
127
|
-
f"the database"
|
|
128
|
-
)
|
|
129
|
-
|
|
130
|
-
if size_dict["weight"]:
|
|
131
|
-
if not patient_attributes.patient_weight:
|
|
132
|
-
patient_attributes.patient_weight = size_dict["weight"]
|
|
133
|
-
log_file.file.open("a")
|
|
134
|
-
log_file.write(f"\r\n Inserted weight of {size_dict['weight']} kg")
|
|
135
|
-
log_file.file.close()
|
|
136
|
-
if size_dict["verbose"]:
|
|
137
|
-
print(f" Inserted weight of {size_dict['weight']} kg")
|
|
138
|
-
elif size_upload.overwrite:
|
|
139
|
-
existing_weight = patient_attributes.patient_weight
|
|
140
|
-
patient_attributes.patient_weight = size_dict["weight"]
|
|
141
|
-
log_file.file.open("a")
|
|
142
|
-
log_file.write(
|
|
143
|
-
f"\r\n Inserted weight of {size_dict['weight']} kg replacing {existing_weight:.1f} kg"
|
|
144
|
-
)
|
|
145
|
-
log_file.file.close()
|
|
146
|
-
if size_dict["verbose"]:
|
|
147
|
-
print(
|
|
148
|
-
f" Inserted weight of {size_dict['weight']} kg replacing {existing_weight:.1f} kg"
|
|
149
|
-
)
|
|
150
|
-
else:
|
|
151
|
-
log_file.file.open("a")
|
|
152
|
-
log_file.write(
|
|
153
|
-
f"\r\n Weight of {size_dict['weight']} kg not inserted as "
|
|
154
|
-
f"{patient_attributes.patient_weight:.1f} kg already in the database"
|
|
155
|
-
)
|
|
156
|
-
log_file.file.close()
|
|
157
|
-
if size_dict["verbose"]:
|
|
158
|
-
print(
|
|
159
|
-
f" Weight of {size_dict['weight']} kg not inserted as "
|
|
160
|
-
f"{patient_attributes.patient_weight:.1f} kg already in the database"
|
|
161
|
-
)
|
|
162
|
-
|
|
163
|
-
patient_attributes.save()
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
def _ptsizeinsert(size_upload=None, size_dict=None):
|
|
167
|
-
|
|
168
|
-
log_file = size_upload.logfile
|
|
169
|
-
if (size_dict["height"] or size_dict["weight"]) and size_dict["acc_no"]:
|
|
170
|
-
if not size_dict["si_uid"]:
|
|
171
|
-
exams = GeneralStudyModuleAttr.objects.filter(
|
|
172
|
-
accession_number__exact=size_dict["acc_no"]
|
|
173
|
-
)
|
|
174
|
-
else:
|
|
175
|
-
exams = GeneralStudyModuleAttr.objects.filter(
|
|
176
|
-
study_instance_uid__exact=size_dict["acc_no"]
|
|
177
|
-
)
|
|
178
|
-
if exams:
|
|
179
|
-
for exam in exams:
|
|
180
|
-
log_file.file.open("a")
|
|
181
|
-
log_file.write(f"\r\n{size_dict['acc_no']}:")
|
|
182
|
-
log_file.file.close()
|
|
183
|
-
if size_dict["verbose"]:
|
|
184
|
-
print(size_dict["acc_no"])
|
|
185
|
-
_patientstudymoduleattributes(
|
|
186
|
-
size_upload=size_upload, exam=exam, size_dict=size_dict
|
|
187
|
-
)
|
|
188
|
-
|
|
189
|
-
db.reset_queries()
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
def websizeimport(csv_pk=None):
|
|
193
|
-
"""Task to import patient size data from the OpenREM web interface.
|
|
194
|
-
|
|
195
|
-
:param csv_pk: Database index key for the import record, containing
|
|
196
|
-
the path to the import csv file and the field header details.
|
|
197
|
-
|
|
198
|
-
"""
|
|
199
|
-
|
|
200
|
-
if csv_pk:
|
|
201
|
-
size_upload = SizeUpload.objects.all().filter(id__exact=csv_pk)[0]
|
|
202
|
-
size_upload.task_id = get_or_generate_task_uuid()
|
|
203
|
-
datestamp = datetime.datetime.now()
|
|
204
|
-
size_upload.import_date = datestamp
|
|
205
|
-
size_upload.progress = "Patient size data import started"
|
|
206
|
-
size_upload.status = "CURRENT"
|
|
207
|
-
size_upload.save()
|
|
208
|
-
if (
|
|
209
|
-
size_upload.id_type
|
|
210
|
-
and size_upload.id_field
|
|
211
|
-
and size_upload.height_field
|
|
212
|
-
and size_upload.weight_field
|
|
213
|
-
):
|
|
214
|
-
si_uid = False
|
|
215
|
-
verbose = False
|
|
216
|
-
if size_upload.id_type == "si-uid":
|
|
217
|
-
si_uid = True
|
|
218
|
-
|
|
219
|
-
log_file = "pt_size_import_log_{0}.txt".format(
|
|
220
|
-
datestamp.strftime("%Y%m%d-%H%M%S%f")
|
|
221
|
-
)
|
|
222
|
-
headerrow = ContentFile(
|
|
223
|
-
f"Patient size import from {size_upload.sizefile.name}\r\n"
|
|
224
|
-
)
|
|
225
|
-
|
|
226
|
-
try:
|
|
227
|
-
size_upload.logfile.save(log_file, headerrow)
|
|
228
|
-
except OSError as e:
|
|
229
|
-
error = (
|
|
230
|
-
"Error saving export file - please contact an administrator. "
|
|
231
|
-
"Error({0}): {1}".format(e.errno, e.strerror)
|
|
232
|
-
)
|
|
233
|
-
size_upload.progress = error
|
|
234
|
-
size_upload.status = "ERROR"
|
|
235
|
-
size_upload.save()
|
|
236
|
-
record_task_error_exit(error)
|
|
237
|
-
return
|
|
238
|
-
except:
|
|
239
|
-
error = (
|
|
240
|
-
"Unexpected error saving export file - please contact an "
|
|
241
|
-
"administrator: {0}".format(sys.exc_info()[0])
|
|
242
|
-
)
|
|
243
|
-
size_upload.progress = error
|
|
244
|
-
size_upload.status = "ERROR"
|
|
245
|
-
size_upload.save()
|
|
246
|
-
record_task_error_exit(error)
|
|
247
|
-
return
|
|
248
|
-
|
|
249
|
-
log_file = size_upload.logfile
|
|
250
|
-
log_file.file.close()
|
|
251
|
-
# Method used for opening and writing to file as per https://code.djangoproject.com/ticket/13809
|
|
252
|
-
|
|
253
|
-
size_upload.sizefile.open(mode="r")
|
|
254
|
-
csv_file = size_upload.sizefile.readlines()
|
|
255
|
-
size_upload.num_records = len(csv_file) - 1
|
|
256
|
-
size_upload.save()
|
|
257
|
-
try:
|
|
258
|
-
dataset = csv.DictReader(csv_file)
|
|
259
|
-
for i, line in enumerate(dataset):
|
|
260
|
-
size_upload.progress = (
|
|
261
|
-
f"Processing row {i + 1} of {size_upload.num_records}"
|
|
262
|
-
)
|
|
263
|
-
size_upload.save()
|
|
264
|
-
size_dict = {
|
|
265
|
-
"acc_no": line[size_upload.id_field],
|
|
266
|
-
"height": line[size_upload.height_field],
|
|
267
|
-
"weight": line[size_upload.weight_field],
|
|
268
|
-
"si_uid": si_uid,
|
|
269
|
-
"verbose": verbose,
|
|
270
|
-
}
|
|
271
|
-
_ptsizeinsert(size_upload=size_upload, size_dict=size_dict)
|
|
272
|
-
finally:
|
|
273
|
-
size_upload.sizefile.delete()
|
|
274
|
-
size_upload.processtime = (
|
|
275
|
-
datetime.datetime.now() - datestamp
|
|
276
|
-
).total_seconds()
|
|
277
|
-
size_upload.status = "COMPLETE"
|
|
278
|
-
size_upload.save()
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
def _create_parser():
|
|
282
|
-
parser = argparse.ArgumentParser(
|
|
283
|
-
description="Import height and weight data from a CSV file into an OpenREM database. If either height or "
|
|
284
|
-
"weight is missing just add a blank column with an appropriate title."
|
|
285
|
-
)
|
|
286
|
-
parser.add_argument(
|
|
287
|
-
"-u",
|
|
288
|
-
"--si-uid",
|
|
289
|
-
action="store_true",
|
|
290
|
-
help="use Study Instance UID instead of Accession Number",
|
|
291
|
-
)
|
|
292
|
-
parser.add_argument(
|
|
293
|
-
"-v", "--verbose", help="also print log to shell", action="store_true"
|
|
294
|
-
)
|
|
295
|
-
parser.add_argument(
|
|
296
|
-
"-o", "--overwrite", help="overwrite existing values", action="store_true"
|
|
297
|
-
)
|
|
298
|
-
parser.add_argument(
|
|
299
|
-
"csvfile", help="csv file with height, weight and study identifier"
|
|
300
|
-
)
|
|
301
|
-
parser.add_argument(
|
|
302
|
-
"id", help="column title for the accession number or study instance UID"
|
|
303
|
-
)
|
|
304
|
-
parser.add_argument(
|
|
305
|
-
"height", help="column title for the patient height, values in cm"
|
|
306
|
-
)
|
|
307
|
-
parser.add_argument(
|
|
308
|
-
"weight", help="column title for the patient weight, values in kg"
|
|
309
|
-
)
|
|
310
|
-
|
|
311
|
-
return parser
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
def csv2db():
|
|
315
|
-
"""Import patient height and weight data from csv RIS exports. Called from ``openrem_ptsizecsv.py`` script
|
|
316
|
-
|
|
317
|
-
:param args: sys.argv from the command line call
|
|
318
|
-
|
|
319
|
-
Example::
|
|
320
|
-
|
|
321
|
-
openrem_ptsizecsv.py -s MyRISExport.csv StudyInstanceUID height weight
|
|
322
|
-
|
|
323
|
-
"""
|
|
324
|
-
|
|
325
|
-
args = _create_parser().parse_args()
|
|
326
|
-
|
|
327
|
-
with open(args.csvfile) as csv_file:
|
|
328
|
-
dataset = csv.DictReader(csv_file)
|
|
329
|
-
fieldnames = dataset.fieldnames
|
|
330
|
-
arg_headers = [args.id, args.height, args.weight]
|
|
331
|
-
if not all(header in fieldnames for header in arg_headers):
|
|
332
|
-
msg = f"Error: one or more of {arg_headers} not found in csv file"
|
|
333
|
-
print(msg)
|
|
334
|
-
record_task_error_exit(msg)
|
|
335
|
-
return
|
|
336
|
-
size_upload = SizeUpload()
|
|
337
|
-
date_stamp = datetime.datetime.now()
|
|
338
|
-
size_upload.import_date = date_stamp
|
|
339
|
-
size_upload.task_id = uuid.uuid4()
|
|
340
|
-
size_upload.progress = "Patient size data import from shell started"
|
|
341
|
-
size_upload.status = "CURRENT"
|
|
342
|
-
size_upload.overwrite = args.overwrite
|
|
343
|
-
size_upload.save()
|
|
344
|
-
log_file_name = "pt_size_import_log_{0}.txt".format(
|
|
345
|
-
date_stamp.strftime("%Y%m%d-%H%M%S%f")
|
|
346
|
-
)
|
|
347
|
-
log_header_row = ContentFile(f"Patient size import from {args.csvfile}\r\n")
|
|
348
|
-
size_upload.logfile.save(log_file_name, log_header_row)
|
|
349
|
-
size_upload.save()
|
|
350
|
-
log_file = size_upload.logfile
|
|
351
|
-
log_file.file.close()
|
|
352
|
-
size_upload.num_records = len(csv_file.readlines())
|
|
353
|
-
size_upload.save()
|
|
354
|
-
csv_file.seek(0)
|
|
355
|
-
|
|
356
|
-
for line in dataset:
|
|
357
|
-
size_dict = {
|
|
358
|
-
"acc_no": line[args.id],
|
|
359
|
-
"height": line[args.height],
|
|
360
|
-
"weight": line[args.weight],
|
|
361
|
-
"si_uid": args.si_uid,
|
|
362
|
-
"verbose": args.verbose,
|
|
363
|
-
}
|
|
364
|
-
_ptsizeinsert(size_upload=size_upload, size_dict=size_dict)
|
|
365
|
-
|
|
366
|
-
size_upload.processtime = (datetime.datetime.now() - date_stamp).total_seconds()
|
|
367
|
-
size_upload.status = "COMPLETE"
|
|
368
|
-
size_upload.save()
|
|
1
|
+
# OpenREM - Radiation Exposure Monitoring tools for the physicist
|
|
2
|
+
# Copyright (C) 2012,2013 The Royal Marsden NHS Foundation Trust
|
|
3
|
+
#
|
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
# (at your option) any later version.
|
|
8
|
+
#
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU General Public License for more details.
|
|
13
|
+
#
|
|
14
|
+
# Additional permission under section 7 of GPLv3:
|
|
15
|
+
# You shall not make any use of the name of The Royal Marsden NHS
|
|
16
|
+
# Foundation trust in connection with this Program in any press or
|
|
17
|
+
# other public announcement without the prior written consent of
|
|
18
|
+
# The Royal Marsden NHS Foundation Trust.
|
|
19
|
+
#
|
|
20
|
+
# You should have received a copy of the GNU General Public License
|
|
21
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
22
|
+
|
|
23
|
+
"""
|
|
24
|
+
.. module:: ptsizecsv2db.
|
|
25
|
+
:synopsis: Use to import height and weight data from csv file to existing studies in the database.
|
|
26
|
+
|
|
27
|
+
.. moduleauthor:: Ed McDonagh
|
|
28
|
+
|
|
29
|
+
"""
|
|
30
|
+
import argparse
|
|
31
|
+
import csv
|
|
32
|
+
import datetime
|
|
33
|
+
from decimal import Decimal
|
|
34
|
+
import logging
|
|
35
|
+
import os
|
|
36
|
+
import sys
|
|
37
|
+
import uuid
|
|
38
|
+
|
|
39
|
+
import django
|
|
40
|
+
from django import db
|
|
41
|
+
from django.core.exceptions import ObjectDoesNotExist
|
|
42
|
+
from django.core.files.base import ContentFile
|
|
43
|
+
from openrem.remapp.tools.background import (
|
|
44
|
+
get_or_generate_task_uuid,
|
|
45
|
+
record_task_error_exit,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
logger = logging.getLogger(__name__)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
basepath = os.path.dirname(__file__)
|
|
53
|
+
projectpath = os.path.abspath(os.path.join(basepath, "..", ".."))
|
|
54
|
+
if projectpath not in sys.path:
|
|
55
|
+
sys.path.insert(1, projectpath)
|
|
56
|
+
os.environ["DJANGO_SETTINGS_MODULE"] = "openremproject.settings"
|
|
57
|
+
django.setup()
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# Absolute import path to prevent issues with script
|
|
61
|
+
from remapp.models import (
|
|
62
|
+
GeneralStudyModuleAttr,
|
|
63
|
+
SizeUpload,
|
|
64
|
+
) # pylint: disable=wrong-import-position
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _patientstudymoduleattributes(
|
|
68
|
+
size_upload=None, exam=None, size_dict=None
|
|
69
|
+
): # C.7.2.2
|
|
70
|
+
|
|
71
|
+
log_file = size_upload.logfile
|
|
72
|
+
try:
|
|
73
|
+
patient_attributes = exam.patientstudymoduleattr_set.get()
|
|
74
|
+
except ObjectDoesNotExist:
|
|
75
|
+
error = (
|
|
76
|
+
f"Attempt to import pt size info for study UID {exam.study_instance_uid}/acc. number"
|
|
77
|
+
f" {exam.accession_number} failed due to a failed import"
|
|
78
|
+
)
|
|
79
|
+
logger.error(error)
|
|
80
|
+
record_task_error_exit(error)
|
|
81
|
+
log_file.file.open("a")
|
|
82
|
+
log_file.write(
|
|
83
|
+
"\r\n ********* Failed to insert size - database entry incomplete *********"
|
|
84
|
+
)
|
|
85
|
+
log_file.file.close()
|
|
86
|
+
if size_dict["verbose"]:
|
|
87
|
+
print(
|
|
88
|
+
" ********* Failed to insert size - database entry incomplete *********"
|
|
89
|
+
)
|
|
90
|
+
return
|
|
91
|
+
|
|
92
|
+
if size_dict["height"]:
|
|
93
|
+
if not patient_attributes.patient_size:
|
|
94
|
+
patient_attributes.patient_size = Decimal(size_dict["height"]) / Decimal(
|
|
95
|
+
100.0
|
|
96
|
+
)
|
|
97
|
+
log_file.file.open("a")
|
|
98
|
+
log_file.write(f"\r\n Inserted height of {size_dict['height']} cm")
|
|
99
|
+
log_file.file.close()
|
|
100
|
+
if size_dict["verbose"]:
|
|
101
|
+
print(f" Inserted height of {size_dict['height']} cm")
|
|
102
|
+
elif size_upload.overwrite:
|
|
103
|
+
existing_height = patient_attributes.patient_size * Decimal(100.0)
|
|
104
|
+
patient_attributes.patient_size = Decimal(size_dict["height"]) / Decimal(
|
|
105
|
+
100.0
|
|
106
|
+
)
|
|
107
|
+
log_file.file.open("a")
|
|
108
|
+
log_file.write(
|
|
109
|
+
f"\r\n Inserted height of {size_dict['height']} cm replacing {existing_height:.0f} cm"
|
|
110
|
+
)
|
|
111
|
+
log_file.file.close()
|
|
112
|
+
if size_dict["verbose"]:
|
|
113
|
+
print(
|
|
114
|
+
f" Inserted height of {size_dict['height']} cm replacing {existing_height:.0f} cm"
|
|
115
|
+
)
|
|
116
|
+
else:
|
|
117
|
+
existing_height = patient_attributes.patient_size * Decimal(100.0)
|
|
118
|
+
log_file.file.open("a")
|
|
119
|
+
log_file.write(
|
|
120
|
+
f"\r\n Height of {size_dict['height']} cm not inserted as {existing_height:.0f} cm "
|
|
121
|
+
f"already in the database"
|
|
122
|
+
)
|
|
123
|
+
log_file.file.close()
|
|
124
|
+
if size_dict["verbose"]:
|
|
125
|
+
print(
|
|
126
|
+
f" Height of {size_dict['height']} cm not inserted as {existing_height:.0f} cm already in "
|
|
127
|
+
f"the database"
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
if size_dict["weight"]:
|
|
131
|
+
if not patient_attributes.patient_weight:
|
|
132
|
+
patient_attributes.patient_weight = size_dict["weight"]
|
|
133
|
+
log_file.file.open("a")
|
|
134
|
+
log_file.write(f"\r\n Inserted weight of {size_dict['weight']} kg")
|
|
135
|
+
log_file.file.close()
|
|
136
|
+
if size_dict["verbose"]:
|
|
137
|
+
print(f" Inserted weight of {size_dict['weight']} kg")
|
|
138
|
+
elif size_upload.overwrite:
|
|
139
|
+
existing_weight = patient_attributes.patient_weight
|
|
140
|
+
patient_attributes.patient_weight = size_dict["weight"]
|
|
141
|
+
log_file.file.open("a")
|
|
142
|
+
log_file.write(
|
|
143
|
+
f"\r\n Inserted weight of {size_dict['weight']} kg replacing {existing_weight:.1f} kg"
|
|
144
|
+
)
|
|
145
|
+
log_file.file.close()
|
|
146
|
+
if size_dict["verbose"]:
|
|
147
|
+
print(
|
|
148
|
+
f" Inserted weight of {size_dict['weight']} kg replacing {existing_weight:.1f} kg"
|
|
149
|
+
)
|
|
150
|
+
else:
|
|
151
|
+
log_file.file.open("a")
|
|
152
|
+
log_file.write(
|
|
153
|
+
f"\r\n Weight of {size_dict['weight']} kg not inserted as "
|
|
154
|
+
f"{patient_attributes.patient_weight:.1f} kg already in the database"
|
|
155
|
+
)
|
|
156
|
+
log_file.file.close()
|
|
157
|
+
if size_dict["verbose"]:
|
|
158
|
+
print(
|
|
159
|
+
f" Weight of {size_dict['weight']} kg not inserted as "
|
|
160
|
+
f"{patient_attributes.patient_weight:.1f} kg already in the database"
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
patient_attributes.save()
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _ptsizeinsert(size_upload=None, size_dict=None):
|
|
167
|
+
|
|
168
|
+
log_file = size_upload.logfile
|
|
169
|
+
if (size_dict["height"] or size_dict["weight"]) and size_dict["acc_no"]:
|
|
170
|
+
if not size_dict["si_uid"]:
|
|
171
|
+
exams = GeneralStudyModuleAttr.objects.filter(
|
|
172
|
+
accession_number__exact=size_dict["acc_no"]
|
|
173
|
+
)
|
|
174
|
+
else:
|
|
175
|
+
exams = GeneralStudyModuleAttr.objects.filter(
|
|
176
|
+
study_instance_uid__exact=size_dict["acc_no"]
|
|
177
|
+
)
|
|
178
|
+
if exams:
|
|
179
|
+
for exam in exams:
|
|
180
|
+
log_file.file.open("a")
|
|
181
|
+
log_file.write(f"\r\n{size_dict['acc_no']}:")
|
|
182
|
+
log_file.file.close()
|
|
183
|
+
if size_dict["verbose"]:
|
|
184
|
+
print(size_dict["acc_no"])
|
|
185
|
+
_patientstudymoduleattributes(
|
|
186
|
+
size_upload=size_upload, exam=exam, size_dict=size_dict
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
db.reset_queries()
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def websizeimport(csv_pk=None):
|
|
193
|
+
"""Task to import patient size data from the OpenREM web interface.
|
|
194
|
+
|
|
195
|
+
:param csv_pk: Database index key for the import record, containing
|
|
196
|
+
the path to the import csv file and the field header details.
|
|
197
|
+
|
|
198
|
+
"""
|
|
199
|
+
|
|
200
|
+
if csv_pk:
|
|
201
|
+
size_upload = SizeUpload.objects.all().filter(id__exact=csv_pk)[0]
|
|
202
|
+
size_upload.task_id = get_or_generate_task_uuid()
|
|
203
|
+
datestamp = datetime.datetime.now()
|
|
204
|
+
size_upload.import_date = datestamp
|
|
205
|
+
size_upload.progress = "Patient size data import started"
|
|
206
|
+
size_upload.status = "CURRENT"
|
|
207
|
+
size_upload.save()
|
|
208
|
+
if (
|
|
209
|
+
size_upload.id_type
|
|
210
|
+
and size_upload.id_field
|
|
211
|
+
and size_upload.height_field
|
|
212
|
+
and size_upload.weight_field
|
|
213
|
+
):
|
|
214
|
+
si_uid = False
|
|
215
|
+
verbose = False
|
|
216
|
+
if size_upload.id_type == "si-uid":
|
|
217
|
+
si_uid = True
|
|
218
|
+
|
|
219
|
+
log_file = "pt_size_import_log_{0}.txt".format(
|
|
220
|
+
datestamp.strftime("%Y%m%d-%H%M%S%f")
|
|
221
|
+
)
|
|
222
|
+
headerrow = ContentFile(
|
|
223
|
+
f"Patient size import from {size_upload.sizefile.name}\r\n"
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
try:
|
|
227
|
+
size_upload.logfile.save(log_file, headerrow)
|
|
228
|
+
except OSError as e:
|
|
229
|
+
error = (
|
|
230
|
+
"Error saving export file - please contact an administrator. "
|
|
231
|
+
"Error({0}): {1}".format(e.errno, e.strerror)
|
|
232
|
+
)
|
|
233
|
+
size_upload.progress = error
|
|
234
|
+
size_upload.status = "ERROR"
|
|
235
|
+
size_upload.save()
|
|
236
|
+
record_task_error_exit(error)
|
|
237
|
+
return
|
|
238
|
+
except:
|
|
239
|
+
error = (
|
|
240
|
+
"Unexpected error saving export file - please contact an "
|
|
241
|
+
"administrator: {0}".format(sys.exc_info()[0])
|
|
242
|
+
)
|
|
243
|
+
size_upload.progress = error
|
|
244
|
+
size_upload.status = "ERROR"
|
|
245
|
+
size_upload.save()
|
|
246
|
+
record_task_error_exit(error)
|
|
247
|
+
return
|
|
248
|
+
|
|
249
|
+
log_file = size_upload.logfile
|
|
250
|
+
log_file.file.close()
|
|
251
|
+
# Method used for opening and writing to file as per https://code.djangoproject.com/ticket/13809
|
|
252
|
+
|
|
253
|
+
size_upload.sizefile.open(mode="r")
|
|
254
|
+
csv_file = size_upload.sizefile.readlines()
|
|
255
|
+
size_upload.num_records = len(csv_file) - 1
|
|
256
|
+
size_upload.save()
|
|
257
|
+
try:
|
|
258
|
+
dataset = csv.DictReader(csv_file)
|
|
259
|
+
for i, line in enumerate(dataset):
|
|
260
|
+
size_upload.progress = (
|
|
261
|
+
f"Processing row {i + 1} of {size_upload.num_records}"
|
|
262
|
+
)
|
|
263
|
+
size_upload.save()
|
|
264
|
+
size_dict = {
|
|
265
|
+
"acc_no": line[size_upload.id_field],
|
|
266
|
+
"height": line[size_upload.height_field],
|
|
267
|
+
"weight": line[size_upload.weight_field],
|
|
268
|
+
"si_uid": si_uid,
|
|
269
|
+
"verbose": verbose,
|
|
270
|
+
}
|
|
271
|
+
_ptsizeinsert(size_upload=size_upload, size_dict=size_dict)
|
|
272
|
+
finally:
|
|
273
|
+
size_upload.sizefile.delete()
|
|
274
|
+
size_upload.processtime = (
|
|
275
|
+
datetime.datetime.now() - datestamp
|
|
276
|
+
).total_seconds()
|
|
277
|
+
size_upload.status = "COMPLETE"
|
|
278
|
+
size_upload.save()
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def _create_parser():
|
|
282
|
+
parser = argparse.ArgumentParser(
|
|
283
|
+
description="Import height and weight data from a CSV file into an OpenREM database. If either height or "
|
|
284
|
+
"weight is missing just add a blank column with an appropriate title."
|
|
285
|
+
)
|
|
286
|
+
parser.add_argument(
|
|
287
|
+
"-u",
|
|
288
|
+
"--si-uid",
|
|
289
|
+
action="store_true",
|
|
290
|
+
help="use Study Instance UID instead of Accession Number",
|
|
291
|
+
)
|
|
292
|
+
parser.add_argument(
|
|
293
|
+
"-v", "--verbose", help="also print log to shell", action="store_true"
|
|
294
|
+
)
|
|
295
|
+
parser.add_argument(
|
|
296
|
+
"-o", "--overwrite", help="overwrite existing values", action="store_true"
|
|
297
|
+
)
|
|
298
|
+
parser.add_argument(
|
|
299
|
+
"csvfile", help="csv file with height, weight and study identifier"
|
|
300
|
+
)
|
|
301
|
+
parser.add_argument(
|
|
302
|
+
"id", help="column title for the accession number or study instance UID"
|
|
303
|
+
)
|
|
304
|
+
parser.add_argument(
|
|
305
|
+
"height", help="column title for the patient height, values in cm"
|
|
306
|
+
)
|
|
307
|
+
parser.add_argument(
|
|
308
|
+
"weight", help="column title for the patient weight, values in kg"
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
return parser
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def csv2db():
|
|
315
|
+
"""Import patient height and weight data from csv RIS exports. Called from ``openrem_ptsizecsv.py`` script
|
|
316
|
+
|
|
317
|
+
:param args: sys.argv from the command line call
|
|
318
|
+
|
|
319
|
+
Example::
|
|
320
|
+
|
|
321
|
+
openrem_ptsizecsv.py -s MyRISExport.csv StudyInstanceUID height weight
|
|
322
|
+
|
|
323
|
+
"""
|
|
324
|
+
|
|
325
|
+
args = _create_parser().parse_args()
|
|
326
|
+
|
|
327
|
+
with open(args.csvfile) as csv_file:
|
|
328
|
+
dataset = csv.DictReader(csv_file)
|
|
329
|
+
fieldnames = dataset.fieldnames
|
|
330
|
+
arg_headers = [args.id, args.height, args.weight]
|
|
331
|
+
if not all(header in fieldnames for header in arg_headers):
|
|
332
|
+
msg = f"Error: one or more of {arg_headers} not found in csv file"
|
|
333
|
+
print(msg)
|
|
334
|
+
record_task_error_exit(msg)
|
|
335
|
+
return
|
|
336
|
+
size_upload = SizeUpload()
|
|
337
|
+
date_stamp = datetime.datetime.now()
|
|
338
|
+
size_upload.import_date = date_stamp
|
|
339
|
+
size_upload.task_id = uuid.uuid4()
|
|
340
|
+
size_upload.progress = "Patient size data import from shell started"
|
|
341
|
+
size_upload.status = "CURRENT"
|
|
342
|
+
size_upload.overwrite = args.overwrite
|
|
343
|
+
size_upload.save()
|
|
344
|
+
log_file_name = "pt_size_import_log_{0}.txt".format(
|
|
345
|
+
date_stamp.strftime("%Y%m%d-%H%M%S%f")
|
|
346
|
+
)
|
|
347
|
+
log_header_row = ContentFile(f"Patient size import from {args.csvfile}\r\n")
|
|
348
|
+
size_upload.logfile.save(log_file_name, log_header_row)
|
|
349
|
+
size_upload.save()
|
|
350
|
+
log_file = size_upload.logfile
|
|
351
|
+
log_file.file.close()
|
|
352
|
+
size_upload.num_records = len(csv_file.readlines())
|
|
353
|
+
size_upload.save()
|
|
354
|
+
csv_file.seek(0)
|
|
355
|
+
|
|
356
|
+
for line in dataset:
|
|
357
|
+
size_dict = {
|
|
358
|
+
"acc_no": line[args.id],
|
|
359
|
+
"height": line[args.height],
|
|
360
|
+
"weight": line[args.weight],
|
|
361
|
+
"si_uid": args.si_uid,
|
|
362
|
+
"verbose": args.verbose,
|
|
363
|
+
}
|
|
364
|
+
_ptsizeinsert(size_upload=size_upload, size_dict=size_dict)
|
|
365
|
+
|
|
366
|
+
size_upload.processtime = (datetime.datetime.now() - date_stamp).total_seconds()
|
|
367
|
+
size_upload.status = "COMPLETE"
|
|
368
|
+
size_upload.save()
|