Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2348 Pyright #2349

Merged
merged 24 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ae89559
Add Pyright Developer Environment Dependancy List
JackEAllen Oct 21, 2024
a2a7437
Configure Pyright Ruleset
JackEAllen Oct 21, 2024
56805d6
Update Makefile to include Pyright
JackEAllen Oct 21, 2024
b210ad5
Add pyright conda and windows workflows
JackEAllen Nov 1, 2024
9740fbe
Update pre-commit to add pyright check
JackEAllen Nov 1, 2024
57ef6ab
Resolve Pyright reportOptionalSubscript Errors
JackEAllen Oct 22, 2024
004d2a7
Resolve Pyright reportOperatorIssue Error
JackEAllen Oct 22, 2024
55160fc
Resolve Pyright reportGeneralTypeIssues Error
JackEAllen Oct 22, 2024
d2b6c2c
Resolve Pyright reportReturnType Errors
JackEAllen Oct 23, 2024
6585fd4
Resolve Pyright reportSelfClsParameterName
JackEAllen Oct 23, 2024
f3ba1c3
Resolve Pyright reportOptionalOperand
JackEAllen Oct 23, 2024
959a235
Resolve Pyright ImageStack
JackEAllen Oct 23, 2024
ab279fa
Resolve pyright reportOptionalOperand and reportOptionalOperand in Ne…
JackEAllen Oct 30, 2024
d9d2304
Resolve pyright reportReturnType errors
JackEAllen Oct 30, 2024
b968c8e
Remove _divide_by_counts() as does not seem to be used
JackEAllen Oct 30, 2024
0c50265
Resolve Pyright reportReturnType errors in astra and cil recon methods
JackEAllen Oct 30, 2024
5596272
Resolve pyright reportUnboundVariable and reportOperatorIssue errors …
JackEAllen Oct 30, 2024
d2bdc22
Resolve pyright reportReturnType in AsyncTask task_is_running()
JackEAllen Nov 1, 2024
2409286
Resolve Pyright Declaration 'step' is obscured by a declaration of t…
JackEAllen Nov 1, 2024
080fd75
Resolve 'float' is not assignable to 'int' (reportReturnType)
JackEAllen Nov 1, 2024
7fb0067
Resolve pyright reportOptionalOperand
JackEAllen Nov 1, 2024
c01414d
Ignore pyright reportUndefinedVariable in eyes manager
JackEAllen Oct 30, 2024
5933496
Ignore pyright reportReturnType
JackEAllen Nov 1, 2024
3b1c28f
Release Notes
JackEAllen Nov 1, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/conda.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ jobs:
run: |
mypy --ignore-missing-imports mantidimaging

- name: pyright
shell: bash -l {0}
run: |
pyright mantidimaging

- name: pytest
timeout-minutes: 10
shell: bash -l {0}
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ jobs:
run: |
mypy --ignore-missing-imports mantidimaging

- name: pyright
shell: bash -l {0}
run: |
pyright mantidimaging

- name: pytest
timeout-minutes: 10
shell: bash -l {0}
Expand Down
9 changes: 9 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,16 @@ repos:
files: ^mantidimaging/
args: [--ignore-missing-imports]
additional_dependencies: [types-docutils, types-PyYAML, types-requests]
- repo: local
hooks:
- id: pyright
name: pyright
description: Checks that all files pass pyright checks
entry: pyright
language: system
types: [python]
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.3.3
hooks:
- id: ruff

3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ test-screenshots-win:
mypy:
python -m mypy --ignore-missing-imports ${SOURCE_DIRS}

pyright:
python -m pyright ${SOURCE_DIRS}

yapf:
python -m yapf --parallel --diff --recursive ${SOURCE_DIRS}

Expand Down
1 change: 1 addition & 0 deletions docs/release_notes/next/dev-2348-Pyright
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#2348: Pyright dependancy to project, configure pyright basic rulest and resolve issues raised by pyright in basic configuration
1 change: 1 addition & 0 deletions environment-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ dependencies:
- pyfakefs==5.3.*
- parameterized==0.9.*
- pyinstaller==6.9.*
- pyright==1.1.*
- make==4.3
- ruff=0.3.3
- pre-commit==3.5.*
Expand Down
8 changes: 4 additions & 4 deletions mantidimaging/core/io/instrument_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ class InstrumentLogParser(BaseParser):

