From b51cc243b0fb1ff301e4a24361b007ed54294800 Mon Sep 17 00:00:00 2001 From: James Kerns Date: Wed, 22 Feb 2023 11:17:37 -0600 Subject: [PATCH] isort --- docs/source/code_snippets/tg51_class.py | 1 - docs/source/code_snippets/tg51_function.py | 1 - docs/source/code_snippets/trs398_class.py | 1 - docs/source/code_snippets/trs398_function.py | 1 - docs/source/conf.py | 1 - pylinac/__init__.py | 50 ++++----- pylinac/acr.py | 6 +- pylinac/calibration/trs398.py | 30 ++--- pylinac/core/geometry.py | 43 ++++---- pylinac/core/image.py | 18 ++- pylinac/core/image_generator/__init__.py | 14 +-- pylinac/core/image_generator/layers.py | 2 +- pylinac/core/image_generator/utils.py | 12 +- pylinac/core/io.py | 4 +- pylinac/core/mtf.py | 6 +- pylinac/core/pdf.py | 2 +- pylinac/core/profile.py | 110 +++++++++---------- pylinac/core/roi.py | 2 +- pylinac/core/utilities.py | 2 +- pylinac/ct.py | 22 ++-- pylinac/dlg.py | 7 +- pylinac/field_analysis.py | 12 +- pylinac/log_analyzer.py | 15 +-- pylinac/picketfence.py | 8 +- pylinac/planar_imaging.py | 14 +-- pylinac/quart.py | 10 +- pylinac/starshot.py | 15 +-- pylinac/vmat.py | 7 +- pylinac/winston_lutz.py | 98 ++++++++--------- tests_bank/_test_bank_cbcts.py | 8 +- tests_bank/_test_bank_logs.py | 2 +- tests_bank/_test_bank_picketfences.py | 4 +- tests_bank/_test_bank_planar_phantoms.py | 6 +- tests_bank/_test_bank_starshots.py | 2 +- tests_bank/_test_bank_winston_lutz.py | 2 +- tests_basic/core/test_generator.py | 11 +- tests_basic/core/test_image.py | 10 +- tests_basic/core/test_io.py | 6 +- tests_basic/core/test_pdf.py | 8 +- tests_basic/core/test_profile.py | 6 +- tests_basic/test_acr.py | 4 +- tests_basic/test_cbct.py | 8 +- tests_basic/test_field_analysis.py | 14 +-- tests_basic/test_logs.py | 20 ++-- tests_basic/test_picketfence.py | 10 +- tests_basic/test_planar_imaging.py | 22 ++-- tests_basic/test_quart.py | 8 +- tests_basic/test_starshot.py | 4 +- tests_basic/test_vmat.py | 8 +- tests_basic/test_winstonlutz.py | 12 +- tests_basic/utils.py | 14 +-- 51 files changed, 337 insertions(+), 366 deletions(-) diff --git a/docs/source/code_snippets/tg51_class.py b/docs/source/code_snippets/tg51_class.py index a38380fc..f9f0bedf 100644 --- a/docs/source/code_snippets/tg51_class.py +++ b/docs/source/code_snippets/tg51_class.py @@ -1,7 +1,6 @@ """A script to calculate TG-51 dose using pylinac classes and following the TG-51 photon form""" from pylinac.calibration import tg51 - ENERGY = 6 TEMP = 22.1 PRESS = tg51.mmHg2kPa(755.0) diff --git a/docs/source/code_snippets/tg51_function.py b/docs/source/code_snippets/tg51_function.py index 63fbe6f0..c69539de 100644 --- a/docs/source/code_snippets/tg51_function.py +++ b/docs/source/code_snippets/tg51_function.py @@ -1,7 +1,6 @@ """A script to calculate TG-51 dose using pylinac functions and following the TG-51 photon form""" from pylinac.calibration import tg51 - ENERGY = 6 TEMP = 22.1 PRESS = tg51.mmHg2kPa(755.0) diff --git a/docs/source/code_snippets/trs398_class.py b/docs/source/code_snippets/trs398_class.py index 5b891b9b..ba26c207 100644 --- a/docs/source/code_snippets/trs398_class.py +++ b/docs/source/code_snippets/trs398_class.py @@ -1,7 +1,6 @@ """A script to calculate TRS-398 dose using pylinac classes and following the TRS-398 photon form""" from pylinac.calibration import trs398 - ENERGY = 6 TEMP = 22.1 PRESS = trs398.mmHg2kPa(755.0) diff --git a/docs/source/code_snippets/trs398_function.py b/docs/source/code_snippets/trs398_function.py index af1d2e49..d8347963 100644 --- a/docs/source/code_snippets/trs398_function.py +++ b/docs/source/code_snippets/trs398_function.py @@ -1,7 +1,6 @@ """A script to calculate TRS-398 dose using pylinac functions and following the TRS-398 photon form""" from pylinac.calibration import trs398 - TEMP = 22.1 PRESS = trs398.mmHg2kPa(755.0) CHAMBER = "30013" # PTW diff --git a/docs/source/conf.py b/docs/source/conf.py index 691d61ec..9276260f 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- # # pylinac documentation build configuration file, created by # sphinx-quickstart on Thu Sep 10 11:56:25 2015. diff --git a/pylinac/__init__.py b/pylinac/__init__.py index 88c6e51e..7c047561 100644 --- a/pylinac/__init__.py +++ b/pylinac/__init__.py @@ -8,45 +8,45 @@ "Pylinac is only supported on Python 3.7+. Please update your environment." ) +# alphabetized modules +from .acr import ACRCT, ACRMRILarge +from .calibration import tg51, trs398 + # import shortcuts # core first from .core import decorators, geometry, image, io, mask, profile, roi, utilities - -# alphabetized modules -from .acr import ACRCT, ACRMRILarge -from .ct import CatPhan504, CatPhan600, CatPhan503, CatPhan604 -from .quart import QuartDVT -from .core.utilities import clear_data_files, assign2machine +from .core.utilities import assign2machine, clear_data_files +from .ct import CatPhan503, CatPhan504, CatPhan600, CatPhan604 from .field_analysis import ( - FieldAnalysis, - DeviceFieldAnalysis, - Protocol, + Centering, Device, + DeviceFieldAnalysis, Edge, + FieldAnalysis, Interpolation, Normalization, - Centering, + Protocol, ) +from .log_analyzer import Dynalog, MachineLogs, TrajectoryLog, load_log +from .picketfence import PicketFence # must be after log analyzer from .planar_imaging import ( - LeedsTOR, - StandardImagingQC3, - LasVegas, - DoselabMC2kV, - DoselabMC2MV, - StandardImagingQCkV, PTWEPIDQC, - SNCMV, - SNCkV, - StandardImagingFC2, - IMTLRad, SNCFSQA, - LeedsTORBlue, + SNCMV, SNCMV12510, + DoselabMC2kV, + DoselabMC2MV, IBAPrimusA, + IMTLRad, + LasVegas, + LeedsTOR, + LeedsTORBlue, + SNCkV, + StandardImagingFC2, + StandardImagingQC3, + StandardImagingQCkV, ) -from .log_analyzer import load_log, Dynalog, TrajectoryLog, MachineLogs -from .picketfence import PicketFence # must be after log analyzer +from .quart import QuartDVT from .starshot import Starshot -from .vmat import DRMLC, DRGS +from .vmat import DRGS, DRMLC from .winston_lutz import WinstonLutz, WinstonLutzMultiTargetMultiField -from .calibration import tg51, trs398 diff --git a/pylinac/acr.py b/pylinac/acr.py index 767d4047..10bb2ddc 100644 --- a/pylinac/acr.py +++ b/pylinac/acr.py @@ -6,7 +6,7 @@ from dataclasses import dataclass from io import BytesIO from pathlib import Path -from typing import Union, List, Dict, Optional, Tuple +from typing import Dict, List, Optional, Tuple, Union import numpy as np from matplotlib import pyplot as plt @@ -15,10 +15,10 @@ from .core import pdf from .core.geometry import Line, Point from .core.mtf import MTF -from .core.profile import SingleProfile, Interpolation +from .core.profile import Interpolation, SingleProfile from .core.roi import HighContrastDiskROI, RectangleROI from .core.utilities import ResultBase -from .ct import CatPhanBase, CatPhanModule, ThicknessROI, Slice, get_regions +from .ct import CatPhanBase, CatPhanModule, Slice, ThicknessROI, get_regions # CT CT_UNIFORMITY_MODULE_OFFSET_MM = 70 diff --git a/pylinac/calibration/trs398.py b/pylinac/calibration/trs398.py index 18c36c59..691773ce 100644 --- a/pylinac/calibration/trs398.py +++ b/pylinac/calibration/trs398.py @@ -1,29 +1,29 @@ import webbrowser from abc import ABC from datetime import datetime -from typing import Union, Optional +from typing import Optional, Union import argue import numpy as np +from ..core.pdf import PylinacCanvas +from ..core.typing import NumberOrArray +from ..core.utilities import Structure, is_close from . import tg51 as _tg51 +from .tg51 import MAX_PPOL # make available to module from .tg51 import ( - mmHg2kPa, - mbar2kPa, - fahrenheit2celsius, - tpr2010_from_pdd2010, - MIN_PTP, + MAX_PELEC, + MAX_PION, MAX_PTP, MIN_PELEC, - MAX_PELEC, - MIN_PPOL, - MAX_PPOL, MIN_PION, - MAX_PION, -) # make available to module -from ..core.pdf import PylinacCanvas -from ..core.typing import NumberOrArray -from ..core.utilities import is_close, Structure + MIN_PPOL, + MIN_PTP, + fahrenheit2celsius, + mbar2kPa, + mmHg2kPa, + tpr2010_from_pdd2010, +) V1_V2_FITS = { 2.0: {"a0": 2.337, "a1": -3.636, "a2": 2.299}, @@ -1137,7 +1137,7 @@ def publish_pdf( metadata is at the top of every page while notes is at the bottom of the report. """ was_adjusted = "Yes" if self.output_was_adjusted else "No" - title = "TRS-398 Electron Report - {} MV".format(self.energy) + title = f"TRS-398 Electron Report - {self.energy} MV" canvas = PylinacCanvas(filename, page_title=title, metadata=metadata) text = [ diff --git a/pylinac/core/geometry.py b/pylinac/core/geometry.py index bbc3a8c2..1cf8a8b2 100644 --- a/pylinac/core/geometry.py +++ b/pylinac/core/geometry.py @@ -3,12 +3,13 @@ import math from itertools import zip_longest -from typing import Union, Optional, List, Iterable, Tuple +from typing import Iterable, List, Optional, Tuple, Union import argue import matplotlib.pyplot as plt import numpy as np -from matplotlib.patches import Circle as mpl_Circle, Rectangle as mpl_Rectangle +from matplotlib.patches import Circle as mpl_Circle +from matplotlib.patches import Rectangle as mpl_Rectangle from .utilities import is_iterable @@ -39,16 +40,16 @@ class Point: z: float y: float x: float - _attr_list: List[str] = ["x", "y", "z", "idx", "value"] - _coord_list: List[str] = ["x", "y", "z"] + _attr_list: list[str] = ["x", "y", "z", "idx", "value"] + _coord_list: list[str] = ["x", "y", "z"] def __init__( self, - x: Union[float, tuple, Point] = 0, + x: float | tuple | Point = 0, y: float = 0, z: float = 0, - idx: Optional[int] = None, - value: Optional[float] = None, + idx: int | None = None, + value: float | None = None, as_int: bool = False, ): """ @@ -85,7 +86,7 @@ def __init__( self.y = int(round(self.y)) self.z = int(round(self.z)) - def distance_to(self, thing: Union["Point", "Circle"]) -> float: + def distance_to(self, thing: Point | Circle) -> float: """Calculate the distance to the given point. Parameters @@ -116,7 +117,7 @@ def as_array(self, only_coords: bool = True) -> np.array: ] ) - def as_vector(self) -> "Vector": + def as_vector(self) -> Vector: return Vector(x=self.x, y=self.y, z=self.z) def __repr__(self): @@ -160,9 +161,7 @@ class Circle: center: Point radius: float - def __init__( - self, center_point: Union[Point, Iterable] = (0, 0), radius: float = 0 - ): + def __init__(self, center_point: Point | Iterable = (0, 0), radius: float = 0): """ Parameters ---------- @@ -229,7 +228,7 @@ def as_scalar(self) -> float: """Return the scalar equivalent of the vector.""" return math.sqrt(self.x**2 + self.y**2 + self.z**2) - def distance_to(self, thing: Union[Circle, Point]) -> float: + def distance_to(self, thing: Circle | Point) -> float: """Calculate the distance to the given point. Parameters @@ -248,19 +247,19 @@ def distance_to(self, thing: Union[Circle, Point]) -> float: (self.x - p.x) ** 2 + (self.y - p.y) ** 2 + (self.z - p.z) ** 2 ) - def __sub__(self, other: "Vector") -> "Vector": + def __sub__(self, other: Vector) -> Vector: new_x = self.x - other.x new_y = self.y - other.y new_z = self.z - other.z return Vector(x=new_x, y=new_y, z=new_z) - def __add__(self, other: "Vector") -> "Vector": + def __add__(self, other: Vector) -> Vector: new_x = self.x + other.x new_y = self.y + other.y new_z = self.z + other.z return Vector(x=new_x, y=new_y, z=new_z) - def __truediv__(self, other: float) -> "Vector": + def __truediv__(self, other: float) -> Vector: for attr in ("x", "y", "z"): val = getattr(self, attr) setattr(self, attr, val / other) @@ -297,8 +296,8 @@ class Line: def __init__( self, - point1: Union[Point, Tuple[float, float]], - point2: Union[Point, Tuple[float, float]], + point1: Point | tuple[float, float], + point2: Point | tuple[float, float], ): """ Parameters @@ -355,7 +354,7 @@ def length(self) -> float: """Return length of the line, if finite.""" return self.point1.distance_to(self.point2) - def distance_to(self, point: "Point") -> float: + def distance_to(self, point: Point) -> float: """Calculate the minimum distance from the line to a point. Equations are from here: http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html #14 @@ -397,8 +396,8 @@ def plot2axes( class Rectangle: """A rectangle with width, height, center Point, top-left corner Point, and bottom-left corner Point.""" - width: Union[int, float] - height: Union[int, float] + width: int | float + height: int | float _as_int: bool center: Point @@ -406,7 +405,7 @@ def __init__( self, width: float, height: float, - center: Union[Point, Tuple], + center: Point | tuple, as_int: bool = False, ): """ diff --git a/pylinac/core/image.py b/pylinac/core/image.py index 6968e0f7..9fb9267a 100644 --- a/pylinac/core/image.py +++ b/pylinac/core/image.py @@ -9,9 +9,9 @@ import typing from collections import Counter from datetime import datetime -from io import BytesIO, BufferedReader +from io import BufferedReader, BytesIO from pathlib import Path -from typing import Union, Sequence, List, Any, Tuple, Optional, BinaryIO +from typing import Any, BinaryIO, List, Optional, Sequence, Tuple, Union import argue import matplotlib.pyplot as plt @@ -24,17 +24,17 @@ from scipy import ndimage from skimage.draw import disk +from ..settings import PATH_TRUNCATION_LENGTH, get_dicom_cmap from .geometry import Point from .io import ( - get_url, TemporaryZipDirectory, - retrieve_filenames, + get_url, is_dicom_image, retrieve_dicom_file, + retrieve_filenames, ) from .profile import stretch as stretcharray -from .utilities import is_close, decode_binary -from ..settings import get_dicom_cmap, PATH_TRUNCATION_LENGTH +from .utilities import decode_binary, is_close ARRAY = "Array" DICOM = "DICOM" @@ -129,7 +129,7 @@ def retrieve_image_files(path: str) -> List[str]: def load( path: Union[str, Path, ImageLike, np.ndarray, BinaryIO], **kwargs ) -> ImageLike: - """Load a DICOM image, JPG/TIF/BMP image, or numpy 2D array. + r"""Load a DICOM image, JPG/TIF/BMP image, or numpy 2D array. Parameters ---------- @@ -1169,9 +1169,7 @@ def _get_axis_value(self, axis_str: str, axis_dcm_attr: str) -> float: axis_found = True # if it is, then make sure it follows the naming convention of else: - match = re.search( - r"(?<={})\d+".format(axis_str.lower()), filename.lower() - ) + match = re.search(rf"(?<={axis_str.lower()})\d+", filename.lower()) if match is None: raise ValueError( f"The filename contains '{axis_str}' but could not read a number following it. Use the format '...{axis_str}<#>...'" diff --git a/pylinac/core/image_generator/__init__.py b/pylinac/core/image_generator/__init__.py index 6dccf864..8eb4a56d 100644 --- a/pylinac/core/image_generator/__init__.py +++ b/pylinac/core/image_generator/__init__.py @@ -1,19 +1,19 @@ from .layers import ( + ConstantLayer, + FilteredFieldLayer, + FilterFreeConeLayer, + FilterFreeFieldLayer, + GaussianFilterLayer, PerfectBBLayer, PerfectConeLayer, PerfectFieldLayer, - GaussianFilterLayer, - FilterFreeFieldLayer, - FilteredFieldLayer, - ConstantLayer, - FilterFreeConeLayer, RandomNoiseLayer, ) -from .simulators import AS1200Image, AS500Image, AS1000Image +from .simulators import AS500Image, AS1000Image, AS1200Image from .utils import ( generate_picketfence, generate_winstonlutz, generate_winstonlutz_cone, - generate_winstonlutz_multi_bb_single_field, generate_winstonlutz_multi_bb_multi_field, + generate_winstonlutz_multi_bb_single_field, ) diff --git a/pylinac/core/image_generator/layers.py b/pylinac/core/image_generator/layers.py index 7e16ba3d..1c91ba6f 100644 --- a/pylinac/core/image_generator/layers.py +++ b/pylinac/core/image_generator/layers.py @@ -1,4 +1,4 @@ -from abc import abstractmethod, ABC +from abc import ABC, abstractmethod from typing import Type import numpy as np diff --git a/pylinac/core/image_generator/utils.py b/pylinac/core/image_generator/utils.py index 0584b6a0..2bf74f30 100644 --- a/pylinac/core/image_generator/utils.py +++ b/pylinac/core/image_generator/utils.py @@ -2,22 +2,22 @@ import os import os.path as osp import random -from typing import Sequence, Union, List, Tuple, Type, Optional, Dict +from typing import Dict, List, Optional, Sequence, Tuple, Type, Union +from ...picketfence import Orientation +from ...winston_lutz import bb_projection_gantry_plane, bb_projection_long +from ..geometry import cos, sin from . import GaussianFilterLayer from .layers import ( FilteredFieldLayer, + FilterFreeConeLayer, FilterFreeFieldLayer, Layer, PerfectBBLayer, - PerfectFieldLayer, - FilterFreeConeLayer, PerfectConeLayer, + PerfectFieldLayer, ) from .simulators import Simulator -from ..geometry import cos, sin -from ...picketfence import Orientation -from ...winston_lutz import bb_projection_long, bb_projection_gantry_plane def generate_lightrad( diff --git a/pylinac/core/io.py b/pylinac/core/io.py index 581ba5a4..6e260b09 100644 --- a/pylinac/core/io.py +++ b/pylinac/core/io.py @@ -5,9 +5,9 @@ import zipfile from pathlib import Path from tempfile import TemporaryDirectory -from typing import Callable, List, Tuple, Union, BinaryIO, Optional +from typing import BinaryIO, Callable, List, Optional, Tuple, Union from urllib.error import HTTPError, URLError -from urllib.request import urlretrieve, urlopen +from urllib.request import urlopen, urlretrieve import numpy as np import pydicom diff --git a/pylinac/core/mtf.py b/pylinac/core/mtf.py index e64485d0..a8767844 100644 --- a/pylinac/core/mtf.py +++ b/pylinac/core/mtf.py @@ -1,7 +1,7 @@ from __future__ import annotations import warnings -from typing import Sequence, Optional, Tuple +from typing import Optional, Sequence, Tuple import argue import numpy as np @@ -84,7 +84,7 @@ def from_high_contrast_diskset( def plot( self, - axis: Optional[plt.Axes] = None, + axis: plt.Axes | None = None, grid: bool = True, x_label: str = "Line pairs / mm", y_label: str = "Relative MTF", @@ -92,7 +92,7 @@ def plot( margins: float = 0.05, marker: str = "o", label: str = "rMTF", - ) -> Tuple: + ) -> tuple: """Plot the Relative MTF. Parameters diff --git a/pylinac/core/pdf.py b/pylinac/core/pdf.py index 37e9cad2..66098094 100644 --- a/pylinac/core/pdf.py +++ b/pylinac/core/pdf.py @@ -2,7 +2,7 @@ import io from datetime import datetime from pathlib import Path -from typing import List, Union, Sequence, Optional +from typing import List, Optional, Sequence, Union from PIL import Image from reportlab.lib.pagesizes import A4 diff --git a/pylinac/core/profile.py b/pylinac/core/profile.py index a759b7b4..62bce334 100644 --- a/pylinac/core/profile.py +++ b/pylinac/core/profile.py @@ -4,7 +4,7 @@ import enum import math import warnings -from typing import Union, Tuple, Sequence, List, Optional +from typing import List, Optional, Sequence, Tuple, Union import argue import matplotlib.pyplot as plt @@ -16,7 +16,7 @@ from scipy.optimize import OptimizeWarning, minimize from scipy.stats import linregress -from .geometry import Point, Circle +from .geometry import Circle, Point from .hill import Hill from .utilities import convert_to_enum @@ -100,7 +100,7 @@ def gamma_1d( def stretch( - array: np.ndarray, min: int = 0, max: int = 1, fill_dtype: Optional[np.dtype] = None + array: np.ndarray, min: int = 0, max: int = 1, fill_dtype: np.dtype | None = None ) -> np.ndarray: """'Stretch' the profile to the fit a new min and max value and interpolate in between. From: http://www.labri.fr/perso/nrougier/teaching/numpy.100/ exercise #17 @@ -147,7 +147,7 @@ def invert(self) -> None: orig_array = self.values self.values = -orig_array + orig_array.max() + orig_array.min() - def normalize(self, norm_val: Union[str, float] = "max") -> None: + def normalize(self, norm_val: str | float = "max") -> None: """Normalize the profile to the given value. Parameters @@ -254,15 +254,15 @@ def __init__( self, values: np.ndarray, dpmm: float = None, - interpolation: Union[Interpolation, str, None] = Interpolation.LINEAR, + interpolation: Interpolation | str | None = Interpolation.LINEAR, ground: bool = True, interpolation_resolution_mm: float = 0.1, interpolation_factor: float = 10, - normalization_method: Union[Normalization, str] = Normalization.BEAM_CENTER, - edge_detection_method: Union[Edge, str] = Edge.FWHM, + normalization_method: Normalization | str = Normalization.BEAM_CENTER, + edge_detection_method: Edge | str = Edge.FWHM, edge_smoothing_ratio: float = 0.003, hill_window_ratio: float = 0.1, - x_values: Optional[np.ndarray] = None, + x_values: np.ndarray | None = None, ): """ Parameters @@ -335,9 +335,7 @@ def __init__( x_indices, norm_values, bounds_error=False, fill_value="extrapolate" ) - def _x_interp_to_original( - self, location: Union[float, np.ndarray] - ) -> Union[float, np.ndarray]: + def _x_interp_to_original(self, location: float | np.ndarray) -> float | np.ndarray: """Get the x-value of the (possibly) interpolated profile. The input value is in the original value range. E.g. a profile with x-range of 0-10 is interpolated to 10x. Asking for the location at 99 would scale back to 9.9. We need this function because peak finding is independent of the x-values. I.e. peaks are found and reported according @@ -347,9 +345,7 @@ def _x_interp_to_original( return float(x) return x - def _y_original_to_interp( - self, location: Union[float, np.ndarray] - ) -> Union[float, np.ndarray]: + def _y_original_to_interp(self, location: float | np.ndarray) -> float | np.ndarray: """Get the interpolated y-value of the profile. This is a corollary to the _x_interp... function""" y = self._y_interp1d(location) if isinstance(location, (float, int)) or location.size == 1: @@ -967,7 +963,7 @@ def field_calculation( in_field_ratio: float = 0.8, calculation: str = "mean", slope_exclusion_ratio: float = 0.2, - ) -> Union[float, Tuple[float, float]]: + ) -> float | tuple[float, float]: """Perform an operation on the field values of the profile. This function is useful for determining field symmetry and flatness. @@ -1080,11 +1076,11 @@ class MultiProfile(ProfileMixin): """ - values: Union[np.ndarray, Sequence] - peaks: List - valleys: List + values: np.ndarray | Sequence + peaks: list + valleys: list - def __init__(self, values: Union[np.ndarray, Sequence]): + def __init__(self, values: np.ndarray | Sequence): """ Parameters ---------- @@ -1095,7 +1091,7 @@ def __init__(self, values: Union[np.ndarray, Sequence]): self.peaks = [] self.valleys = [] - def plot(self, ax: Optional[plt.Axes] = None) -> None: + def plot(self, ax: plt.Axes | None = None) -> None: """Plot the profile. Parameters @@ -1115,12 +1111,12 @@ def plot(self, ax: Optional[plt.Axes] = None) -> None: def find_peaks( self, - threshold: Union[float, int] = 0.3, - min_distance: Union[float, int] = 0.05, + threshold: float | int = 0.3, + min_distance: float | int = 0.05, max_number: int = None, - search_region: Tuple = (0.0, 1.0), + search_region: tuple = (0.0, 1.0), peak_sort="prominences", - ) -> Tuple[np.ndarray, np.ndarray]: + ) -> tuple[np.ndarray, np.ndarray]: """Find the peaks of the profile using a simple maximum value search. This also sets the `peaks` attribute. Parameters @@ -1166,11 +1162,11 @@ def find_peaks( def find_valleys( self, - threshold: Union[float, int] = 0.3, - min_distance: Union[float, int] = 0.05, + threshold: float | int = 0.3, + min_distance: float | int = 0.05, max_number: int = None, - search_region: Tuple = (0.0, 1.0), - ) -> Tuple[np.ndarray, np.ndarray]: + search_region: tuple = (0.0, 1.0), + ) -> tuple[np.ndarray, np.ndarray]: """Find the valleys (minimums) of the profile using a simple minimum value search. Returns @@ -1200,13 +1196,13 @@ def find_valleys( def find_fwxm_peaks( self, - threshold: Union[float, int] = 0.3, - min_distance: Union[float, int] = 0.05, + threshold: float | int = 0.3, + min_distance: float | int = 0.05, max_number: int = None, - search_region: Tuple = (0.0, 1.0), + search_region: tuple = (0.0, 1.0), peak_sort: str = "prominences", required_prominence=None, - ) -> Tuple[np.ndarray, np.ndarray]: + ) -> tuple[np.ndarray, np.ndarray]: """Find peaks using the center of the FWXM (rather than by max value). Parameters @@ -1256,18 +1252,18 @@ class CircleProfile(MultiProfile, Circle): """ image_array: np.ndarray - start_angle: Union[float, int] + start_angle: float | int ccw: bool sampling_ratio: float - _x_locations: Optional[np.ndarray] - _y_locations: Optional[np.ndarray] + _x_locations: np.ndarray | None + _y_locations: np.ndarray | None def __init__( self, center: Point, radius: float, image_array: np.ndarray, - start_angle: Union[float, int] = 0, + start_angle: float | int = 0, ccw: bool = True, sampling_ratio: float = 1.0, ): @@ -1350,11 +1346,11 @@ def _profile(self) -> np.ndarray: def find_peaks( self, - threshold: Union[float, int] = 0.3, - min_distance: Union[float, int] = 0.05, + threshold: float | int = 0.3, + min_distance: float | int = 0.05, max_number: int = None, - search_region: Tuple[float, float] = (0.0, 1.0), - ) -> Tuple[np.ndarray, np.ndarray]: + search_region: tuple[float, float] = (0.0, 1.0), + ) -> tuple[np.ndarray, np.ndarray]: """Overloads Profile to also map peak locations to the image.""" peak_idxs, peak_vals = super().find_peaks( threshold, min_distance, max_number, search_region @@ -1364,11 +1360,11 @@ def find_peaks( def find_valleys( self, - threshold: Union[float, int] = 0.3, - min_distance: Union[float, int] = 0.05, + threshold: float | int = 0.3, + min_distance: float | int = 0.05, max_number: int = None, - search_region: Tuple[float, float] = (0.0, 1.0), - ) -> Tuple[np.ndarray, np.ndarray]: + search_region: tuple[float, float] = (0.0, 1.0), + ) -> tuple[np.ndarray, np.ndarray]: """Overload Profile to also map valley locations to the image.""" valley_idxs, valley_vals = super().find_valleys( threshold, min_distance, max_number, search_region @@ -1378,11 +1374,11 @@ def find_valleys( def find_fwxm_peaks( self, - threshold: Union[float, int] = 0.3, - min_distance: Union[float, int] = 0.05, + threshold: float | int = 0.3, + min_distance: float | int = 0.05, max_number: int = None, - search_region: Tuple[float, float] = (0.0, 1.0), - ) -> Tuple[np.ndarray, np.ndarray]: + search_region: tuple[float, float] = (0.0, 1.0), + ) -> tuple[np.ndarray, np.ndarray]: """Overloads Profile to also map the peak locations to the image.""" peak_idxs, peak_vals = super().find_fwxm_peaks( threshold, min_distance, max_number, search_region=search_region @@ -1463,7 +1459,7 @@ def __init__( self, center: Point, radius: float, - image_array: Union[np.ndarray, "ArrayImage"], + image_array: np.ndarray | ArrayImage, start_angle: int = 0, ccw: bool = True, sampling_ratio: float = 1.0, @@ -1500,7 +1496,7 @@ def size(self) -> float: return np.pi * max(self._radii) * 2 * self.sampling_ratio @property - def _multi_x_locations(self) -> List: + def _multi_x_locations(self) -> list: """List of x-locations of the sampling profiles""" x = [] cos = np.cos(self._radians) @@ -1510,7 +1506,7 @@ def _multi_x_locations(self) -> List: return x @property - def _multi_y_locations(self) -> List: + def _multi_y_locations(self) -> list: """List of x-locations of the sampling profiles""" y = [] sin = np.sin(self._radians) @@ -1571,15 +1567,15 @@ def plot2axes( def find_peaks( values: np.ndarray, - threshold: Union[float, int] = -np.inf, - peak_separation: Union[float, int] = 0, + threshold: float | int = -np.inf, + peak_separation: float | int = 0, max_number: int = None, fwxm_height: float = 0.5, min_width: int = 0, - search_region: Tuple[float, float] = (0.0, 1.0), + search_region: tuple[float, float] = (0.0, 1.0), peak_sort="prominences", required_prominence=None, -) -> Tuple[np.ndarray, dict]: +) -> tuple[np.ndarray, dict]: """Find the peaks of a 1D signal. Heavily relies on the scipy implementation. Parameters @@ -1644,10 +1640,10 @@ def find_peaks( def _parse_peak_args( peak_separation: float, - search_region: Tuple[float, float], + search_region: tuple[float, float], threshold: float, values: np.ndarray, -) -> Tuple[float, int, float, np.ndarray]: +) -> tuple[float, int, float, np.ndarray]: """Converts arguments as needed. E.g. converting a ratio to actual values""" # set threshold as % if between 0 and 1 val_range = values.max() - values.min() diff --git a/pylinac/core/roi.py b/pylinac/core/roi.py index ea7f76cc..3729c1d5 100644 --- a/pylinac/core/roi.py +++ b/pylinac/core/roi.py @@ -1,5 +1,5 @@ import enum -from typing import Union, Tuple, Optional +from typing import Optional, Tuple, Union import matplotlib.pyplot as plt import numpy as np diff --git a/pylinac/core/utilities.py b/pylinac/core/utilities.py index 07e219ca..fb83eb69 100644 --- a/pylinac/core/utilities.py +++ b/pylinac/core/utilities.py @@ -6,7 +6,7 @@ from dataclasses import dataclass, field from datetime import datetime from enum import Enum -from typing import Union, Sequence, Type, BinaryIO +from typing import BinaryIO, Sequence, Type, Union import numpy as np import pydicom diff --git a/pylinac/ct.py b/pylinac/ct.py index fd3de9c9..55cc4627 100644 --- a/pylinac/ct.py +++ b/pylinac/ct.py @@ -25,15 +25,15 @@ from os import path as osp from pathlib import Path from typing import ( - Optional, - Union, + BinaryIO, + Callable, Dict, - Tuple, - Sequence, List, - BinaryIO, + Optional, + Sequence, + Tuple, Type, - Callable, + Union, ) import matplotlib.pyplot as plt @@ -41,16 +41,16 @@ from cached_property import cached_property from py_linq import Enumerable from scipy import ndimage -from skimage import filters, measure, segmentation, draw +from skimage import draw, filters, measure, segmentation from skimage.measure._regionprops import RegionProperties from .core import image, pdf -from .core.geometry import Point, Line -from .core.image import DicomImageStack, ArrayImage +from .core.geometry import Line, Point +from .core.image import ArrayImage, DicomImageStack from .core.io import TemporaryZipDirectory, get_url, retrieve_demo_file from .core.mtf import MTF -from .core.profile import CollapsedCircleProfile, SingleProfile, Interpolation -from .core.roi import DiskROI, RectangleROI, LowContrastDiskROI, Contrast +from .core.profile import CollapsedCircleProfile, Interpolation, SingleProfile +from .core.roi import Contrast, DiskROI, LowContrastDiskROI, RectangleROI from .core.utilities import ResultBase, convert_to_enum from .settings import get_dicom_cmap diff --git a/pylinac/dlg.py b/pylinac/dlg.py index 0d7adfea..b06f6bf8 100644 --- a/pylinac/dlg.py +++ b/pylinac/dlg.py @@ -1,14 +1,13 @@ -from math import floor, ceil +from math import ceil, floor from typing import Sequence import numpy as np from matplotlib import pyplot as plt from scipy.stats import stats -from .core.profile import Normalization from .core import image -from .core.profile import SingleProfile, find_peaks -from .picketfence import MLCArrangement, MLC +from .core.profile import Normalization, SingleProfile, find_peaks +from .picketfence import MLC, MLCArrangement class DLG: diff --git a/pylinac/field_analysis.py b/pylinac/field_analysis.py index e08d01e2..46ddf5f1 100644 --- a/pylinac/field_analysis.py +++ b/pylinac/field_analysis.py @@ -6,19 +6,19 @@ import webbrowser from dataclasses import dataclass from enum import Enum -from math import floor, ceil +from math import ceil, floor from pathlib import Path -from typing import Union, Optional, Tuple, BinaryIO, List, Dict +from typing import BinaryIO, Dict, List, Optional, Tuple, Union import matplotlib.pyplot as plt import numpy as np from .core import image, pdf from .core.exceptions import NotAnalyzed -from .core.geometry import Rectangle, Point +from .core.geometry import Point, Rectangle from .core.hill import Hill -from .core.io import retrieve_demo_file, SNCProfiler -from .core.profile import SingleProfile, Edge, Interpolation, Normalization +from .core.io import SNCProfiler, retrieve_demo_file +from .core.profile import Edge, Interpolation, Normalization, SingleProfile from .core.roi import RectangleROI from .core.utilities import ResultBase, convert_to_enum from .settings import get_dicom_cmap @@ -39,7 +39,7 @@ def flatness_dose_difference( calculation="min", slope_exclusion_ratio=kwargs.get("slope_exclusion_ratio", 0.2), ) - except IOError: + except OSError: raise ValueError( "An error was encountered in the flatness calculation. The image is likely inverted. Try inverting the image before analysis with .image.invert()." ) diff --git a/pylinac/log_analyzer.py b/pylinac/log_analyzer.py index f77aa780..75683b28 100644 --- a/pylinac/log_analyzer.py +++ b/pylinac/log_analyzer.py @@ -32,9 +32,9 @@ import shutil import webbrowser import zipfile -from io import BytesIO, BufferedReader +from io import BufferedReader, BytesIO from pathlib import Path -from typing import Union, List, Optional, Tuple, Iterable, Sequence, BinaryIO +from typing import BinaryIO, Iterable, List, Optional, Sequence, Tuple, Union import argue import matplotlib.pyplot as plt @@ -43,12 +43,7 @@ from .core import image, io, pdf from .core.decorators import lru_cache -from .core.utilities import ( - is_iterable, - decode_binary, - Structure, - convert_to_enum, -) +from .core.utilities import Structure, convert_to_enum, decode_binary, is_iterable from .settings import get_array_cmap @@ -86,7 +81,7 @@ class MachineLogs(list): """Read in machine logs from a directory. Inherits from list. Batch methods are also provided.""" def __init__(self, folder: str, recursive: bool = True): - """ + r""" Parameters ---------- folder : str @@ -1552,7 +1547,7 @@ def __init__(self, filename: str, exclude_beam_off: bool = True): self.filename = filename self.exclude_beam_off = exclude_beam_off else: - raise IOError(f"{filename} was not a valid log file") + raise OSError(f"{filename} was not a valid log file") @classmethod def from_url(cls, url: str, exclude_beam_off: bool = True): diff --git a/pylinac/picketfence.py b/pylinac/picketfence.py index 39918ce5..7964c011 100644 --- a/pylinac/picketfence.py +++ b/pylinac/picketfence.py @@ -24,7 +24,7 @@ from itertools import cycle from pathlib import Path from tempfile import TemporaryDirectory -from typing import Union, Tuple, List, Optional, BinaryIO, Iterable, Sequence +from typing import BinaryIO, Iterable, List, Optional, Sequence, Tuple, Union import matplotlib.pyplot as plt import numpy as np @@ -33,9 +33,9 @@ from py_linq import Enumerable from .core import image, pdf -from .core.geometry import Line, Rectangle, Point +from .core.geometry import Line, Point, Rectangle from .core.io import get_url, retrieve_demo_file -from .core.profile import MultiProfile, SingleProfile, Interpolation +from .core.profile import Interpolation, MultiProfile, SingleProfile from .core.utilities import ResultBase, convert_to_enum from .log_analyzer import load_log from .settings import get_dicom_cmap @@ -826,7 +826,7 @@ def _add_leaf_error_subplot(self, ax: plt.Axes) -> None: # calculate the error and stdev values per MLC pair error_stdev = [] error_vals = [] - for leaf_num in set([m.leaf_num for m in self.mlc_meas]): + for leaf_num in {m.leaf_num for m in self.mlc_meas}: error_vals.append( np.mean( [np.abs(m.error) for m in self.mlc_meas if m.leaf_num == leaf_num] diff --git a/pylinac/planar_imaging.py b/pylinac/planar_imaging.py index f612ee1e..b716cdb9 100644 --- a/pylinac/planar_imaging.py +++ b/pylinac/planar_imaging.py @@ -27,7 +27,7 @@ import webbrowser from dataclasses import dataclass from pathlib import Path -from typing import Optional, List, Tuple, Union, BinaryIO, Callable, Dict +from typing import BinaryIO, Callable, Dict, List, Optional, Tuple, Union import matplotlib.pyplot as plt import numpy as np @@ -37,18 +37,18 @@ from skimage import feature, measure from skimage.measure._regionprops import RegionProperties -from .core import image, pdf, geometry +from .core import geometry, image, pdf from .core.decorators import lru_cache -from .core.geometry import Point, Rectangle, Circle, Vector +from .core.geometry import Circle, Point, Rectangle, Vector from .core.io import get_url, retrieve_demo_file from .core.mtf import MTF -from .core.profile import Interpolation, CollapsedCircleProfile, SingleProfile +from .core.profile import CollapsedCircleProfile, Interpolation, SingleProfile from .core.roi import ( - LowContrastDiskROI, - HighContrastDiskROI, - bbox_center, Contrast, DiskROI, + HighContrastDiskROI, + LowContrastDiskROI, + bbox_center, ) from .core.utilities import ResultBase from .ct import get_regions diff --git a/pylinac/quart.py b/pylinac/quart.py index e612e6d2..2aa7b40f 100644 --- a/pylinac/quart.py +++ b/pylinac/quart.py @@ -4,7 +4,7 @@ import webbrowser from io import BytesIO from pathlib import Path -from typing import Union, Dict, Optional, List, Tuple +from typing import Dict, List, Optional, Tuple, Union import numpy as np import scipy.ndimage @@ -12,15 +12,15 @@ from .core import pdf from .core.geometry import Line, Point -from .core.profile import SingleProfile, Interpolation +from .core.profile import Interpolation, SingleProfile from .core.utilities import ResultBase from .ct import ( - CTP404CP504, AIR, - ThicknessROI, + CTP404CP504, CTP486, - CatPhanModule, CatPhanBase, + CatPhanModule, + ThicknessROI, rois_to_results, ) diff --git a/pylinac/starshot.py b/pylinac/starshot.py index 70ec8a8b..8ddf0c00 100644 --- a/pylinac/starshot.py +++ b/pylinac/starshot.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ The Starshot module analyses a starshot image made of radiation spokes, whether gantry, collimator, MLC or couch. It is based on ideas from `Depuydt et al `_ @@ -25,7 +24,7 @@ import webbrowser from dataclasses import dataclass from pathlib import Path -from typing import Union, List, Optional, Tuple, BinaryIO +from typing import BinaryIO, List, Optional, Tuple, Union import argue import matplotlib.pyplot as plt @@ -33,9 +32,9 @@ from scipy import optimize from .core import image, pdf -from .core.geometry import Point, Line, Circle -from .core.io import get_url, TemporaryZipDirectory, retrieve_demo_file -from .core.profile import SingleProfile, CollapsedCircleProfile, Interpolation +from .core.geometry import Circle, Line, Point +from .core.io import TemporaryZipDirectory, get_url, retrieve_demo_file +from .core.profile import CollapsedCircleProfile, Interpolation, SingleProfile from .core.utilities import ResultBase from .settings import get_dicom_cmap @@ -683,10 +682,8 @@ def get_peaks(self, min_peak_height, min_peak_distance=0.02, fwhm=True): def get_peak_height(): - for height in np.linspace(0.05, 0.95, 10): - yield height + yield from np.linspace(0.05, 0.95, 10) def get_radius(): - for radius in np.linspace(0.95, 0.1, 10): - yield radius + yield from np.linspace(0.95, 0.1, 10) diff --git a/pylinac/vmat.py b/pylinac/vmat.py index 215fe1af..5b496385 100644 --- a/pylinac/vmat.py +++ b/pylinac/vmat.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """The VMAT module consists of the class VMAT, which is capable of loading an EPID DICOM Open field image and MLC field image and analyzing the images according to the Varian RapidArc QA tests and procedures, specifically the Dose-Rate & Gantry-Speed (DRGS) and Dose-Rate & MLC speed (DRMLC) tests. @@ -16,7 +15,7 @@ from dataclasses import dataclass from io import BytesIO from pathlib import Path -from typing import Union, List, Tuple, Sequence, Optional, BinaryIO +from typing import BinaryIO, List, Optional, Sequence, Tuple, Union import argue import matplotlib.pyplot as plt @@ -25,9 +24,9 @@ from .core import image from .core.geometry import Point, Rectangle from .core.image import ImageLike -from .core.io import get_url, TemporaryZipDirectory, retrieve_demo_file +from .core.io import TemporaryZipDirectory, get_url, retrieve_demo_file from .core.pdf import PylinacCanvas -from .core.profile import SingleProfile, Interpolation, Edge +from .core.profile import Edge, Interpolation, SingleProfile from .core.utilities import ResultBase from .settings import get_dicom_cmap diff --git a/pylinac/winston_lutz.py b/pylinac/winston_lutz.py index bfa15b70..a814fd2b 100644 --- a/pylinac/winston_lutz.py +++ b/pylinac/winston_lutz.py @@ -31,24 +31,24 @@ from itertools import zip_longest from pathlib import Path from textwrap import wrap -from typing import Union, List, Tuple, Optional, BinaryIO, Iterable, Dict +from typing import BinaryIO, Dict, Iterable, List, Optional, Tuple, Union import argue import matplotlib.pyplot as plt import numpy as np -from scipy import ndimage, optimize, linalg +from scipy import linalg, ndimage, optimize from skimage import measure from skimage.measure._regionprops import RegionProperties from tabulate import tabulate from .core import image, pdf from .core.decorators import lru_cache -from .core.geometry import Point, Line, Vector, cos, sin +from .core.geometry import Line, Point, Vector, cos, sin from .core.image import LinacDicomImage -from .core.io import TemporaryZipDirectory, get_url, retrieve_demo_file, is_dicom_image +from .core.io import TemporaryZipDirectory, get_url, is_dicom_image, retrieve_demo_file from .core.mask import bounding_box from .core.scale import MachineScale, convert -from .core.utilities import is_close, ResultBase, convert_to_enum +from .core.utilities import ResultBase, convert_to_enum, is_close class BBArrangement: @@ -181,7 +181,7 @@ class WinstonLutzResult(ResultBase): max_coll_rms_deviation_mm: float #: couch_2d_iso_diameter_mm: float #: max_couch_rms_deviation_mm: float #: - image_details: List[WinstonLutz2DResult] #: + image_details: list[WinstonLutz2DResult] #: @dataclass @@ -274,7 +274,7 @@ class WinstonLutz2D(image.LinacDicomImage): bb: Point field_cax: Point _rad_field_bounding_box: list - detection_conditions: List[callable] = [ + detection_conditions: list[callable] = [ is_round, is_symmetric, is_near_center, @@ -282,7 +282,7 @@ class WinstonLutz2D(image.LinacDicomImage): ] def __init__( - self, file: Union[str, BinaryIO, Path], use_filenames: bool = False, **kwargs + self, file: str | BinaryIO | Path, use_filenames: bool = False, **kwargs ): """ Parameters @@ -340,7 +340,7 @@ def has_noise(self, window_size): self.crop(window_size) safety_stop -= 1 - def _find_field_centroid(self) -> Tuple[Point, List]: + def _find_field_centroid(self) -> tuple[Point, list]: """Find the centroid of the radiation field based on a 50% height threshold. Returns @@ -483,7 +483,7 @@ def cax2epid_distance(self) -> float: return self.field_cax.distance_to(self.epid) / self.dpmm def plot( - self, ax: Optional[plt.Axes] = None, show: bool = True, clear_fig: bool = False + self, ax: plt.Axes | None = None, show: bool = True, clear_fig: bool = False ): """Plot the image, zoomed-in on the radiation field, along with the detected BB location and field CAX location. @@ -549,7 +549,7 @@ def variable_axis(self) -> Axis: else: return Axis.GBP_COMBO - def results_data(self, as_dict=False) -> Union[WinstonLutz2DResult, dict]: + def results_data(self, as_dict=False) -> WinstonLutz2DResult | dict: """Present the results data and metadata as a dataclass or dict. The default return type is a dataclass.""" if not self._is_analyzed: @@ -578,9 +578,9 @@ class WinstonLutz: def __init__( self, - directory: Union[str, List[str], Path], + directory: str | list[str] | Path, use_filenames: bool = False, - axis_mapping: Optional[Dict[str, Tuple[int, int, int]]] = None, + axis_mapping: dict[str, tuple[int, int, int]] | None = None, ): """ Parameters @@ -638,9 +638,9 @@ def from_demo_images(cls): @classmethod def from_zip( cls, - zfile: Union[str, BinaryIO], + zfile: str | BinaryIO, use_filenames: bool = False, - axis_mapping: Optional[Dict[str, Tuple[int, int, int]]] = None, + axis_mapping: dict[str, tuple[int, int, int]] | None = None, ): """Instantiate from a zip file rather than a directory. @@ -700,7 +700,7 @@ def analyze( self._is_analyzed = True @lru_cache() - def _minimize_axis(self, axes: Union[Axis, Tuple[Axis, ...]] = (Axis.GANTRY,)): + def _minimize_axis(self, axes: Axis | tuple[Axis, ...] = (Axis.GANTRY,)): """Return the minimization result of the given axis.""" if isinstance(axes, Axis): axes = (axes,) @@ -817,9 +817,9 @@ def bb_shift_vector(self) -> Vector: def bb_shift_instructions( self, - couch_vrt: Optional[float] = None, - couch_lng: Optional[float] = None, - couch_lat: Optional[float] = None, + couch_vrt: float | None = None, + couch_lng: float | None = None, + couch_lat: float | None = None, ) -> str: """Returns a string describing how to shift the BB to the radiation isocenter looking from the foot of the couch. Optionally, the current couch values can be passed in to get the new couch values. If passing the current @@ -849,7 +849,7 @@ def bb_shift_instructions( @argue.options(value=("all", "range")) def axis_rms_deviation( self, axis: Axis = Axis.GANTRY, value: str = "all" - ) -> Union[Iterable, float]: + ) -> Iterable | float: """The RMS deviations of a given axis/axes. Parameters @@ -907,7 +907,7 @@ def cax2epid_distance(self, metric: str = "max") -> float: return float(np.mean([image.cax2epid_distance for image in self.images])) def _plot_deviation( - self, axis: Axis, ax: Optional[plt.Axes] = None, show: bool = True + self, axis: Axis, ax: plt.Axes | None = None, show: bool = True ): """Helper function: Plot the sag in Cartesian coordinates. @@ -932,9 +932,7 @@ def _plot_deviation( for image in self.images if image.variable_axis in (axis, Axis.REFERENCE) ] - angles = [ - getattr(image, "{}_angle".format(axis.value.lower())) for image in imgs - ] + angles = [getattr(image, f"{axis.value.lower()}_angle") for image in imgs] xz_sag = np.array([getattr(img, attr).x for img in imgs]) y_sag = np.array([getattr(img, attr).y for img in imgs]) rms = np.sqrt(xz_sag**2 + y_sag**2) @@ -956,15 +954,15 @@ def _plot_deviation( plt.show() def _get_images( - self, axis: Union[Axis, Tuple[Axis, ...]] = (Axis.GANTRY,) - ) -> Tuple[float, list]: + self, axis: Axis | tuple[Axis, ...] = (Axis.GANTRY,) + ) -> tuple[float, list]: if isinstance(axis, Axis): axis = (axis,) images = [image for image in self.images if image.variable_axis in axis] return len(images), images def plot_axis_images( - self, axis: Axis = Axis.GANTRY, show: bool = True, ax: Optional[plt.Axes] = None + self, axis: Axis = Axis.GANTRY, show: bool = True, ax: plt.Axes | None = None ): """Plot all CAX/BB/EPID positions for the images of a given axis. @@ -1016,7 +1014,7 @@ def plot_axis_images( def plot_images( self, axis: Axis = Axis.GANTRY, show: bool = True, split: bool = False, **kwargs - ) -> (List[plt.Figure], List[str]): + ) -> (list[plt.Figure], list[str]): """Plot a grid of all the images acquired. Four columns are plotted with the titles showing which axis that column represents. @@ -1099,9 +1097,7 @@ def plot_images( return figs, names - def save_images( - self, filename: Union[str, BinaryIO], axis: Axis = Axis.GANTRY, **kwargs - ): + def save_images(self, filename: str | BinaryIO, axis: Axis = Axis.GANTRY, **kwargs): """Save the figure of `plot_images()` to file. Keyword arguments are passed to `matplotlib.pyplot.savefig()`. Parameters @@ -1114,7 +1110,7 @@ def save_images( self.plot_images(axis=axis, show=False) plt.savefig(filename, **kwargs) - def save_images_to_stream(self, **kwargs) -> Dict[str, io.BytesIO]: + def save_images_to_stream(self, **kwargs) -> dict[str, io.BytesIO]: """Save the individual image plots to stream""" figs, names = self.plot_images( axis=Axis.GBP_COMBO, show=False, split=True @@ -1124,7 +1120,7 @@ def save_images_to_stream(self, **kwargs) -> Dict[str, io.BytesIO]: fig.savefig(stream, **kwargs) return {name: stream for name, stream in zip(names, streams)} - def plot_summary(self, show: bool = True, fig_size: Optional[tuple] = None): + def plot_summary(self, show: bool = True, fig_size: tuple | None = None): """Plot a summary figure showing the gantry sag and wobble plots of the three axes.""" if not self._is_analyzed: raise ValueError("The set is not analyzed. Use .analyze() first.") @@ -1150,7 +1146,7 @@ def plot_summary(self, show: bool = True, fig_size: Optional[tuple] = None): plt.tight_layout() plt.show() - def save_summary(self, filename: Union[str, BinaryIO], **kwargs): + def save_summary(self, filename: str | BinaryIO, **kwargs): """Save the summary image.""" self.plot_summary(show=False, fig_size=kwargs.pop("fig_size", None)) plt.tight_layout() @@ -1193,7 +1189,7 @@ def results(self, as_list: bool = False) -> str: result = "\n".join(result) return result - def results_data(self, as_dict=False) -> Union[WinstonLutzResult, dict]: + def results_data(self, as_dict=False) -> WinstonLutzResult | dict: """Present the results data and metadata as a dataclass or dict. The default return type is a dataclass.""" if not self._is_analyzed: @@ -1247,10 +1243,10 @@ def results_data(self, as_dict=False) -> Union[WinstonLutzResult, dict]: def publish_pdf( self, filename: str, - notes: Optional[Union[str, List[str]]] = None, + notes: str | list[str] | None = None, open_file: bool = False, - metadata: Optional[dict] = None, - logo: Optional[Union[Path, str]] = None, + metadata: dict | None = None, + logo: Path | str | None = None, ): """Publish (print) a PDF containing the analysis, images, and quantitative results. @@ -1342,7 +1338,7 @@ def as_analyzed(self, bb_location: dict) -> WinstonLutz2DMultiTarget: return copy.deepcopy(self) def plot( - self, ax: Optional[plt.Axes] = None, show: bool = True, clear_fig: bool = False + self, ax: plt.Axes | None = None, show: bool = True, clear_fig: bool = False ): ax = super(LinacDicomImage, self).plot(ax=ax, show=False, clear_fig=clear_fig) ax.plot(self.field_cax.x, self.field_cax.y, "gs", ms=8) @@ -1380,7 +1376,7 @@ def _nominal_point(self, bb: dict) -> Point: expected_x = self.epid.x + shift_x_mm * self.dpmm return Point(x=expected_x, y=expected_y) - def _find_field_centroid(self, location: dict) -> Tuple[Point, List]: + def _find_field_centroid(self, location: dict) -> tuple[Point, list]: """Find the centroid of the radiation field based on a 50% height threshold. This applies the field detection conditions and also a nearness condition. @@ -1503,15 +1499,15 @@ def location_near_nominal(self, region: RegionProperties, location: dict) -> boo near_x = math.isclose(expected.x, region.centroid[1], abs_tol=5 * self.dpmm) return near_y and near_x - def results_data(self, as_dict: bool = False) -> Union[WinstonLutz2DResult, dict]: + def results_data(self, as_dict: bool = False) -> WinstonLutz2DResult | dict: raise NotImplementedError( "Results data is not available for a multi-bb 2D WL image" ) class WinstonLutzMultiTargetMultiField(WinstonLutz): - images: List[WinstonLutz2DMultiTarget] #: - analyzed_images: Dict[str, List[WinstonLutz2DMultiTarget]] #: + images: list[WinstonLutz2DMultiTarget] #: + analyzed_images: dict[str, list[WinstonLutz2DMultiTarget]] #: image_type = WinstonLutz2DMultiTarget bb_arrangement: Iterable[dict] #: @@ -1583,7 +1579,7 @@ def analyze(self, bb_arrangement: Iterable[dict]): self.analyzed_images[BBArrangement.to_human(bb)] = image_set self._is_analyzed = True - def plot_images(self, show: bool = True, **kwargs) -> (List[plt.Figure], List[str]): + def plot_images(self, show: bool = True, **kwargs) -> (list[plt.Figure], list[str]): """Make a plot for each BB. Each plot contains the analysis of that BB on each image it was found.""" figs, names = [], [] @@ -1615,7 +1611,7 @@ def save_images(self, prefix: str = "", **kwargs): for fig, name in zip(figs, names): fig.savefig(prefix + "_" + str(name) + ".png", **kwargs) - def save_images_to_stream(self, **kwargs) -> Dict[str, io.BytesIO]: + def save_images_to_stream(self, **kwargs) -> dict[str, io.BytesIO]: """Save the individual image plots to stream""" figs, names = self.plot_images(show=False, **kwargs) streams = [io.BytesIO() for _ in figs] @@ -1646,7 +1642,7 @@ def cax2bb_distance(self, bb: str, metric: str = "max") -> float: def results_data( self, as_dict: bool = False - ) -> Union[WinstonLutzMultiTargetMultiFieldResult, dict]: + ) -> WinstonLutzMultiTargetMultiFieldResult | dict: """Present the results data and metadata as a dataclass or dict. The default return type is a dataclass.""" if not self._is_analyzed: @@ -1666,11 +1662,11 @@ def results_data( return dataclasses.asdict(data) return data - def plot_summary(self, show: bool = True, fig_size: Optional[tuple] = None): + def plot_summary(self, show: bool = True, fig_size: tuple | None = None): raise NotImplementedError("Not yet implemented") def plot_axis_images( - self, axis: Axis = Axis.GANTRY, show: bool = True, ax: Optional[plt.Axes] = None + self, axis: Axis = Axis.GANTRY, show: bool = True, ax: plt.Axes | None = None ): raise NotImplementedError("Not yet implemented") @@ -1762,10 +1758,10 @@ def results(self, as_list: bool = False) -> str: def publish_pdf( self, filename: str, - notes: Optional[Union[str, List[str]]] = None, + notes: str | list[str] | None = None, open_file: bool = False, - metadata: Optional[dict] = None, - logo: Optional[Union[Path, str]] = None, + metadata: dict | None = None, + logo: Path | str | None = None, ): """Publish (print) a PDF containing the analysis, images, and quantitative results. diff --git a/tests_bank/_test_bank_cbcts.py b/tests_bank/_test_bank_cbcts.py index 468457b2..69a02e48 100644 --- a/tests_bank/_test_bank_cbcts.py +++ b/tests_bank/_test_bank_cbcts.py @@ -3,7 +3,7 @@ from unittest import TestCase from zipfile import BadZipfile -from pylinac import CatPhan600, CatPhan503, CatPhan504 +from pylinac import CatPhan503, CatPhan504, CatPhan600 from tests_basic.utils import DataBankMixin @@ -14,7 +14,7 @@ def run_catphan504(path): mypf.analyze() return "Success" except (ValueError, FileNotFoundError, BadZipfile) as e: - return "Failure: {} @ {}".format(e, path) + return f"Failure: {e} @ {path}" def run_catphan503(path): @@ -23,7 +23,7 @@ def run_catphan503(path): mypf.analyze() return "Success" except (ValueError, FileNotFoundError, BadZipfile) as e: - return "Failure: {} @ {}".format(e, path) + return f"Failure: {e} @ {path}" def run_catphan600(path): @@ -32,7 +32,7 @@ def run_catphan600(path): mypf.analyze() return "Success" except (ValueError, FileNotFoundError, BadZipfile) as e: - return "Failure: {} @ {}".format(e, path) + return f"Failure: {e} @ {path}" class CBCTTestBank(DataBankMixin, TestCase): diff --git a/tests_bank/_test_bank_logs.py b/tests_bank/_test_bank_logs.py index 31a51eec..1963fcd9 100644 --- a/tests_bank/_test_bank_logs.py +++ b/tests_bank/_test_bank_logs.py @@ -16,7 +16,7 @@ def run_log(path): raise Exception("Gamma pass % < 90") ret = "Success" except Exception as e: - ret = "Failure: {} @ {}".format(e, path) + ret = f"Failure: {e} @ {path}" return ret diff --git a/tests_bank/_test_bank_picketfences.py b/tests_bank/_test_bank_picketfences.py index a7f28224..fa06d437 100644 --- a/tests_bank/_test_bank_picketfences.py +++ b/tests_bank/_test_bank_picketfences.py @@ -21,9 +21,9 @@ def run_pf(path): raise Exception("Max MLC peak error > 1.2mm") return "Success" except (ValueError,) as e: - return "Failure: {} @ {}".format(e, path) + return f"Failure: {e} @ {path}" except Exception as e: - return "Failure: {} @ {}".format(e, path) + return f"Failure: {e} @ {path}" class PicketFenceTestBank(DataBankMixin, TestCase): diff --git a/tests_bank/_test_bank_planar_phantoms.py b/tests_bank/_test_bank_planar_phantoms.py index 3649c476..80ac3ed6 100644 --- a/tests_bank/_test_bank_planar_phantoms.py +++ b/tests_bank/_test_bank_planar_phantoms.py @@ -4,8 +4,8 @@ # from tests_basic import prep_mpl_testing import matplotlib.pyplot as plt -from pylinac import LeedsTOR, StandardImagingQC3, LasVegas -from pylinac.planar_imaging import PTWEPIDQC, SNCkV, SNCMV, StandardImagingQCkV +from pylinac import LasVegas, LeedsTOR, StandardImagingQC3 +from pylinac.planar_imaging import PTWEPIDQC, SNCMV, SNCkV, StandardImagingQCkV from tests_basic.utils import DataBankMixin @@ -15,7 +15,7 @@ def process_phantom(phantom, path): phantom.plot_analyzed_image(show=False) plt.close("all") except Exception as e: - return "Failure: {} @ {}".format(e, path) + return f"Failure: {e} @ {path}" else: return "Success" diff --git a/tests_bank/_test_bank_starshots.py b/tests_bank/_test_bank_starshots.py index 3f33ac33..77c9a41d 100644 --- a/tests_bank/_test_bank_starshots.py +++ b/tests_bank/_test_bank_starshots.py @@ -14,7 +14,7 @@ def run_star(path): raise Exception("Diamater was > 3mm.") return "Success" except Exception as e: - return "Failure: {} @ {}".format(e, path) + return f"Failure: {e} @ {path}" class StarshotBank(DataBankMixin, TestCase): diff --git a/tests_bank/_test_bank_winston_lutz.py b/tests_bank/_test_bank_winston_lutz.py index b1fad3a1..83f0f3c5 100644 --- a/tests_bank/_test_bank_winston_lutz.py +++ b/tests_bank/_test_bank_winston_lutz.py @@ -13,7 +13,7 @@ def run_wl(path): raise ValueError return "Success" except Exception as e: - return "Failure: {} @ {}".format(e, path) + return f"Failure: {e} @ {path}" class WinstonLutzTestBank(DataBankMixin, TestCase): diff --git a/tests_basic/core/test_generator.py b/tests_basic/core/test_generator.py index ea2ea603..f23498d6 100644 --- a/tests_basic/core/test_generator.py +++ b/tests_basic/core/test_generator.py @@ -10,22 +10,21 @@ from pylinac import Interpolation, Normalization from pylinac.core.image import load from pylinac.core.image_generator import ( - AS1200Image, - PerfectFieldLayer, - PerfectBBLayer, - PerfectConeLayer, AS500Image, AS1000Image, + AS1200Image, ConstantLayer, - GaussianFilterLayer, FilterFreeFieldLayer, + GaussianFilterLayer, + PerfectBBLayer, + PerfectConeLayer, + PerfectFieldLayer, RandomNoiseLayer, ) from pylinac.core.image_generator.layers import Layer, clip_add, even_round from pylinac.core.image_generator.simulators import Simulator from pylinac.core.profile import SingleProfile - np.random.seed(1234) # reproducible noise results diff --git a/tests_basic/core/test_image.py b/tests_basic/core/test_image.py index d18e1609..651e5aa1 100644 --- a/tests_basic/core/test_image.py +++ b/tests_basic/core/test_image.py @@ -6,23 +6,23 @@ import unittest from unittest import TestCase -import PIL.Image import numpy as np +import PIL.Image from numpy.testing import assert_array_almost_equal from pylinac.core import image from pylinac.core.geometry import Point from pylinac.core.image import ( - DicomImage, + XIM, ArrayImage, - FileImage, + DicomImage, DicomImageStack, + FileImage, LinacDicomImage, gamma_2d, - XIM, ) from pylinac.core.io import TemporaryZipDirectory -from tests_basic.utils import save_file, get_file_from_cloud_test_repo +from tests_basic.utils import get_file_from_cloud_test_repo, save_file tif_path = get_file_from_cloud_test_repo(["Starshot", "Starshot-1.tif"]) png_path = get_file_from_cloud_test_repo(["Starshot", "Starshot-1.png"]) diff --git a/tests_basic/core/test_io.py b/tests_basic/core/test_io.py index 9b100569..7e66f659 100644 --- a/tests_basic/core/test_io.py +++ b/tests_basic/core/test_io.py @@ -1,14 +1,14 @@ """Test suite for the pylinac.io module.""" -import unittest import os import os.path as osp +import unittest from pylinac.core.io import ( + SNCProfiler, TemporaryZipDirectory, - get_url, URLError, + get_url, is_dicom, - SNCProfiler, ) from pylinac.core.profile import SingleProfile from tests_basic.utils import get_file_from_cloud_test_repo diff --git a/tests_basic/core/test_pdf.py b/tests_basic/core/test_pdf.py index 3da553f7..026a26f1 100644 --- a/tests_basic/core/test_pdf.py +++ b/tests_basic/core/test_pdf.py @@ -4,15 +4,15 @@ from pathlib import Path from pylinac import ( - PicketFence, + DRGS, CatPhan604, - FieldAnalysis, Dynalog, + FieldAnalysis, LeedsTOR, - StandardImagingFC2, + PicketFence, QuartDVT, + StandardImagingFC2, Starshot, - DRGS, WinstonLutz, ) diff --git a/tests_basic/core/test_profile.py b/tests_basic/core/test_profile.py index ea236b2e..96d67199 100644 --- a/tests_basic/core/test_profile.py +++ b/tests_basic/core/test_profile.py @@ -6,12 +6,12 @@ from pylinac.core import image from pylinac.core.image_generator.simulators import Simulator from pylinac.core.profile import ( - SingleProfile, - MultiProfile, CircleProfile, CollapsedCircleProfile, - Normalization, Interpolation, + MultiProfile, + Normalization, + SingleProfile, gamma_1d, ) from tests_basic.utils import get_file_from_cloud_test_repo diff --git a/tests_basic/test_acr.py b/tests_basic/test_acr.py index d4ed4e4e..06071f0c 100644 --- a/tests_basic/test_acr.py +++ b/tests_basic/test_acr.py @@ -11,11 +11,11 @@ from pylinac.core.geometry import Point from pylinac.core.io import TemporaryZipDirectory from tests_basic.utils import ( - InitTesterMixin, + CloudFileMixin, FromZipTesterMixin, + InitTesterMixin, get_file_from_cloud_test_repo, save_file, - CloudFileMixin, ) TEST_DIR_CT = ["ACR", "CT"] diff --git a/tests_basic/test_cbct.py b/tests_basic/test_cbct.py index 29879895..5fe31b68 100644 --- a/tests_basic/test_cbct.py +++ b/tests_basic/test_cbct.py @@ -9,15 +9,15 @@ from pylinac import CatPhan503, CatPhan504, CatPhan600, CatPhan604 from pylinac.core.geometry import Point from pylinac.core.io import TemporaryZipDirectory -from pylinac.ct import CTP404CP504, CTP404CP503, CTP528CP503, CTP528CP504, CatphanResult +from pylinac.ct import CTP404CP503, CTP404CP504, CTP528CP503, CTP528CP504, CatphanResult from tests_basic.utils import ( - save_file, CloudFileMixin, - get_file_from_cloud_test_repo, - InitTesterMixin, FromDemoImageTesterMixin, FromURLTesterMixin, FromZipTesterMixin, + InitTesterMixin, + get_file_from_cloud_test_repo, + save_file, ) TEST_DIR = "CBCT" diff --git a/tests_basic/test_field_analysis.py b/tests_basic/test_field_analysis.py index eb244f60..7f342bc5 100644 --- a/tests_basic/test_field_analysis.py +++ b/tests_basic/test_field_analysis.py @@ -9,23 +9,23 @@ from pylinac.core import image from pylinac.core.exceptions import NotAnalyzed from pylinac.core.io import retrieve_demo_file -from pylinac.core.profile import Edge, Normalization, Interpolation +from pylinac.core.profile import Edge, Interpolation, Normalization from pylinac.field_analysis import ( + Centering, + DeviceFieldAnalysis, FieldAnalysis, + FieldResult, Protocol, - DeviceFieldAnalysis, - Centering, - symmetry_point_difference, flatness_dose_difference, plot_flatness, plot_symmetry_point_difference, - FieldResult, + symmetry_point_difference, ) from tests_basic.utils import ( - has_www_connection, CloudFileMixin, - save_file, get_file_from_cloud_test_repo, + has_www_connection, + save_file, ) TEST_DIR = "flatness_symmetry" diff --git a/tests_basic/test_logs.py b/tests_basic/test_logs.py index 6a19fe4c..ec84df76 100644 --- a/tests_basic/test_logs.py +++ b/tests_basic/test_logs.py @@ -1,30 +1,30 @@ import io -import os.path as osp import os -from unittest import TestCase +import os.path as osp import shutil import tempfile +from unittest import TestCase import numpy as np from pylinac.log_analyzer import ( - MachineLogs, - TreatmentType, - anonymize, - TrajectoryLog, Dynalog, - load_log, DynalogMatchError, + MachineLogs, NotADynalogError, NotALogError, + TrajectoryLog, + TreatmentType, + anonymize, + load_log, ) from tests_basic.utils import ( - save_file, CloudFileMixin, - get_file_from_cloud_test_repo, - get_folder_from_cloud_test_repo, FromDemoImageTesterMixin, FromURLTesterMixin, + get_file_from_cloud_test_repo, + get_folder_from_cloud_test_repo, + save_file, ) TEST_DIR = "mlc_logs" diff --git a/tests_basic/test_picketfence.py b/tests_basic/test_picketfence.py index 72d5b205..eb673cf8 100644 --- a/tests_basic/test_picketfence.py +++ b/tests_basic/test_picketfence.py @@ -8,14 +8,14 @@ from scipy import ndimage from pylinac.core import image -from pylinac.picketfence import PicketFence, Orientation, PFResult, MLCArrangement, MLC +from pylinac.picketfence import MLC, MLCArrangement, Orientation, PFResult, PicketFence from tests_basic.utils import ( - save_file, CloudFileMixin, - get_file_from_cloud_test_repo, - InitTesterMixin, - FromURLTesterMixin, FromDemoImageTesterMixin, + FromURLTesterMixin, + InitTesterMixin, + get_file_from_cloud_test_repo, + save_file, ) TEST_DIR = "picket_fence" diff --git a/tests_basic/test_planar_imaging.py b/tests_basic/test_planar_imaging.py index dcf8afc2..0ce0c570 100644 --- a/tests_basic/test_planar_imaging.py +++ b/tests_basic/test_planar_imaging.py @@ -9,27 +9,27 @@ from scipy.ndimage import rotate from pylinac import ( - LeedsTOR, - StandardImagingQC3, - LasVegas, DoselabMC2kV, DoselabMC2MV, IBAPrimusA, + LasVegas, + LeedsTOR, + StandardImagingQC3, ) from pylinac.core import image from pylinac.planar_imaging import ( - PlanarResult, - SNCkV, - SNCMV, - StandardImagingQCkV, PTWEPIDQC, - StandardImagingFC2, - IMTLRad, SNCFSQA, - LeedsTORBlue, + SNCMV, SNCMV12510, + IMTLRad, + LeedsTORBlue, + PlanarResult, + SNCkV, + StandardImagingFC2, + StandardImagingQCkV, ) -from tests_basic.utils import save_file, CloudFileMixin, get_file_from_cloud_test_repo +from tests_basic.utils import CloudFileMixin, get_file_from_cloud_test_repo, save_file TEST_DIR = "planar_imaging" diff --git a/tests_basic/test_quart.py b/tests_basic/test_quart.py index ae8c95fc..61a928e1 100644 --- a/tests_basic/test_quart.py +++ b/tests_basic/test_quart.py @@ -9,14 +9,14 @@ from pylinac import QuartDVT from pylinac.core.geometry import Point from pylinac.core.io import TemporaryZipDirectory -from pylinac.quart import QuartDVTResult, ACRYLIC, POLY +from pylinac.quart import ACRYLIC, POLY, QuartDVTResult from tests_basic.utils import ( - InitTesterMixin, + CloudFileMixin, FromZipTesterMixin, + InitTesterMixin, get_file_from_cloud_test_repo, - save_file, - CloudFileMixin, get_folder_from_cloud_test_repo, + save_file, ) TEST_DIR = ["CBCT", "Quart"] diff --git a/tests_basic/test_starshot.py b/tests_basic/test_starshot.py index 90db4771..56f6848d 100644 --- a/tests_basic/test_starshot.py +++ b/tests_basic/test_starshot.py @@ -11,11 +11,11 @@ from pylinac.core.geometry import Point from pylinac.starshot import StarshotResults from tests_basic.utils import ( - save_file, CloudFileMixin, + FromURLTesterMixin, get_file_from_cloud_test_repo, get_folder_from_cloud_test_repo, - FromURLTesterMixin, + save_file, ) plt.close("all") diff --git a/tests_basic/test_vmat.py b/tests_basic/test_vmat.py index 085a0093..b4064f88 100644 --- a/tests_basic/test_vmat.py +++ b/tests_basic/test_vmat.py @@ -1,6 +1,6 @@ import io from functools import partial -from typing import Union, Type, Iterable +from typing import Iterable, Type, Union from unittest import TestCase from matplotlib import pyplot as plt @@ -9,10 +9,10 @@ from pylinac.core.geometry import Point from pylinac.vmat import VMATResult from tests_basic.utils import ( - save_file, - get_file_from_cloud_test_repo, - FromURLTesterMixin, FromDemoImageTesterMixin, + FromURLTesterMixin, + get_file_from_cloud_test_repo, + save_file, ) TEST_DIR = "VMAT" diff --git a/tests_basic/test_winstonlutz.py b/tests_basic/test_winstonlutz.py index 027e02e1..f9490892 100644 --- a/tests_basic/test_winstonlutz.py +++ b/tests_basic/test_winstonlutz.py @@ -14,19 +14,19 @@ from pylinac.core.scale import MachineScale from pylinac.winston_lutz import ( Axis, - WinstonLutzResult, + BBArrangement, WinstonLutz2D, - bb_projection_long, + WinstonLutzResult, bb_projection_gantry_plane, - BBArrangement, + bb_projection_long, ) from tests_basic.utils import ( - save_file, CloudFileMixin, - get_folder_from_cloud_test_repo, - get_file_from_cloud_test_repo, FromDemoImageTesterMixin, FromURLTesterMixin, + get_file_from_cloud_test_repo, + get_folder_from_cloud_test_repo, + save_file, ) TEST_DIR = "Winston-Lutz" diff --git a/tests_basic/utils.py b/tests_basic/utils.py index d3df139e..696d21b6 100644 --- a/tests_basic/utils.py +++ b/tests_basic/utils.py @@ -11,7 +11,7 @@ from io import BytesIO, StringIO from pathlib import Path, PurePosixPath from tempfile import TemporaryDirectory -from typing import List, Sequence, Callable, Union +from typing import Callable, List, Sequence, Union from urllib.request import urlopen from google.cloud import storage @@ -144,9 +144,9 @@ def save_file(method, *args, as_file_object=None, to_single_file=True, **kwargs) def point_equality_validation(point1, point2): if point1.x != point2.x: - raise ValueError("{} does not equal {}".format(point1.x, point2.x)) + raise ValueError(f"{point1.x} does not equal {point2.x}") if point1.y != point2.y: - raise ValueError("{} does not equal {}".format(point1.y, point2.y)) + raise ValueError(f"{point1.y} does not equal {point2.y}") class CloudFileMixin: @@ -268,7 +268,7 @@ class DataBankMixin: def setUpClass(cls): cls.DATA_DIR = osp.join(cls.DATA_BANK_DIR, *cls.DATA_DIR) if not osp.isdir(cls.DATA_DIR): - raise NotADirectoryError("Directory {} is not valid".format(cls.DATA_DIR)) + raise NotADirectoryError(f"Directory {cls.DATA_DIR} is not valid") def file_should_be_processed(self, filepath): """Decision of whether file should be run. Returns boolean.""" @@ -320,11 +320,9 @@ def test_all(self, func): ) ) if len(fails) > 0: - pprint.pprint("Failures: {}".format(fails)) + pprint.pprint(f"Failures: {fails}") if self.write_failures_to_file: - with open( - "failures_{}.txt".format(osp.basename(self.DATA_DIR)), mode="w" - ) as f: + with open(f"failures_{osp.basename(self.DATA_DIR)}.txt", mode="w") as f: for file in fails: f.write(file + "\n") print("Failures written to file")