diff --git a/build.py b/build.py index 66c4d1ca0..21682eaa2 100644 --- a/build.py +++ b/build.py @@ -13,10 +13,10 @@ import re import sys from pathlib import Path -from typing import Any, Dict, List +from typing import Any -def get_entry_point(filename: Path, prefix: str, import_path: str) -> List[str]: +def get_entry_point(filename: Path, prefix: str, import_path: str) -> list[str]: """Returns the entry point string for a given path. This looks for LIBTBX_SET_DISPATCHER_NAME, and a root function @@ -54,7 +54,7 @@ def get_entry_point(filename: Path, prefix: str, import_path: str) -> List[str]: return [f"{prefix}.{filename.stem}={import_path}.{filename.stem}:run"] -def enumerate_format_classes(path: Path) -> List[str]: +def enumerate_format_classes(path: Path) -> list[str]: """Find all Format*.py files and contained Format classes in a path""" format_classes = [] for filename in path.glob("Format*.py"): @@ -81,7 +81,7 @@ def enumerate_format_classes(path: Path) -> List[str]: return format_classes -def build(setup_kwargs: Dict[str, Any]) -> None: +def build(setup_kwargs: dict[str, Any]) -> None: """Called by setup.py to inject any dynamic configuration""" package_path = Path(__file__).parent / "src" / "dxtbx" entry_points = setup_kwargs.setdefault("entry_points", {}) diff --git a/cmake/read_env.py b/cmake/read_env.py index db761d9b5..f9bb2f245 100644 --- a/cmake/read_env.py +++ b/cmake/read_env.py @@ -45,7 +45,7 @@ def _read_obj(obj, prev=None): return obj -class prop_object(object): +class prop_object: """Object that can convert itself to a dictionary""" def to_dict(self): @@ -63,13 +63,13 @@ class _pathed_prop_object(prop_object): return _pathed_prop_object -class relocatable_path(object): +class relocatable_path: def __repr__(self): _all_relocatable_paths.add(self) return os.path.normpath(os.path.join(str(self._anchor), self.relocatable)) -class absolute_path(object): +class absolute_path: def __init__(self, path): # This init not used by unpickle - only for rewriting in here self._path = str(path) diff --git a/newsfragments/769.removal b/newsfragments/769.removal new file mode 100644 index 000000000..4a9b23023 --- /dev/null +++ b/newsfragments/769.removal @@ -0,0 +1 @@ +Python 3.10 is now the minimum required diff --git a/src/dxtbx/__init__.py b/src/dxtbx/__init__.py index 9d9664823..1aa9e74c9 100644 --- a/src/dxtbx/__init__.py +++ b/src/dxtbx/__init__.py @@ -45,9 +45,7 @@ class IncorrectFormatError(RuntimeError): """ def __init__(self, format_instance, filename): - super().__init__( - "Could not open {} as {}".format(filename, str(format_instance)) - ) + super().__init__(f"Could not open {filename} as {str(format_instance)}") self.args = (format_instance, filename) diff --git a/src/dxtbx/dxtbx_format_nexus_ext.pyi b/src/dxtbx/dxtbx_format_nexus_ext.pyi index f4a9ae809..7903c52e7 100644 --- a/src/dxtbx/dxtbx_format_nexus_ext.pyi +++ b/src/dxtbx/dxtbx_format_nexus_ext.pyi @@ -1,9 +1,9 @@ from __future__ import annotations -from typing import Any, Tuple +from typing import Any from scitbx.array_family import flex -def dataset_as_flex_double(dataset_id: Any, selection: Tuple[slice]) -> flex.double: ... -def dataset_as_flex_float(dataset_id: Any, selection: Tuple[slice]) -> flex.float: ... -def dataset_as_flex_int(dataset_id: Any, selection: Tuple[slice]) -> flex.int: ... +def dataset_as_flex_double(dataset_id: Any, selection: tuple[slice]) -> flex.double: ... +def dataset_as_flex_float(dataset_id: Any, selection: tuple[slice]) -> flex.float: ... +def dataset_as_flex_int(dataset_id: Any, selection: tuple[slice]) -> flex.int: ... diff --git a/src/dxtbx/dxtbx_imageset_ext.pyi b/src/dxtbx/dxtbx_imageset_ext.pyi index 8335d3c1a..9debeae44 100644 --- a/src/dxtbx/dxtbx_imageset_ext.pyi +++ b/src/dxtbx/dxtbx_imageset_ext.pyi @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Any, Tuple, Union +from typing import Any, Union from scitbx.array_family import flex @@ -71,7 +71,7 @@ class ImageSet: def get_mask(self, int) -> Any: ... def get_path(self, int) -> Any: ... def get_pedestal(self, int) -> Any: ... - def get_raw_data(self, index: int) -> Tuple[ImageData]: ... + def get_raw_data(self, index: int) -> tuple[ImageData]: ... def get_scan(self) -> Any: ... def has_dynamic_mask(self) -> Any: ... def indices(self) -> Any: ... diff --git a/src/dxtbx/dxtbx_masking_ext.pyi b/src/dxtbx/dxtbx_masking_ext.pyi index 7e89a1cfe..804f14231 100644 --- a/src/dxtbx/dxtbx_masking_ext.pyi +++ b/src/dxtbx/dxtbx_masking_ext.pyi @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Any, Tuple +from typing import Any from scitbx.array_family import flex @@ -31,7 +31,7 @@ class GoniometerShadowMasker: def project_extrema( self, detector: Detector, scan_angle: float ) -> flex.vec2_double: ... - def get_mask(self, detector: Detector, scan_angle: float) -> Tuple[flex.bool]: ... + def get_mask(self, detector: Detector, scan_angle: float) -> tuple[flex.bool]: ... class SmarGonShadowMasker(GoniometerShadowMasker): def __init__(self, goniometer: MultiAxisGoniometer) -> None: ... diff --git a/src/dxtbx/dxtbx_model_ext.pyi b/src/dxtbx/dxtbx_model_ext.pyi index 1de0e1da6..c9fe92c74 100644 --- a/src/dxtbx/dxtbx_model_ext.pyi +++ b/src/dxtbx/dxtbx_model_ext.pyi @@ -1,14 +1,9 @@ from __future__ import annotations +from collections.abc import Iterator, Sequence from enum import Enum from typing import ( Any, - Dict, - Iterator, - List, - Optional, - Sequence, - Tuple, TypeVar, Union, overload, @@ -33,12 +28,12 @@ TExperimentModel = TypeVar( "TExperimentModel", BeamBase, Detector, Goniometer, Scan, CrystalBase, object ) -Vec2Float = Tuple[float, float] -Vec3Float = Tuple[float, float, float] -Vec6Float = Tuple[float, float, float, float, float, float] -Vec9Float = Tuple[float, float, float, float, float, float, float, float, float] -Vec2Int = Tuple[int, int] -Vec4Int = Tuple[int, int, int, int] +Vec2Float = tuple[float, float] +Vec3Float = tuple[float, float, float] +Vec6Float = tuple[float, float, float, float, float, float] +Vec9Float = tuple[float, float, float, float, float, float, float, float, float] +Vec2Int = tuple[int, int] +Vec4Int = tuple[int, int, int, int] ScanPropertyTypes = Union[ flex.int, flex.double, @@ -65,7 +60,7 @@ class BeamBase: def get_s0_at_scan_point(self, index: int) -> Vec3Float: ... def get_s0_at_scan_points(self) -> flex.vec3_double: ... def set_s0_at_scan_points( - self, points: Union[Tuple[Vec3Float], List[Vec3Float]] + self, points: tuple[Vec3Float] | list[Vec3Float] ) -> None: ... def get_sample_to_source_direction(self) -> Vec3Float: ... def get_sample_to_source_distance(self) -> float: ... @@ -144,8 +139,8 @@ class Beam(BeamBase): deg: bool = ..., ) -> None: ... @staticmethod - def from_dict(data: Dict) -> Beam: ... - def to_dict(self) -> Dict: ... + def from_dict(data: dict) -> Beam: ... + def to_dict(self) -> dict: ... @staticmethod def get_probe_from_name(name: str) -> Probe: ... @@ -179,8 +174,8 @@ class PolychromaticBeam(Beam): def set_wavelength_range(self, wavelength_range: Vec2Float) -> None: ... def get_wavelength_range(self) -> Vec2Float: ... @staticmethod - def from_dict(data: Dict) -> PolychromaticBeam: ... - def to_dict(self) -> Dict: ... + def from_dict(data: dict) -> PolychromaticBeam: ... + def to_dict(self) -> dict: ... class CrystalBase: @property @@ -205,7 +200,7 @@ class CrystalBase: def get_real_space_vectors(self) -> flex.vec3_double: ... def get_recalculated_cell_parameter_sd(self) -> Vec6Float: ... def get_recalculated_cell_volume_sd(self) -> float: ... - def get_recalculated_unit_cell(self) -> Optional[unit_cell]: ... + def get_recalculated_unit_cell(self) -> unit_cell | None: ... def get_unit_cell(self) -> unit_cell: ... def get_space_group(self) -> space_group: ... def get_unit_cell_at_scan_point(self, index: int) -> unit_cell: ... @@ -222,11 +217,9 @@ class CrystalBase: self, axis: Vec3Float, angle: float, deg: bool = ... ) -> Any: ... def set_A_at_scan_points( - self, value: Union[List[Vec9Float], Tuple[Vec9Float], flex.mat3_double] - ) -> None: ... - def set_B_covariance( - self, covariance: Union[Tuple[float, ...], flex.double] + self, value: list[Vec9Float] | tuple[Vec9Float] | flex.mat3_double ) -> None: ... + def set_B_covariance(self, covariance: tuple[float, ...] | flex.double) -> None: ... def set_B_covariance_at_scan_points(self, data: flex.double) -> None: ... def set_recalculated_cell_parameter_sd(self, value: Vec6Float) -> None: ... def set_recalculated_cell_volume_sd(self, volume: float) -> None: ... @@ -306,13 +299,13 @@ class Detector: @overload def add_panel(self, panel: Panel) -> Panel: ... @staticmethod - def from_dict(data: Dict) -> Detector: ... - def to_dict(self) -> Dict: ... + def from_dict(data: dict) -> Detector: ... + def to_dict(self) -> dict: ... def get_max_inscribed_resolution(self, s0: Vec3Float) -> float: ... def get_max_resolution(self, s0: Vec3Float) -> float: ... def get_names(self) -> flex.std_string: ... def get_panel_intersection(self, s1: Vec3Float) -> int: ... - def get_ray_intersection(self, s1: Vec3Float) -> Tuple[int, Vec2Float]: ... + def get_ray_intersection(self, s1: Vec3Float) -> tuple[int, Vec2Float]: ... def has_projection_2d(self) -> bool: ... def is_similar_to( self, @@ -380,10 +373,10 @@ class ExperimentList: def __contains__(self, obj: TExperimentModel) -> bool: ... def replace(self, obj: TExperimentModel, withobj: TExperimentModel) -> None: ... def indices( - self, obj: Union[TExperimentModel, FlexPlain[TExperimentModel]] + self, obj: TExperimentModel | FlexPlain[TExperimentModel] ) -> flex.size_t: ... - def remove_on_experiment_identifiers(self, identifiers: List[str]) -> None: ... - def select_on_experiment_identifiers(self, identifiers: List[str]) -> None: ... + def remove_on_experiment_identifiers(self, identifiers: list[str]) -> None: ... + def select_on_experiment_identifiers(self, identifiers: list[str]) -> None: ... def where( self, beam: BeamBase, @@ -419,7 +412,7 @@ class Goniometer(GoniometerBase): @property def num_scan_points(self) -> int: ... @staticmethod - def from_dict(data: Dict) -> Goniometer: ... + def from_dict(data: dict) -> Goniometer: ... def get_fixed_rotation(self) -> Vec9Float: ... def get_num_scan_points(self) -> int: ... def get_rotation_axis(self) -> Vec3Float: ... @@ -444,9 +437,9 @@ class Goniometer(GoniometerBase): def set_setting_rotation(self, rotation: Vec9Float) -> None: ... def set_setting_rotation_at_scan_points( self, - setting_rotations: Union[List[Vec9Float], Tuple[Vec9Float], flex.mat3_double], + setting_rotations: list[Vec9Float] | tuple[Vec9Float] | flex.mat3_double, ) -> Any: ... - def to_dict(self) -> Dict: ... + def to_dict(self) -> dict: ... class KappaDirection(Enum): PlusY = ... @@ -498,8 +491,8 @@ class MultiAxisGoniometer(Goniometer): scan_axis: int, ) -> None: ... @staticmethod - def from_dict(data: Dict) -> MultiAxisGoniometer: ... - def to_dict(self) -> Dict: ... + def from_dict(data: dict) -> MultiAxisGoniometer: ... + def to_dict(self) -> dict: ... def get_angles(self) -> flex.double: ... def set_angles(self, angles: flex.double) -> None: ... def get_axes(self) -> flex.vec3_double: ... @@ -601,7 +594,7 @@ class Panel(PanelData): slow_axis: Vec3Float, origin: Vec3Float, pixel_size: Vec2Float, - image_size: Tuple[int, int], + image_size: tuple[int, int], trusted_range: Vec2Float, thickness: float, material: str, @@ -617,7 +610,7 @@ class Panel(PanelData): slow_axis: Vec3Float, origin: Vec3Float, pixel_size: Vec2Float, - image_size: Tuple[int, int], + image_size: tuple[int, int], trusted_range: Vec2Float, thickness: float, material: str, @@ -627,10 +620,10 @@ class Panel(PanelData): ) -> None: ... @staticmethod @overload - def from_dict(data: Dict) -> Panel: ... + def from_dict(data: dict) -> Panel: ... @staticmethod @overload - def from_dict(data: Dict, dx: flex.double, dy: flex.double) -> Panel: ... + def from_dict(data: dict, dx: flex.double, dy: flex.double) -> Panel: ... def get_beam_centre_px(self, s0: Vec3Float) -> Vec2Float: ... def get_bidirectional_ray_intersection_px(self, s1: Vec3Float) -> Vec2Float: ... def get_cos2_two_theta_array(self, s0: Vec3Float) -> flex.double: ... @@ -652,7 +645,7 @@ class Panel(PanelData): def get_normal_origin_px(self) -> Vec2Float: ... def get_pedestal(self) -> float: ... def get_pixel_lab_coord(self, px: Vec2Float) -> Vec3Float: ... - def get_projection_2d(self) -> Union[Tuple[Vec4Int, Vec2Int], Tuple[()]]: ... + def get_projection_2d(self) -> tuple[Vec4Int, Vec2Int] | tuple[()]: ... def get_px_mm_strategy(self) -> PxMmStrategy: ... def get_ray_intersection_px(self, s1: Vec3Float) -> Vec2Float: ... @overload @@ -663,9 +656,7 @@ class Panel(PanelData): def get_resolution_at_pixel( self, beam: PolychromaticBeam, xy: Vec2Float ) -> float: ... - def get_trusted_range_mask( - self, image: Union[flex.int, flex.double] - ) -> flex.bool: ... + def get_trusted_range_mask(self, image: flex.int | flex.double) -> flex.bool: ... def get_two_theta_array(self, s0: Vec3Float) -> flex.double: ... def get_two_theta_at_pixel(self, s0: Vec3Float, xy: Vec2Float) -> float: ... def get_untrusted_rectangle_mask(self) -> flex.bool: ... @@ -689,7 +680,7 @@ class Panel(PanelData): def set_pedestal(self, pedestal: float) -> None: ... def set_projection_2d(self, rotation: Vec4Int, translation: Vec2Int) -> None: ... def set_px_mm_strategy(self, strategy: PxMmStrategy) -> None: ... - def to_dict(self) -> Dict: ... + def to_dict(self) -> dict: ... class DetectorNode(Panel): @overload @@ -780,13 +771,13 @@ class Scan(ScanBase): def __init__( self, image_range: Vec2Int, - properties_table: Dict, + properties_table: dict, batch_offset: int, deg: bool = ..., ) -> None: ... def append(self, other: Scan, scan_tolerance: float) -> None: ... @staticmethod - def from_dict(data: Dict) -> Scan: ... + def from_dict(data: dict) -> Scan: ... @overload def get_angle_from_array_index(self, index: float, deg: bool = ...) -> float: ... @overload @@ -825,8 +816,8 @@ class Scan(ScanBase): def get_oscillation(self, deg: bool = ...) -> Vec2Float: ... def set_oscillation(self, oscillation: Vec2Float, deg: bool = ...) -> None: ... def get_oscillation_range(self, deg: bool = ...) -> Vec2Float: ... - def get_valid_image_ranges(self, i: str) -> List[Vec2Int]: ... - def set_valid_image_ranges(self, i: str, ranges: List[Vec2Int]) -> None: ... + def get_valid_image_ranges(self, i: str) -> list[Vec2Int]: ... + def set_valid_image_ranges(self, i: str, ranges: list[Vec2Int]) -> None: ... def get_properties(self) -> dict: ... def set_properties(self, properties: dict) -> None: ... def has_property(self, key: str) -> bool: ... @@ -852,8 +843,8 @@ class Scan(ScanBase): def is_image_index_valid(self, index: int) -> bool: ... def is_still(self) -> bool: ... def swap(self, other: Scan) -> None: ... - def to_dict(self) -> Dict: ... - def __getitem__(self, index: Union[int, slice]) -> Scan: ... + def to_dict(self) -> dict: ... + def __getitem__(self, index: int | slice) -> Scan: ... def __len__(self) -> int: ... def __add__(self, other: Scan) -> Scan: ... def __iadd__(self, other: Scan) -> Scan: ... @@ -868,7 +859,7 @@ class Spectrum: @overload def __init__(self, energies: flex.double, weights: flex.double) -> None: ... @staticmethod - def from_dict(data: Dict) -> Spectrum: ... + def from_dict(data: dict) -> Spectrum: ... def get_emax_eV(self) -> float: ... def get_emin_eV(self) -> float: ... def get_energies_eV(self) -> flex.double: ... @@ -876,7 +867,7 @@ class Spectrum: def get_weighted_energy_variance(self) -> float: ... def get_weighted_wavelength(self) -> float: ... def get_weights(self) -> flex.double: ... - def to_dict(self) -> Dict: ... + def to_dict(self) -> dict: ... class flex_Beam(FlexPlain[Beam]): pass diff --git a/src/dxtbx/format/Format.py b/src/dxtbx/format/Format.py index dea10c004..397e8cfa3 100644 --- a/src/dxtbx/format/Format.py +++ b/src/dxtbx/format/Format.py @@ -12,8 +12,9 @@ import bz2 import functools import os +from collections.abc import Callable from io import IOBase -from typing import Callable, ClassVar +from typing import ClassVar import libtbx diff --git a/src/dxtbx/format/FormatBrukerED1.py b/src/dxtbx/format/FormatBrukerED1.py index fc2a5e31a..bc7197b22 100644 --- a/src/dxtbx/format/FormatBrukerED1.py +++ b/src/dxtbx/format/FormatBrukerED1.py @@ -222,9 +222,7 @@ def get_raw_data(self): elif npixelb[0] == 2: read_data = read_2b else: - raise IncorrectFormatError( - "{} bytes per pixel is not supported".format(npixelb[0]) - ) + raise IncorrectFormatError(f"{npixelb[0]} bytes per pixel is not supported") nrows = int(self.header_dict["NROWS"].split()[0]) ncols = int(self.header_dict["NCOLS"].split()[0]) @@ -234,9 +232,9 @@ def get_raw_data(self): image_size = (nrows, ncols) raw_data.reshape(flex.grid(*image_size)) - (num_underflows, num_2b_overflows, num_4b_overflows) = [ + (num_underflows, num_2b_overflows, num_4b_overflows) = ( int(e) for e in self.header_dict["NOVERFL"].split() - ] + ) # read underflows if num_underflows > 0: diff --git a/src/dxtbx/format/FormatBrukerPhoton.py b/src/dxtbx/format/FormatBrukerPhoton.py index 1ae34b5e3..a0f8e4300 100644 --- a/src/dxtbx/format/FormatBrukerPhoton.py +++ b/src/dxtbx/format/FormatBrukerPhoton.py @@ -192,9 +192,7 @@ def get_raw_data(self): elif npixelb[0] == 2: read_data = read_2b else: - raise IncorrectFormatError( - "{} bytes per pixel is not supported".format(npixelb[0]) - ) + raise IncorrectFormatError(f"{npixelb[0]} bytes per pixel is not supported") nrows = int(self.header_dict["NROWS"].split()[0]) ncols = int(self.header_dict["NCOLS"].split()[0]) @@ -204,9 +202,9 @@ def get_raw_data(self): image_size = (nrows, ncols) raw_data.reshape(flex.grid(*image_size)) - (num_underflows, num_2b_overflows, num_4b_overflows) = [ + (num_underflows, num_2b_overflows, num_4b_overflows) = ( int(e) for e in self.header_dict["NOVERFL"].split() - ] + ) # read underflows if num_underflows > 0: diff --git a/src/dxtbx/format/FormatCBFMiniPilatusDLS12M.py b/src/dxtbx/format/FormatCBFMiniPilatusDLS12M.py index 21872dfd8..d1ec06052 100644 --- a/src/dxtbx/format/FormatCBFMiniPilatusDLS12M.py +++ b/src/dxtbx/format/FormatCBFMiniPilatusDLS12M.py @@ -65,7 +65,7 @@ def _detector(self): beam_xy = self._cif_header_dictionary["Beam_xy"] beam_xy = beam_xy.replace("(", "").replace(")", "").replace(",", "").split()[:2] - obs_beam_x, obs_beam_y = [float(f) for f in beam_xy] + obs_beam_x, obs_beam_y = (float(f) for f in beam_xy) ideal_beam_x = 1075 ideal_beam_y = 2594 diff --git a/src/dxtbx/format/FormatESSNMX.py b/src/dxtbx/format/FormatESSNMX.py index 3e6b5190a..8747cb1e6 100644 --- a/src/dxtbx/format/FormatESSNMX.py +++ b/src/dxtbx/format/FormatESSNMX.py @@ -1,7 +1,6 @@ from __future__ import annotations import logging -from typing import List, Tuple import h5py import numpy as np @@ -36,7 +35,7 @@ def __init__(self, image_file, **kwargs) -> None: def understand(image_file: str) -> bool: try: return FormatESSNMX.is_nmx_file(image_file) - except (IOError, KeyError): + except (OSError, KeyError): return False @staticmethod @@ -45,7 +44,7 @@ def get_name(image_file): try: with h5py.File(image_file, "r") as handle: return handle["NMX_data"].attrs["name"] - except (IOError, KeyError, AttributeError): + except (OSError, KeyError, AttributeError): return "" return get_name(image_file) == "NMX" @@ -72,7 +71,7 @@ def _load_raw_data(self) -> None: def get_raw_data( self, index: int, use_loaded_data: bool = False - ) -> Tuple[flex.int]: + ) -> tuple[flex.int]: raw_data = [] image_size = self._get_image_size() total_pixels = image_size[0] * image_size[1] @@ -96,11 +95,11 @@ def get_raw_data( return tuple(raw_data) - def _get_time_channel_bins(self) -> List[float]: + def _get_time_channel_bins(self) -> list[float]: # (usec) return self._nxs_file["NMX_data"]["detector_1"]["t_bin"][:] * 10**6 - def _get_time_of_flight(self) -> List[float]: + def _get_time_of_flight(self) -> list[float]: # (usec) bins = self._get_time_channel_bins() return [float((bins[i] + bins[i + 1]) * 0.5) for i in range(len(bins) - 1)] @@ -142,7 +141,7 @@ def get_detector(self, index: int = None) -> Detector: def _get_num_panels(self) -> int: return self._nxs_file["NMX_data/instrument"].attrs["nr_detector"] - def _get_panel_names(self) -> List[str]: + def _get_panel_names(self) -> list[str]: return [ "%02d" % (i + 1) for i in range(self._nxs_file["NMX_data/instrument"].attrs["nr_detector"]) @@ -151,29 +150,29 @@ def _get_panel_names(self) -> List[str]: def _get_panel_type(self) -> str: return "SENSOR_PAD" - def _get_image_size(self) -> Tuple[int, int]: + def _get_image_size(self) -> tuple[int, int]: # (px) return (1280, 1280) - def _get_panel_trusted_range(self) -> Tuple[int, int]: + def _get_panel_trusted_range(self) -> tuple[int, int]: # 4 * 1280**2 plus buffer return (-1, 7000000) - def _get_pixel_size(self) -> Tuple[float, float]: + def _get_pixel_size(self) -> tuple[float, float]: # (mm) return (0.4, 0.4) - def _get_panel_fast_axes(self) -> Tuple[Tuple[float, float, float]]: + def _get_panel_fast_axes(self) -> tuple[tuple[float, float, float]]: return ((1.0, 0.0, 0.0), (0.0, 0.0, 1.0), (0.0, 0.0, -1.0)) - def _get_panel_slow_axes(self) -> Tuple[Tuple[float, float, float]]: + def _get_panel_slow_axes(self) -> tuple[tuple[float, float, float]]: return ((0.0, 1.0, 0.0), (0.0, 1.0, 0.0), (0.0, 1.0, 0.0)) - def _get_panel_origins(self) -> Tuple[Tuple[float, float, float]]: + def _get_panel_origins(self) -> tuple[tuple[float, float, float]]: # (mm) return ((-250, -250.0, -292.0), (290, -250.0, -250), (-290, -250.0, 250.0)) - def _get_panel_projections_2d(self) -> dict[int : Tuple[Tuple, Tuple]]: + def _get_panel_projections_2d(self) -> dict[int : tuple[tuple, tuple]]: p_w, p_h = self._get_image_size() p_w += 10 p_h += 10 @@ -196,10 +195,10 @@ def get_beam(self, index: int = None) -> PolychromaticBeam: wavelength_range=wavelength_range, ) - def _get_sample_to_source_direction(self) -> Tuple[float, float, float]: + def _get_sample_to_source_direction(self) -> tuple[float, float, float]: return (0, 0, 1) - def _get_wavelength_range(self) -> Tuple[float, float]: + def _get_wavelength_range(self) -> tuple[float, float]: # (A) return (1.8, 2.55) @@ -230,7 +229,7 @@ def get_goniometer(self, index: int = None) -> Goniometer: goniometer.rotate_around_origin(axes[idx], -angle) return goniometer - def get_goniometer_orientations(self) -> Tuple[float, float, float]: + def get_goniometer_orientations(self) -> tuple[float, float, float]: # Angles in deg along x, y, z return self._nxs_file["NMX_data/crystal_orientation"][...] @@ -242,8 +241,8 @@ def get_scan(self, index=None) -> Scan: ) def get_flattened_data( - self, image_range: None | Tuple = None, scale_data: bool = True - ) -> Tuple[flex.int]: + self, image_range: None | tuple = None, scale_data: bool = True + ) -> tuple[flex.int]: """ Image data summed along the time-of-flight direction """ @@ -286,7 +285,7 @@ def get_flattened_data( def get_flattened_pixel_data( self, panel_idx: int, x: int, y: int - ) -> Tuple[Tuple, Tuple]: + ) -> tuple[tuple, tuple]: time_channels = self._get_time_of_flight() panel_size = self._get_image_size() height = panel_size[1] diff --git a/src/dxtbx/format/FormatHDF5SaclaMPCCD.py b/src/dxtbx/format/FormatHDF5SaclaMPCCD.py index 44d55f1d3..24f4c8556 100644 --- a/src/dxtbx/format/FormatHDF5SaclaMPCCD.py +++ b/src/dxtbx/format/FormatHDF5SaclaMPCCD.py @@ -120,9 +120,7 @@ def __init__(self, image_file, index=0, reconst_mode=False, **kwargs): self.panel_rotations[i] = tmp[i * 3 + 2] except Exception as e: raise OSError( - "Invalid MPCCD Geometry specified in environment variable MPCCD_GEOMETRY: {}".format( - e - ) + f"Invalid MPCCD Geometry specified in environment variable MPCCD_GEOMETRY: {e}" ) if "MPCCD_DISTANCE" in os.environ: self.distance = float(os.environ["MPCCD_DISTANCE"]) diff --git a/src/dxtbx/format/FormatISISSXD.py b/src/dxtbx/format/FormatISISSXD.py index e013e29d6..784d4dc80 100644 --- a/src/dxtbx/format/FormatISISSXD.py +++ b/src/dxtbx/format/FormatISISSXD.py @@ -1,7 +1,5 @@ from __future__ import annotations -from typing import List, Tuple - import h5py import numpy as np @@ -32,7 +30,7 @@ def __init__(self, image_file: str, **kwargs) -> None: def understand(image_file: str) -> bool: try: return FormatISISSXD.is_isissxd_file(image_file) - except (IOError, KeyError): + except (OSError, KeyError): return False @staticmethod @@ -112,30 +110,30 @@ def get_detector(self, index: int = None) -> Detector: return detector - def _get_pixel_size(self) -> Tuple[float, float]: + def _get_pixel_size(self) -> tuple[float, float]: # (mm) return (3.0, 3.0) - def _get_image_size(self) -> Tuple[int, int]: + def _get_image_size(self) -> tuple[int, int]: # (px) return (64, 64) def _get_num_panels(self) -> int: return 11 - def _get_panel_names(self) -> List[str]: + def _get_panel_names(self) -> list[str]: return ["%02d" % (i + 1) for i in range(11)] def _get_panel_gain(self): return 1.0 - def _get_panel_trusted_range(self) -> Tuple[int, int]: + def _get_panel_trusted_range(self) -> tuple[int, int]: return (-1, 100000) def _get_panel_type(self) -> str: return "SENSOR_PAD" - def _get_panel_origins(self) -> Tuple[Tuple[float, float, float]]: + def _get_panel_origins(self) -> tuple[tuple[float, float, float]]: # (mm) start_date = self.get_start_date() @@ -194,7 +192,7 @@ def _panel_0_flipped(self) -> bool: return True return False - def _get_panel_slow_axes(self) -> Tuple[Tuple[float, float, float]]: + def _get_panel_slow_axes(self) -> tuple[tuple[float, float, float]]: start_date = self.get_start_date() assert start_date is not None year, _, _ = start_date.split("-") @@ -243,7 +241,7 @@ def _get_panel_slow_axes(self) -> Tuple[Tuple[float, float, float]]: (-0.0, 0.0, -1.0), ) - def _get_panel_fast_axes(self) -> Tuple[Tuple[float, float, float]]: + def _get_panel_fast_axes(self) -> tuple[tuple[float, float, float]]: start_date = self.get_start_date() assert start_date is not None year, _, _ = start_date.split("-") @@ -331,10 +329,10 @@ def _get_sample_to_source_distance(self) -> float: # (mm) return 8300.0 - def _get_sample_to_source_direction(self) -> Tuple[float, float, float]: + def _get_sample_to_source_direction(self) -> tuple[float, float, float]: return (0, 0, -1) - def _get_wavelength_range(self) -> Tuple[float, float]: + def _get_wavelength_range(self) -> tuple[float, float]: # (A) return (0.2, 10.0) @@ -345,13 +343,13 @@ def get_scan(self, index=None) -> Scan: image_range=image_range, properties=properties ) - def _get_time_channel_bins(self) -> List[float]: + def _get_time_channel_bins(self) -> list[float]: # (usec) return self._nxs_file["raw_data_1"]["instrument"]["dae"]["time_channels_1"][ "time_of_flight" ][:] - def _get_time_of_flight(self) -> Tuple[float]: + def _get_time_of_flight(self) -> tuple[float]: # (usec) bins = self._get_time_channel_bins() return tuple( @@ -381,7 +379,7 @@ def _load_raw_data(self): raw_data.append(panel_data) self._raw_data = tuple(raw_data) - def get_raw_data(self, index: int, use_loaded_data=True) -> Tuple[flex.int]: + def get_raw_data(self, index: int, use_loaded_data=True) -> tuple[flex.int]: raw_data = [] if use_loaded_data: @@ -416,8 +414,8 @@ def get_raw_data(self, index: int, use_loaded_data=True) -> Tuple[flex.int]: return tuple(raw_data) def get_flattened_data( - self, image_range: None | Tuple = None, scale_data: bool = True - ) -> Tuple[flex.int]: + self, image_range: None | tuple = None, scale_data: bool = True + ) -> tuple[flex.int]: """ Image data summed along the time-of-flight direction """ @@ -466,7 +464,7 @@ def get_flattened_data( def get_flattened_pixel_data( self, panel_idx: int, x: int, y: int - ) -> Tuple[Tuple, Tuple]: + ) -> tuple[tuple, tuple]: time_channels = self._get_time_of_flight() panel_size = self._get_image_size() height = panel_size[1] diff --git a/src/dxtbx/format/FormatMANDI.py b/src/dxtbx/format/FormatMANDI.py index 3d7473046..8fd283b5f 100644 --- a/src/dxtbx/format/FormatMANDI.py +++ b/src/dxtbx/format/FormatMANDI.py @@ -3,7 +3,6 @@ from multiprocessing import Pool, cpu_count from os.path import join from sys import argv -from typing import List, Tuple import h5py import numpy as np @@ -45,7 +44,7 @@ def get_base_entry_name(self, nxs_file: h5py.File) -> str: def understand(image_file: str) -> bool: try: return FormatMANDI.is_mandi_file(image_file) - except IOError: + except OSError: return False @staticmethod @@ -64,7 +63,7 @@ def get_name(image_file: str) -> str: return get_name(image_file) == "MANDI" - def get_raw_data(self, index: int) -> Tuple[flex.int]: + def get_raw_data(self, index: int) -> tuple[flex.int]: raw_data = [] panel_size = self._get_image_size() for panel_name in self._get_panel_names(): @@ -109,11 +108,11 @@ def get_detector(self) -> Detector: return detector - def _get_time_channel_bins(self) -> List[float]: + def _get_time_channel_bins(self) -> list[float]: # (usec) return self.nxs_file[self._base_entry]["time_of_flight"][:] - def _get_time_of_flight(self) -> List[float]: + def _get_time_of_flight(self) -> list[float]: # (usec) bins = self._get_time_channel_bins() return tuple([float(bins[i] + bins[i + 1]) * 0.5 for i in range(len(bins) - 1)]) @@ -122,13 +121,13 @@ def _get_sample_to_source_distance(self) -> float: # (mm) return 30000 - def _get_sample_to_source_direction(self) -> Tuple[float, float, float]: + def _get_sample_to_source_direction(self) -> tuple[float, float, float]: return (0, 0, -1) def _get_num_panels(self) -> int: return 40 - def _get_panel_names(self) -> Tuple[str]: + def _get_panel_names(self) -> tuple[str]: return ( "bank1", "bank2", @@ -175,10 +174,10 @@ def _get_panel_names(self) -> Tuple[str]: def _get_panel_gain(self) -> float: return 1.0 - def _get_panel_trusted_range(self) -> Tuple[int, int]: + def _get_panel_trusted_range(self) -> tuple[int, int]: return (-1, 100000) - def _get_panel_origins(self) -> Tuple[Tuple[float, float, float], ...]: + def _get_panel_origins(self) -> tuple[tuple[float, float, float], ...]: return ( (71.59649688799595, -407.9875271017446, 91.63277006330976), (247.78726107849047, -370.86794223009696, 93.05022800601382), @@ -222,7 +221,7 @@ def _get_panel_origins(self) -> Tuple[Tuple[float, float, float], ...]: (-259.44611581654755, 152.81413474372576, 357.96944889204525), ) - def _get_panel_fast_axes(self) -> Tuple[Tuple[float, float, float], ...]: + def _get_panel_fast_axes(self) -> tuple[tuple[float, float, float], ...]: return ( (-0.9999583639962794, 0.004549995022478471, 0.007909982249012876), (-0.9270112280582247, -0.36646049406596276, 0.07973010311615258), @@ -266,7 +265,7 @@ def _get_panel_fast_axes(self) -> Tuple[Tuple[float, float, float], ...]: (-0.3374699569875644, 0.606049917647629, -0.720289889870817), ) - def _get_panel_slow_axes(self) -> Tuple[Tuple[float, float, float], ...]: + def _get_panel_slow_axes(self) -> tuple[tuple[float, float, float], ...]: return ( (0.009080058381285394, 0.4099593618136086, 0.9120585914299427), (-0.07844604621503816, 0.39736287118342395, 0.914302448010555), @@ -345,10 +344,10 @@ def get_goniometer(self, idx: int = None) -> Goniometer: goniometer.rotate_around_origin(rotation_axis_omega, omega) return goniometer - def _get_image_size(self) -> Tuple[int, int]: + def _get_image_size(self) -> tuple[int, int]: return (256, 256) - def _get_pixel_size(self) -> Tuple[float, float]: + def _get_pixel_size(self) -> tuple[float, float]: return (0.618, 0.618) def _get_panel_type(self) -> str: @@ -372,7 +371,7 @@ def add_histogram_data_to_nxs_file( write_tof_bins: bool = True, delta_tof: float = 5, # (usec) tof_padding: float = 100, # (usec) - panel_size: Tuple[int, int] = (256, 256), # (px) + panel_size: tuple[int, int] = (256, 256), # (px) nproc: int = 8, ) -> None: tof_bins = FormatMANDI.generate_tof_bins( @@ -394,7 +393,7 @@ def add_histogram_data_to_nxs_file( def write_histogram_data( nxs_file_path: str, tof_bins: np.array, - panel_size: Tuple[int, int], + panel_size: tuple[int, int], remove_event_data: bool, spectra_output_name: str = "spectra", write_tof_bins: bool = True, @@ -439,7 +438,7 @@ def delete_event_data(nxs_file, base_dir, panel_name): @staticmethod def compute_event_histogram( - args: Tuple[int, np.array, np.array, np.array], + args: tuple[int, np.array, np.array, np.array], ) -> np.array: pixel_idx, event_time_offset, corrected_event_id, tof_bins = args h, _ = np.histogram( @@ -451,7 +450,7 @@ def compute_event_histogram( def generate_histogram_data_for_panel( nxs_file: h5py.File, tof_bins: np.array, - panel_size: Tuple[int, int], + panel_size: tuple[int, int], panel_name: str, nproc=8, ) -> np.array: @@ -495,8 +494,8 @@ def generate_histogram_data_for_panel( @staticmethod def get_time_range_for_panel( - nxs_file: h5py.File, panel_size: Tuple[float, float], panel_name: str - ) -> Tuple[float, float]: + nxs_file: h5py.File, panel_size: tuple[float, float], panel_name: str + ) -> tuple[float, float]: """ Returns the range of event times for a given panel """ @@ -533,8 +532,8 @@ def event_data_is_valid(event_id, event_time_offset): @staticmethod def get_time_range_for_dataset( - nxs_file_path: str, panel_size: Tuple[int, int] - ) -> Tuple[float, float]: + nxs_file_path: str, panel_size: tuple[int, int] + ) -> tuple[float, float]: """ Iterates over num_panels to find the overall min/max tof event recorded """ @@ -571,7 +570,7 @@ def get_time_range_for_dataset( @staticmethod def generate_tof_bins( nxs_file: str, - panel_size: Tuple[float, float], + panel_size: tuple[float, float], delta_tof: float = 50, padding: float = 100, ) -> np.ndarray: @@ -590,7 +589,7 @@ def generate_tof_bins( return np.linspace(min_tof, max_tof, num_bins) @staticmethod - def get_panel_names(nxs_file: h5py.File) -> List[str]: + def get_panel_names(nxs_file: h5py.File) -> list[str]: raw_names = [i for i in nxs_file[list(nxs_file.keys())[0]] if "bank" in i] names = [] for name in raw_names: diff --git a/src/dxtbx/format/FormatROD.py b/src/dxtbx/format/FormatROD.py index fa031c0a1..4bf951fd0 100644 --- a/src/dxtbx/format/FormatROD.py +++ b/src/dxtbx/format/FormatROD.py @@ -364,7 +364,7 @@ def get_raw_data(self): if comp.startswith("TY6"): return self._get_raw_data_ty6_native() else: - raise NotImplementedError("Can't handle compression: {0}".format(comp)) + raise NotImplementedError(f"Can't handle compression: {comp}") def _get_raw_data_ty6_native(self): offset = self._txt_header["NHEADER"] diff --git a/src/dxtbx/format/FormatSER.py b/src/dxtbx/format/FormatSER.py index acf5ccc21..0276b889b 100644 --- a/src/dxtbx/format/FormatSER.py +++ b/src/dxtbx/format/FormatSER.py @@ -361,9 +361,7 @@ def _get_raw_data(self, index): elif d["DataType"] == 1: read_pixel = dxtbx.ext.read_uint8 else: - raise RuntimeError( - "Image {} data is of an unsupported type".format(index + 1) - ) + raise RuntimeError(f"Image {index + 1} data is of an unsupported type") d["ArraySizeX"] = struct.unpack(" wavelength_tolerance: text.append(f" Wavelength: {aw:f}, {bw:f}") if abs(ad.angle(bd)) > direction_tolerance: - text.append(" Direction: {}, {}".format(tuple(ad), tuple(bd))) + text.append(f" Direction: {tuple(ad)}, {tuple(bd)}") if abs(an.angle(bn)) > polarization_normal_tolerance: - text.append(" Polarization normal: {}, {}".format(tuple(an), tuple(bn))) + text.append(f" Polarization normal: {tuple(an)}, {tuple(bn)}") if abs(af - bf) > polarization_fraction_tolerance: text.append(f" Polarization fraction: {af}, {bf}") if len(text) > 0: @@ -139,7 +139,7 @@ def goniometer_diff( b_setting = goniometer2.get_setting_rotation() text = [] if abs(a_axis.angle(b_axis)) > rotation_axis_tolerance: - text.append(" Rotation axis: {}, {}".format(tuple(a_axis), tuple(b_axis))) + text.append(f" Rotation axis: {tuple(a_axis)}, {tuple(b_axis)}") if not _all_approx_equal(a_fixed, b_fixed, fixed_rotation_tolerance): text.append(f" Fixed rotation: {a_fixed}, {b_fixed}") if not _all_approx_equal(a_setting, b_setting, setting_rotation_tolerance): diff --git a/src/dxtbx/model/detector_helpers.py b/src/dxtbx/model/detector_helpers.py index d768b72ec..5347dc3eb 100644 --- a/src/dxtbx/model/detector_helpers.py +++ b/src/dxtbx/model/detector_helpers.py @@ -3,7 +3,7 @@ import itertools import math from operator import itemgetter -from typing import TYPE_CHECKING, Tuple, cast +from typing import TYPE_CHECKING, cast import numpy as np @@ -19,8 +19,8 @@ except ImportError: sklearn = None -Float2 = Tuple[float, float] -Float4 = Tuple[float, float, float, float] +Float2 = tuple[float, float] +Float4 = tuple[float, float, float, float] def read_xds_xparm(xds_xparm_file): diff --git a/src/dxtbx/model/experiment_list.py b/src/dxtbx/model/experiment_list.py index 4ab93b966..0619766bb 100644 --- a/src/dxtbx/model/experiment_list.py +++ b/src/dxtbx/model/experiment_list.py @@ -11,7 +11,8 @@ import os import pickle import sys -from typing import Any, Callable, Generator, Iterable +from collections.abc import Callable, Generator, Iterable +from typing import Any import natsort from tqdm import tqdm @@ -198,9 +199,7 @@ def __init__(self, obj, check_format=True, directory=None): # Basic check: This is a dict-like object. This can happen if e.g. we # were passed a DataBlock list instead of an ExperimentList dictionary if isinstance(obj, list) or not hasattr(obj, "get"): - raise InvalidExperimentListError( - "Expected dictionary, not {}".format(type(obj)) - ) + raise InvalidExperimentListError(f"Expected dictionary, not {type(obj)}") self._obj = copy.deepcopy(obj) self._check_format = check_format diff --git a/src/dxtbx/model/tof_helpers.py b/src/dxtbx/model/tof_helpers.py index 0941f6b92..243ce0099 100644 --- a/src/dxtbx/model/tof_helpers.py +++ b/src/dxtbx/model/tof_helpers.py @@ -1,7 +1,5 @@ from __future__ import annotations -from typing import List - from scipy.constants import Planck, m_n from scipy.interpolate import interp1d @@ -33,7 +31,7 @@ def tof_from_wavelength( return (wavelength * m_n * distance) / Planck -def frame_to_tof_interpolator(frames: List[float], tof: List[float]) -> interp1d: +def frame_to_tof_interpolator(frames: list[float], tof: list[float]) -> interp1d: """ ToF can vary nonlinearly with frame number. A cubic spline is used to better account for these cases. @@ -46,7 +44,7 @@ def frame_to_tof_interpolator(frames: List[float], tof: List[float]) -> interp1d return interp1d(frames, tof, kind="cubic") -def tof_to_frame_interpolator(tof: List[float], frames: List[float]) -> interp1d: +def tof_to_frame_interpolator(tof: list[float], frames: list[float]) -> interp1d: """ ToF can vary nonlinearly with frame number. A cubic spline is used to better account for these cases. diff --git a/src/dxtbx/nexus/__init__.py b/src/dxtbx/nexus/__init__.py index 2e3938e79..b7c60ca4d 100644 --- a/src/dxtbx/nexus/__init__.py +++ b/src/dxtbx/nexus/__init__.py @@ -565,7 +565,7 @@ def get_raw_data( nxdata: nxmx.NXdata, nxdetector: nxmx.NXdetector, index: int, - bit_depth: Optional[int] = None, + bit_depth: int | None = None, ) -> tuple[flex.float | flex.double | flex.int, ...]: """Return the raw data for an NXdetector. diff --git a/src/dxtbx/util/__init__.py b/src/dxtbx/util/__init__.py index d0d0cd799..538784f91 100644 --- a/src/dxtbx/util/__init__.py +++ b/src/dxtbx/util/__init__.py @@ -81,11 +81,7 @@ def show_mask_info(expt_list): print("---- ----") print(d) for j, _m in enumerate(m): - print( - "Module {} has {} masked pixels of {}".format( - j, _m.count(False), _m.size() - ) - ) + print(f"Module {j} has {_m.count(False)} masked pixels of {_m.size()}") def get_url_scheme(url) -> str: diff --git a/tests/format/test_uri.py b/tests/format/test_uri.py index 1406ee23b..683eb60eb 100644 --- a/tests/format/test_uri.py +++ b/tests/format/test_uri.py @@ -4,7 +4,6 @@ from __future__ import annotations -from typing import Type from unittest.mock import Mock import pytest @@ -22,7 +21,7 @@ def registry(monkeypatch): _temporary_formats = {} _original_get_format_class_for = Registry.get_format_class_for - def _get_format_class_for(format_class_name: str) -> Type[Format]: + def _get_format_class_for(format_class_name: str) -> type[Format]: """Intercept fetching format classes""" if format_class_name in _temporary_formats: return _temporary_formats[format_class_name] diff --git a/tests/model/test_experiment_list.py b/tests/model/test_experiment_list.py index 2a19e2ec5..fadec54ee 100644 --- a/tests/model/test_experiment_list.py +++ b/tests/model/test_experiment_list.py @@ -995,7 +995,7 @@ def _fake_open_file(cls, name): if name in ("a", "b", os.path.join("dir", "c"), os.path.join("dir", "d"), "e"): return mock.Mock() elif name.startswith("dir"): - err = IOError() + err = OSError() err.errno = errno.EISDIR # raise IOError(errno=errno.EISDIR) raise err diff --git a/tests/test_filecache_controller.py b/tests/test_filecache_controller.py index c2106ca00..60893bc1c 100644 --- a/tests/test_filecache_controller.py +++ b/tests/test_filecache_controller.py @@ -25,7 +25,7 @@ def test_invalid_cache(monkeypatch): mocklazy.return_value.open.assert_called() # Now, pass the cache an opener that fails - badfile = Mock(side_effect=IOError("Testing bad file")) + badfile = Mock(side_effect=OSError("Testing bad file")) with pytest.raises(IOError): cache.check("not_working", badfile)