"""

def __init_subclass__(subcls) -> None:
def __init_subclass__(cls) -> None:
"""Automatically register subclasses"""
InstrumentLog.register_parser(subcls)
InstrumentLog.register_parser(cls)

@abstractmethod
def parse(self) -> LogDataType:
Expand All @@ -103,9 +103,9 @@ class InstrumentShutterCountParser(BaseParser):

"""

def __init_subclass__(subcls) -> None:
def __init_subclass__(cls) -> None:
"""Automatically register subclasses"""
ShutterCount.register_parser(subcls)
ShutterCount.register_parser(cls)

@abstractmethod
def parse(self) -> ShutterCountType:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@
from PyQt5.QtWidgets import QFormLayout, QWidget


def _divide_by_counts(data=None, counts=None):
data[:] = np.true_divide(data, counts)


class MonitorNormalisation(BaseFilter):
"""Normalises the image data using the average count of a beam monitor from the
experiment log file. This scaling operation is an alternative to ROI normalisation
Expand Down
2 changes: 1 addition & 1 deletion mantidimaging/core/reconstruct/astra_recon.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def find_cor(images: ImageStack, slice_idx: int, start_cor: float | np.ndarray,
proj_angles = images.projection_angles(recon_params.max_projection_angle)

def get_sumsq(image: np.ndarray) -> float:
return np.sum(image**2)
return float(np.sum(image**2))

def minimizer_function(cor: float | np.ndarray) -> float:
if isinstance(cor, np.ndarray):
Expand Down
2 changes: 1 addition & 1 deletion mantidimaging/core/reconstruct/cil_recon.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ def set_approx_norm(A2d: BlockOperator, acquisition_data: AcquisitionGeometry,

@staticmethod
def get_data(sino: np.ndarray, ag: AcquisitionGeometry, recon_params: ReconstructionParameters,
num_subsets: int) -> AcquisitionData:
num_subsets: int) -> BlockDataContainer | AcquisitionData:
data = AcquisitionData(sino, deep_copy=False, geometry=ag, suppress_warning=True)

if recon_params.stochastic:
Expand Down
1 change: 1 addition & 0 deletions mantidimaging/core/utility/histogram.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def set_histogram_log_scale(histogram: HistogramLUTItem) -> None:
:param histogram: The HistogramLUTItem of an image.
"""
x_data, y_data = histogram.plot.getData()
assert isinstance(x_data, np.ndarray) and isinstance(y_data, np.ndarray)
histogram.plot.setData(x_data, np.log(y_data + 1))


Expand Down
16 changes: 5 additions & 11 deletions mantidimaging/core/utility/memory_usage.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,20 @@ def mb(self):
return Value(meminfo.available - meminfo.total * MEMORY_CAP_PERCENTAGE)


def get_memory_usage_linux(kb=False, mb=False):
def get_memory_usage_linux() -> float:
"""
:param kb: Return the value in Kilobytes
:param mb: Return the value in Megabytes
Get the memory usage of the system in bytes
"""
import psutil

meminfo = psutil.virtual_memory()
tuple_to_return = () # start with empty tuple
# meminfo.used gives the size in bytes
if kb:
tuple_to_return += (meminfo.used / 1024, )

if mb:
tuple_to_return += (meminfo.used / 1024 / 1024, )
return tuple_to_return
return meminfo.used


def get_memory_usage_linux_str():
memory_in_kbs, memory_in_mbs = get_memory_usage_linux(kb=True, mb=True)
memory_in_kbs = get_memory_usage_linux() / 1024
memory_in_mbs = memory_in_kbs / 1024
# handle caching
memory_string = f"{memory_in_kbs} KB, {memory_in_mbs} MB"

Expand Down
5 changes: 2 additions & 3 deletions mantidimaging/core/utility/test/memory_usage_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,8 @@ def test_get_memory_usage_linux(self, mock_virtual_memory):
mock_meminfo.used = 4 * 1024 * 1024 * 1024 # 4 GB
mock_virtual_memory.return_value = mock_meminfo

memory_kb, memory_mb = get_memory_usage_linux(kb=True, mb=True)
self.assertEqual(memory_kb, 4 * 1024 * 1024)
self.assertEqual(memory_mb, 4 * 1024)
memory_in_bytes = get_memory_usage_linux()
self.assertEqual(memory_in_bytes, 4 * 1024 * 1024 * 1024)


