Source code for deid.tests.test_dicom_funcs

#!/usr/bin/env python

__author__ = "Vanessa Sochat"
__copyright__ = "Copyright 2016-2022, Vanessa Sochat"
__license__ = "MIT"


import re
import shutil
import tempfile
import unittest

from deid.data import get_dataset
from deid.dicom.parser import DicomParser
from deid.tests.common import create_recipe, get_file, get_same_file
from deid.utils import get_installdir

uuid_regex = "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}"


[docs]class TestDicomFuncs(unittest.TestCase):
[docs] def setUp(self): self.pwd = get_installdir() self.dataset = get_dataset("humans") self.tmpdir = tempfile.mkdtemp() print("\n######################START######################")
[docs] def tearDown(self): shutil.rmtree(self.tmpdir) print("\n######################END########################")
[docs] def test_user_provided_func(self): """ %header REMOVE ALL func:myfunction """ print("Test user provided func") dicom_file = get_file(self.dataset) def myfunction(dicom, value, field, item): from pydicom.tag import Tag tag = Tag(field.element.tag) if tag in dicom: currentvalue = str(dicom.get(tag).value).lower() if "hibbard" in currentvalue: return True return False actions = [{"action": "REMOVE", "field": "ALL", "value": "func:myfunction"}] recipe = create_recipe(actions) # Create a parser, define function for it parser = DicomParser(dicom_file, recipe=recipe) parser.define("myfunction", myfunction) parser.parse() self.assertEqual(160, len(parser.dicom)) with self.assertRaises(KeyError): parser.dicom["ReferringPhysicianName"].value with self.assertRaises(KeyError): parser.dicom["PhysiciansOfRecord"].value with self.assertRaises(KeyError): parser.dicom["RequestingPhysician"].value with self.assertRaises(KeyError): parser.dicom["00331019"].value
[docs] def test_basic_uuid(self): """ %header REPLACE ReferringPhysicianName deid_func:basic_uuid """ print("Test deid_func:basic_uuid") dicom_file = get_file(self.dataset) actions = [ { "action": "REPLACE", "field": "ReferringPhysicianName", "value": "deid_func:basic_uuid", } ] recipe = create_recipe(actions) # Create a parser, define function for it parser = DicomParser(dicom_file, recipe=recipe) parser.parse() # 8905e722-8103-4823-bc8f-8aed967e272d print(parser.dicom["ReferringPhysicianName"].value) assert re.search(uuid_regex, str(parser.dicom["ReferringPhysicianName"].value))
[docs] def test_pydicom_uuid(self): """ %header REPLACE ReferringPhysicianName deid_func:pydicom_uuid """ print("Test deid_func:pydicom_uuid") dicom_file = get_file(self.dataset) actions = [ { "action": "REPLACE", "field": "ReferringPhysicianName", "value": "deid_func:pydicom_uuid", } ] recipe = create_recipe(actions) # Create a parser, define function for it parser = DicomParser(dicom_file, recipe=recipe) parser.parse() # Randomness is anything, but should be all numbers print(parser.dicom["ReferringPhysicianName"].value) name = str(parser.dicom["ReferringPhysicianName"].value) assert re.search("([0-9]|.)+", name) # This is the pydicom default, and we default to stable remapping assert ( name == "2.25.39101090714049289438893821151950032074223798085258118413707" ) # Add a custom prefix # must match '^(0|[1-9][0-9]*)(\\.(0|[1-9][0-9]*))*\\.$' actions = [ { "action": "REPLACE", "field": "ReferringPhysicianName", "value": "deid_func:pydicom_uuid prefix=1.55.", } ] recipe = create_recipe(actions) parser = DicomParser(dicom_file, recipe=recipe) parser.parse() # Randomness is anything, but should be all numbers print(parser.dicom["ReferringPhysicianName"].value) name = str(parser.dicom["ReferringPhysicianName"].value) assert name.startswith("1.55.") # This should always be consistent if we use the original as entropy dicom_file = get_same_file(self.dataset) actions = [ { "action": "REPLACE", "field": "ReferringPhysicianName", "value": "deid_func:pydicom_uuid stable_remapping=false", } ] recipe = create_recipe(actions) parser = DicomParser(dicom_file, recipe=recipe) parser.parse() # Randomness is anything, but should be all numbers print(parser.dicom["ReferringPhysicianName"].value) name = str(parser.dicom["ReferringPhysicianName"].value) assert ( name != "2.25.39101090714049289438893821151950032074223798085258118413707" )
[docs] def test_suffix_uuid(self): """ %header REPLACE ReferringPhysicianName deid_func:suffix_uuid """ print("Test deid_func:basic_uuid") dicom_file = get_file(self.dataset) actions = [ { "action": "REPLACE", "field": "ReferringPhysicianName", "value": "deid_func:suffix_uuid", } ] recipe = create_recipe(actions) # Create a parser, define function for it parser = DicomParser(dicom_file, recipe=recipe) parser.parse() # 8905e722-8103-4823-bc8f-8aed967e272d print(parser.dicom["ReferringPhysicianName"].value) name = str(parser.dicom["ReferringPhysicianName"].value) assert "referringphysicianname-" in name assert re.search(uuid_regex, name)
[docs] def test_dicom_uuid(self): """ %header REPLACE ReferringPhysicianName deid_func:suffix_uuid org=myorg """ print("Test deid_func:dicom_uuid") dicom_file = get_file(self.dataset) actions = [ { "action": "REPLACE", "field": "ReferringPhysicianName", "value": "deid_func:dicom_uuid org_root=1.2.826.0.1.3680043.10.188", } ] recipe = create_recipe(actions) # Create a parser, define function for it parser = DicomParser(dicom_file, recipe=recipe) parser.parse() # 8905e722-8103-4823-bc8f-8aed967e272d print(parser.dicom["ReferringPhysicianName"].value) name = str(parser.dicom["ReferringPhysicianName"].value) assert "1.2.826.0.1.3680043.10.188" in name assert len(name) == 64
[docs] def test_dicom_jitter(self): """RECIPE RULE REPLACE AcquisitionDate deid_func:jitter days=1 """ print("Test deid_func:jitter") dicom_file = get_file(self.dataset) actions = [ { "action": "REPLACE", "field": "AcquisitionDate", "value": "deid_func:jitter days=1", } ] recipe = create_recipe(actions) # Create a parser, define function for it parser = DicomParser(dicom_file, recipe=recipe) original_date = parser.dicom.AcquisitionDate assert original_date == "20230101" parser.parse() jittered_date = str(parser.dicom["AcquisitionDate"].value) assert jittered_date == "20230102" # Add a day and a year actions = [ { "action": "REPLACE", "field": "AcquisitionDate", "value": "deid_func:jitter days=1 years=1", } ] recipe = create_recipe(actions) # Create a parser, define function for it parser = DicomParser(dicom_file, recipe=recipe) parser.parse() jittered_date = str(parser.dicom["AcquisitionDate"].value) assert jittered_date == "20240102"
if __name__ == "__main__": unittest.main()