diff --git a/src/highdicom/base.py b/src/highdicom/base.py index 6008bd09..6f355dd0 100644 --- a/src/highdicom/base.py +++ b/src/highdicom/base.py @@ -60,6 +60,10 @@ def __init__( device_serial_number: str | None = None, institution_name: str | None = None, institutional_department_name: str | None = None, + content_date: str | datetime.date | None = None, + content_time: str | datetime.time | None = None, + series_date: str | datetime.date | None = None, + series_time: str | datetime.time | None = None, ): """ Parameters @@ -121,6 +125,18 @@ def __init__( institutional_department_name: Union[str, None], optional Name of the department of the person or device that creates the SR document instance. + content_date: str | datetime.date | None, optional + Date the content of this instance was created. If not specified, + the current date will be used. + content_time: str | datetime.time | None, optional + Time the content of this instance was created. If not specified, + the current time will be used. + series_date: str | datetime.date | None, optional + Date the series was started. This should be the same for all + instances in a series. + series_time: str | datetime.time | None, optional + Time the series was started. This should be the same for all + instances in a series. Note ---- @@ -207,7 +223,11 @@ def __init__( _check_long_string(device_serial_number) self.DeviceSerialNumber = device_serial_number if software_versions is not None: - _check_long_string(software_versions) + if not isinstance(software_versions, str): + for v in software_versions: + _check_long_string(v) + else: + _check_long_string(software_versions) self.SoftwareVersions = software_versions if institution_name is not None: _check_long_string(institution_name) @@ -227,11 +247,59 @@ def __init__( ) self.InstanceNumber = instance_number + now = datetime.datetime.now() + self.InstanceCreationDate = DA(now.date()) + self.InstanceCreationTime = TM(now.time()) + # Content Date and Content Time are not present in all IODs if is_attribute_in_iod('ContentDate', sop_class_uid): - self.ContentDate = DA(datetime.datetime.now().date()) + if content_date is None: + if content_time is not None: + raise TypeError( + "'content_time' may not be specified without " + "'content_date'." + ) + content_date = now.date() + content_date = DA(content_date) + self.ContentDate = content_date + elif content_date is not None: + raise TypeError( + f"'content_date' should not be specified for SOP Class UID: " + f"{sop_class_uid}" + ) if is_attribute_in_iod('ContentTime', sop_class_uid): - self.ContentTime = TM(datetime.datetime.now().time()) + if content_time is None: + content_time = now.time() + content_time = TM(content_time) + self.ContentTime = content_time + elif content_time is not None: + raise TypeError( + f"'content_time' should not be specified for SOP Class UID: " + f"{sop_class_uid}" + ) + + if series_date is not None: + series_date = DA(series_date) + if content_date is not None: + if series_date > content_date: + raise ValueError( + "'series_date' must not be later than 'content_date'." + ) + self.SeriesDate = series_date + if series_time is not None: + series_time = TM(series_time) + if series_date is None: + raise TypeError( + "'series_time' may not be specified without " + "'series_date'." + ) + if content_time is not None: + if series_time > content_time: + raise ValueError( + "'series_time' must not be later than content time." + ) + self.SeriesTime = series_time + if content_qualification is not None: content_qualification = ContentQualificationValues( content_qualification diff --git a/tests/test_base.py b/tests/test_base.py index 8fe51504..3f400a92 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -1,3 +1,4 @@ +import datetime import re import pytest import unittest @@ -59,6 +60,92 @@ def test_type_3_attributes(self): ) assert instance.SoftwareVersions is not None assert instance.ManufacturerModelName is not None + assert hasattr(instance, 'ContentDate') + assert hasattr(instance, 'ContentTime') + assert not hasattr(instance, 'SeriesDate') + assert not hasattr(instance, 'SeriesTime') + + def test_content_time_without_date(self): + msg = ( + "'content_time' may not be specified without " + "'content_date'." + ) + with pytest.raises(TypeError, match=msg): + SOPClass( + study_instance_uid=UID(), + series_instance_uid=UID(), + series_number=1, + sop_instance_uid=UID(), + sop_class_uid='1.2.840.10008.5.1.4.1.1.88.33', + instance_number=1, + modality='SR', + manufacturer='highdicom', + manufacturer_model_name='foo-bar', + software_versions='v1.0.0', + transfer_syntax_uid=ExplicitVRLittleEndian, + content_time=datetime.time(12, 34, 56), + ) + + def test_series_datetime(self): + instance = SOPClass( + study_instance_uid=UID(), + series_instance_uid=UID(), + series_number=1, + sop_instance_uid=UID(), + sop_class_uid='1.2.840.10008.5.1.4.1.1.88.33', + instance_number=1, + modality='SR', + manufacturer='highdicom', + manufacturer_model_name='foo-bar', + software_versions='v1.0.0', + transfer_syntax_uid=ExplicitVRLittleEndian, + series_date=datetime.date(2000, 12, 1), + series_time=datetime.time(12, 34, 56), + ) + assert hasattr(instance, 'SeriesDate') + assert hasattr(instance, 'SeriesTime') + + def test_series_date_without_time(self): + msg = ( + "'series_time' may not be specified without " + "'series_date'." + ) + with pytest.raises(TypeError, match=msg): + SOPClass( + study_instance_uid=UID(), + series_instance_uid=UID(), + series_number=1, + sop_instance_uid=UID(), + sop_class_uid='1.2.840.10008.5.1.4.1.1.88.33', + instance_number=1, + modality='SR', + manufacturer='highdicom', + manufacturer_model_name='foo-bar', + software_versions='v1.0.0', + transfer_syntax_uid=ExplicitVRLittleEndian, + series_time=datetime.time(12, 34, 56), + ) + + def test_series_date_after_content(self): + msg = ( + "'series_date' must not be later than 'content_date'." + ) + with pytest.raises(ValueError, match=msg): + SOPClass( + study_instance_uid=UID(), + series_instance_uid=UID(), + series_number=1, + sop_instance_uid=UID(), + sop_class_uid='1.2.840.10008.5.1.4.1.1.88.33', + instance_number=1, + modality='SR', + manufacturer='highdicom', + manufacturer_model_name='foo-bar', + software_versions='v1.0.0', + transfer_syntax_uid=ExplicitVRLittleEndian, + content_date=datetime.date(2000, 12, 1), + series_date=datetime.date(2000, 12, 2), + ) def test_big_endian(self): with pytest.raises(ValueError):