if __name__ == '__main__':
Expand Down
5 changes: 3 additions & 2 deletions mantidimaging/eyes_tests/base_eyes.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
@start_qapplication
class BaseEyesTest(unittest.TestCase):
eyes_manager: EyesManager
app: QApplication

@classmethod
def setUpClass(cls) -> None:
Expand Down Expand Up @@ -130,8 +131,8 @@ def _create_new_dataset(self) -> Dataset:

return new_dataset

def _get_top_level_widget(cls, widget_type):
for widget in cls.app.topLevelWidgets():
def _get_top_level_widget(self, widget_type):
for widget in self.app.topLevelWidgets():
if isinstance(widget, widget_type):
return widget
raise ValueError(f"Could not find top level widget of type {widget_type.__name__}")
4 changes: 2 additions & 2 deletions mantidimaging/eyes_tests/eyes_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class EyesManager:

def __init__(self, application_name="Mantid Imaging", test_name=None):
self.application_name = application_name
self.eyes = Eyes()
self.eyes = Eyes() # type: ignore
self.eyes.match_level = MatchLevel.IGNORE_COLORS
self.eyes.configure.host_os = sys.platform
self.eyes.branch_name = BRANCH_NAME
Expand All @@ -50,7 +50,7 @@ def set_match_level(self, level: MatchLevel):
self.eyes.match_level = level

def set_batch(self, batch_id):
batch_info = BatchInfo()
batch_info = BatchInfo() # type: ignore
batch_info.name = self.test_name
batch_info.id = batch_id
self.eyes.batch = batch_info
Expand Down
2 changes: 1 addition & 1 deletion mantidimaging/gui/dialogs/async_task/presenter.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def do_start_processing(self) -> None:
self.view.show_delayed(1000)

@property
def task_is_running(self) -> None:
def task_is_running(self) -> bool:
return self.model.task_is_running

def progress_update(self) -> None:
Expand Down
1 change: 0 additions & 1 deletion mantidimaging/gui/dialogs/cor_inspection/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@


class CORInspectionDialogModel:
step: int | float

def __init__(self, images: ImageStack, slice_idx: int, initial_cor: ScalarCoR,
recon_params: ReconstructionParameters, iters_mode: bool):
Expand Down
2 changes: 1 addition & 1 deletion mantidimaging/gui/dialogs/cor_inspection/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def optimal_rotation_centre(self) -> ScalarCoR:
return self.presenter.optimal_rotation_centre

@property
def optimal_iterations(self) -> int:
def optimal_iterations(self) -> int | float:
return self.presenter.optimal_iterations

def mark_best_recon(self, diffs) -> None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def histogram(self) -> HistogramLUTItem:
raise NotImplementedError('Required histogram property not implemented')

@property
def image_data(self) -> np.ndarray:
def image_data(self) -> np.ndarray | None:
raise NotImplementedError('Required image_data property not implemented')

@property
Expand Down
4 changes: 2 additions & 2 deletions mantidimaging/gui/widgets/line_profile_plot/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def get_image_region(self) -> tuple[np.ndarray, np.ndarray] | None:
return self.getArrayRegion(self._image_view.image_data,
self._image_view.image_item,
axes=(1, 0),
returnMappedCoords=True)
returnMappedCoords=True) # type: ignore

def reset(self) -> None:
if self._image_data_exists() and self._roi_line_is_visible:
Expand All @@ -114,7 +114,7 @@ def _set_initial_state(self) -> None:
# Prevent emitting a RegionChanged signal from setting the state programmatically
with BlockQtSignals(self):
initial_pos_x = 0
initial_pos_y = self._image_view.image_item.height() // 2
initial_pos_y = self._image_view.image_item.height() // 2 # type: ignore
image_width = self._image_view.image_item.width()
image_height = self._image_view.image_item.height()

Expand Down
12 changes: 8 additions & 4 deletions mantidimaging/gui/widgets/mi_image_view/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@
from mantidimaging.gui.widgets.mi_image_view.presenter import MIImagePresenter
from mantidimaging.gui.widgets.bad_data_overlay.bad_data_overlay import BadDataOverlay

import numpy as np

