From 4ec97a07e0eee478a470fb8f3ed6c47f498428bb Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Tue, 28 May 2024 14:17:35 +0300 Subject: [PATCH] Enforce ruff/bugbear rule B904 B904 Within an `except` clause, raise exceptions with `raise ... from err` or `raise ... from None` to distinguish them from errors in exception handling --- bin/create_iods_modules.py | 4 ++-- src/highdicom/_module_utils.py | 4 ++-- src/highdicom/ann/content.py | 10 +++++----- src/highdicom/color.py | 10 ++++++---- src/highdicom/io.py | 22 ++++++++++++++-------- src/highdicom/ko/sop.py | 4 ++-- src/highdicom/legacy/sop.py | 18 ++++++++++-------- src/highdicom/pm/sop.py | 12 +++++++----- src/highdicom/seg/sop.py | 2 +- src/highdicom/sr/templates.py | 4 ++-- src/highdicom/sr/utils.py | 8 ++++---- src/highdicom/sr/value_types.py | 16 ++++++++-------- 12 files changed, 63 insertions(+), 51 deletions(-) diff --git a/bin/create_iods_modules.py b/bin/create_iods_modules.py index 5f48deaf..912ca235 100755 --- a/bin/create_iods_modules.py +++ b/bin/create_iods_modules.py @@ -102,8 +102,8 @@ def _create_modules(directory): # https://github.com/innolitics/dicom-standard/tree/master/standard try: directory = sys.argv[1] - except IndexError: - raise ValueError('Path to directory must be provided.') + except IndexError as e: + raise ValueError('Path to directory must be provided.') from e if not os.path.exists(directory): raise OSError('Path does not exist: "{}"'.format(directory)) if not os.path.isdir(directory): diff --git a/src/highdicom/_module_utils.py b/src/highdicom/_module_utils.py index f73f246a..eccd5d90 100644 --- a/src/highdicom/_module_utils.py +++ b/src/highdicom/_module_utils.py @@ -92,8 +92,8 @@ def check_required_attributes( for p in base_path: try: tree = tree['attributes'][p] - except KeyError: - raise AttributeError(f"Invalid base path: {base_path}.") + except KeyError as e: + raise AttributeError(f"Invalid base path: {base_path}.") from e # Define recursive function def check( diff --git a/src/highdicom/ann/content.py b/src/highdicom/ann/content.py index 514c98e5..b2629c0b 100644 --- a/src/highdicom/ann/content.py +++ b/src/highdicom/ann/content.py @@ -111,7 +111,7 @@ def get_values(self, number_of_annotations: int) -> np.ndarray: f'annotation indices: {error}. This may either be due to ' 'incorrect encoding of the measurements or due to incorrectly ' 'specified "number_of_annotations".' - ) + ) from error return values @classmethod @@ -339,11 +339,11 @@ def __init__( try: coordinates = np.concatenate(graphic_data, axis=0) - except ValueError: + except ValueError as e: raise ValueError( 'Items of argument "graphic_data" must be arrays with the ' 'same dimensions.' - ) + ) from e if coordinates.dtype.kind in ('u', 'i'): coordinates = coordinates.astype(np.float32) @@ -420,8 +420,8 @@ def __init__( ) try: measured_values = item.get_values(self.NumberOfAnnotations) - except IndexError: - raise ValueError(error_message) + except IndexError as e: + raise ValueError(error_message) from e if len(measured_values) != self.NumberOfAnnotations: # This should not occur, but safety first. raise ValueError(error_message) diff --git a/src/highdicom/color.py b/src/highdicom/color.py index 8a52dc81..93f6e4fd 100644 --- a/src/highdicom/color.py +++ b/src/highdicom/color.py @@ -87,8 +87,8 @@ def __init__(self, icc_profile: bytes): """ try: self._icc_transform = self._build_icc_transform(icc_profile) - except OSError: - raise ValueError('Could not read ICC Profile.') + except OSError as e: + raise ValueError('Could not read ICC Profile.') from e def transform_frame(self, array: np.ndarray) -> np.ndarray: """Transforms a frame by applying the ICC profile. @@ -138,8 +138,10 @@ def _build_icc_transform(icc_profile: bytes) -> ImageCmsTransform: profile: bytes try: profile = ImageCmsProfile(BytesIO(icc_profile)) - except OSError: - raise ValueError('Cannot read ICC Profile in image metadata.') + except OSError as e: + raise ValueError( + 'Cannot read ICC Profile in image metadata.' + ) from e name = getProfileName(profile).strip() description = getProfileDescription(profile).strip() logger.debug(f'found ICC Profile "{name}": "{description}"') diff --git a/src/highdicom/io.py b/src/highdicom/io.py index bb44610c..69d5195d 100644 --- a/src/highdicom/io.py +++ b/src/highdicom/io.py @@ -313,12 +313,14 @@ def open(self) -> None: if self._fp is None: try: self._fp = DicomFile(str(self._filename), mode='rb') - except FileNotFoundError: - raise FileNotFoundError(f'File not found: "{self._filename}"') - except Exception: + except FileNotFoundError as e: + raise FileNotFoundError( + f'File not found: "{self._filename}"' + ) from e + except Exception as e: raise OSError( f'Could not open file for reading: "{self._filename}"' - ) + ) from e is_little_endian, is_implicit_VR = self._check_file_format(self._fp) self._fp.is_little_endian = is_little_endian self._fp.is_implicit_VR = is_implicit_VR @@ -378,7 +380,9 @@ def _read_metadata(self) -> None: try: metadata = dcmread(self._fp, stop_before_pixels=True) except Exception as err: - raise OSError(f'DICOM metadata cannot be read from file: "{err}"') + raise OSError( + f'DICOM metadata cannot be read from file: "{err}"' + ) from err # Cache Transfer Syntax UID, since we need it to decode frame items self._transfer_syntax_uid = UID(metadata.file_meta.TransferSyntaxUID) @@ -392,10 +396,10 @@ def _read_metadata(self) -> None: # Determine whether dataset contains a Pixel Data element try: tag = TupleTag(self._fp.read_tag()) - except EOFError: + except EOFError as e: raise ValueError( 'Dataset does not represent an image information entity.' - ) + ) from e if int(tag) not in _PIXEL_DATA_TAGS: raise ValueError( 'Dataset does not represent an image information entity.' @@ -413,7 +417,9 @@ def _read_metadata(self) -> None: try: self._basic_offset_table = _get_bot(self._fp, number_of_frames) except Exception as err: - raise OSError(f'Failed to build Basic Offset Table: "{err}"') + raise OSError( + f'Failed to build Basic Offset Table: "{err}"' + ) from err self._first_frame_offset = self._fp.tell() else: if self._fp.is_implicit_VR: diff --git a/src/highdicom/ko/sop.py b/src/highdicom/ko/sop.py index 454abc66..44c93034 100644 --- a/src/highdicom/ko/sop.py +++ b/src/highdicom/ko/sop.py @@ -177,11 +177,11 @@ def resolve_reference(self, sop_instance_uid: str) -> Tuple[str, str, str]: """ try: return self._reference_lut[sop_instance_uid] - except KeyError: + except KeyError as e: raise ValueError( 'Could not find any evidence for SOP Instance UID ' f'"{sop_instance_uid}" in KOS document.' - ) + ) from e @classmethod def from_dataset(cls, dataset: Dataset) -> 'KeyObjectSelectionDocument': diff --git a/src/highdicom/legacy/sop.py b/src/highdicom/legacy/sop.py index 2008191e..18801937 100644 --- a/src/highdicom/legacy/sop.py +++ b/src/highdicom/legacy/sop.py @@ -62,8 +62,10 @@ def _convert_legacy_to_enhanced( from highdicom._modules import MODULE_ATTRIBUTE_MAP try: ref_ds = sf_datasets[0] - except IndexError: - raise ValueError('No data sets of single-frame legacy images provided.') + except IndexError as e: + raise ValueError( + 'No data sets of single-frame legacy images provided.' + ) from e if mf_dataset is None: mf_dataset = Dataset() @@ -455,8 +457,8 @@ def __init__( try: ref_ds = legacy_datasets[0] - except IndexError: - raise ValueError('No DICOM data sets of provided.') + except IndexError as e: + raise ValueError('No DICOM data sets of provided.') from e if ref_ds.Modality != 'MR': raise ValueError( @@ -548,8 +550,8 @@ def __init__( try: ref_ds = legacy_datasets[0] - except IndexError: - raise ValueError('No DICOM data sets of provided.') + except IndexError as e: + raise ValueError('No DICOM data sets of provided.') from e if ref_ds.Modality != 'CT': raise ValueError( @@ -627,8 +629,8 @@ def __init__( try: ref_ds = legacy_datasets[0] - except IndexError: - raise ValueError('No DICOM data sets of provided.') + except IndexError as e: + raise ValueError('No DICOM data sets of provided.') from e if ref_ds.Modality != 'PT': raise ValueError( diff --git a/src/highdicom/pm/sop.py b/src/highdicom/pm/sop.py index 9590daed..091e79dc 100644 --- a/src/highdicom/pm/sop.py +++ b/src/highdicom/pm/sop.py @@ -456,8 +456,8 @@ def __init__( sffg_item.RealWorldValueMappingSequence = real_world_value_mappings try: real_world_value_mappings[0] - except IndexError: - raise TypeError(error_message) + except IndexError as e: + raise TypeError(error_message) from e if not isinstance( real_world_value_mappings[0], RealWorldValueMapping @@ -479,8 +479,8 @@ def __init__( ) try: real_world_value_mappings[0][0] - except IndexError: - raise TypeError(error_message) + except IndexError as e: + raise TypeError(error_message) from e if not isinstance( real_world_value_mappings[0][0], RealWorldValueMapping @@ -700,7 +700,9 @@ def __init__( palette_color_lut_transformation, 'PaletteColorLookupTableUID' ): - self.PaletteColorLookupTableUID = palette_color_lut_transformation.PaletteColorLookupTableUID + self.PaletteColorLookupTableUID = ( + palette_color_lut_transformation.PaletteColorLookupTableUID + ) else: self.PixelPresentation = 'MONOCHROME' diff --git a/src/highdicom/seg/sop.py b/src/highdicom/seg/sop.py index be933a3d..cc4df28d 100644 --- a/src/highdicom/seg/sop.py +++ b/src/highdicom/seg/sop.py @@ -2061,7 +2061,7 @@ def __init__( 'Could not determine position of plane ' f'#{plane_index} in three dimensional coordinate ' f'system based on dimension index values: {error}' - ) + ) from error else: dimension_index_values = [] diff --git a/src/highdicom/sr/templates.py b/src/highdicom/sr/templates.py index 405e3dde..1a375385 100644 --- a/src/highdicom/sr/templates.py +++ b/src/highdicom/sr/templates.py @@ -624,11 +624,11 @@ def _get_coded_modality(sop_class_uid: str) -> Code: } try: return sopclass_to_modality_map[sop_class_uid] - except KeyError: + except KeyError as e: raise ValueError( 'SOP Class UID does not identify a SOP Class ' 'for storage of an image information entity.' - ) + ) from e class Template(ContentSequence): diff --git a/src/highdicom/sr/utils.py b/src/highdicom/sr/utils.py index f0d7cb36..8f461942 100644 --- a/src/highdicom/sr/utils.py +++ b/src/highdicom/sr/utils.py @@ -138,11 +138,11 @@ def get_coded_name(item: Dataset) -> CodedConcept: """ try: name = item.ConceptNameCodeSequence[0] - except AttributeError: + except AttributeError as e: raise AttributeError( 'Dataset does not contain attribute "ConceptNameCodeSequence" and ' 'thus doesn\'t represent a SR Content Item.' - ) + ) from e return CodedConcept.from_dataset(name) @@ -162,11 +162,11 @@ def get_coded_value(item: Dataset) -> CodedConcept: """ try: value = item.ConceptCodeSequence[0] - except AttributeError: + except AttributeError as e: raise AttributeError( 'Dataset does not contain attribute "ConceptCodeSequence" and ' 'thus doesn\'t represent a SR Content Item of Value Type CODE.' - ) + ) from e return CodedConcept.from_dataset(value) diff --git a/src/highdicom/sr/value_types.py b/src/highdicom/sr/value_types.py index bc96dcb4..3063f62e 100644 --- a/src/highdicom/sr/value_types.py +++ b/src/highdicom/sr/value_types.py @@ -424,12 +424,12 @@ def index(self, val: ContentItem) -> int: # type: ignore[override] error_message = f'Item "{val.name}" is not in Sequence.' try: matches = self._lut[val.name] - except KeyError: - raise ValueError(error_message) + except KeyError as e: + raise ValueError(error_message) from e try: index = matches.index(val) - except ValueError: - raise ValueError(error_message) + except ValueError as e: + raise ValueError(error_message) from e return index def find(self, name: Union[Code, CodedConcept]) -> 'ContentSequence': @@ -618,17 +618,17 @@ def _check_dataset( ) try: ValueTypeValues(dataset.ValueType) - except TypeError: + except TypeError as e: raise ValueError( f'Item #{index} of sequence is not an SR Content Item ' f'because it has unknown Value Type "{dataset.ValueType}":' f'\n{dataset}' - ) - except AttributeError: + ) from e + except AttributeError as e: raise AttributeError( f'Item #{index} of sequence is not an SR Content Item:\n' f'{dataset}' - ) + ) from e if not hasattr(dataset, 'RelationshipType') and not is_root and is_sr: raise AttributeError( f'Item #{index} of sequence is not a value SR Content Item '