if TYPE_CHECKING:
from pyqtgraph import HistogramLUTItem
import numpy as np
from mantidimaging.core.utility.data_containers import ProjectionAngles


Expand Down Expand Up @@ -128,7 +129,7 @@ def histogram(self) -> HistogramLUTItem:
return self.ui.histogram.item

@property
def image_data(self) -> np.ndarray:
def image_data(self) -> np.ndarray | None:
return self.image

@property
Expand Down Expand Up @@ -202,6 +203,7 @@ def roiChanged(self) -> None:
self._refresh_message()

def _update_roi_region_avg(self) -> SensibleROI | None:
assert self.image is not None
if self.image.ndim != 3:
return None
roi_pos, roi_size = self.get_roi()
Expand Down Expand Up @@ -264,15 +266,15 @@ def _update_message(self, pt) -> None:
if self.image.ndim == 3:
x = clip(pt.x, 0, self.image.shape[2] - 1)
y = clip(pt.y, 0, self.image.shape[1] - 1)
value = self.image[self.currentIndex, y, x]
value = self.image[self.currentIndex, y, x] if self.image is not None else 0
msg = f"x={y}, y={x}, z={self.currentIndex}, value={value :.6f}"
if self.angles:
angle = degrees(self.angles.value[self.currentIndex])
msg += f" | angle = {angle:.2f}"
else:
x = clip(pt.x, 0, self.image.shape[1] - 1)
y = clip(pt.y, 0, self.image.shape[0] - 1)
value = self.image[y, x]
value = self.image[y, x] if self.image is not None else 0
msg = f"x={y}, y={x}, value={value}"
if self.roiString is not None:
msg += f" | roi = {self.roiString}"
Expand Down Expand Up @@ -307,6 +309,8 @@ def set_roi(self, coords: list[int] | None) -> None:
def default_roi(self) -> None | list[int]:
# Recommend an ROI that covers the top left quadrant
# However set min dimensions to avoid an ROI that is so small it's difficult to work with
if self.image_data is None:
return None
min_size = 20
roi_width = max(round(self.image_data.shape[2] / 2), min_size)
roi_height = max(round(self.image_data.shape[1] / 2), min_size)
Expand Down
4 changes: 2 additions & 2 deletions mantidimaging/gui/widgets/mi_mini_image_view/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,14 @@ def histogram(self) -> HistogramLUTItem:

@property
def histogram_region(self) -> tuple[int | list[int], int | list[int]]:
return self.hist.region.getRegion()
return self.hist.region.getRegion() # type: ignore

@histogram_region.setter
def histogram_region(self, new_region: tuple[int | list[int], int | list[int]]) -> None:
self.hist.region.setRegion(new_region)

@property
def image_data(self) -> np.ndarray:
def image_data(self) -> np.ndarray | None:
return self.im.image

@property
Expand Down
2 changes: 1 addition & 1 deletion mantidimaging/gui/widgets/palette_changer/presenter.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def _update_ticks(self) -> None:
self.main_hist.gradient.updateGradient()
self.main_hist.gradient.sigGradientChangeFinished.emit(self.main_hist.gradient)

def _get_colours(self, num_ticks: int) -> list[float]:
def _get_colours(self, num_ticks: int) -> list:
"""
Determine the colours that should be used for the new recon histogram ticks. Should ensure that there is a
suitable amount of contrast between the different materials, even if the ticks are quite close together on
Expand Down
8 changes: 7 additions & 1 deletion mantidimaging/gui/windows/main/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,13 @@ def get_stack(self, stack_uuid: uuid.UUID) -> ImageStack:
return self.presenter.get_stack(stack_uuid)

def get_images_from_stack_uuid(self, stack_uuid) -> ImageStack:
return self.presenter.get_stack_visualiser(stack_uuid).presenter.images
stack_visualiser = self.presenter.get_stack_visualiser(stack_uuid)
if stack_visualiser is None:
raise ValueError(f"No stack visualiser found for UUID: {stack_uuid}")
images = stack_visualiser.presenter.images
if images is None:
raise ValueError(f"No images found for stack UUID: {stack_uuid}")
return images

def get_dataset_id_from_stack_uuid(self, stack_id: uuid.UUID) -> uuid.UUID:
return self.presenter.get_dataset_id_for_stack(stack_id)
Expand Down
Loading
Loading