Skip to content

Commit 19ee5b2

Browse files
committed
Add ruff and address miscellaneous ruff issues
1 parent 50af664 commit 19ee5b2

File tree

7 files changed

+92
-51
lines changed

7 files changed

+92
-51
lines changed

.pre-commit-config.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,17 @@ repos:
2323
- id: mixed-line-ending
2424
# Makes all line endings unix-style
2525
args: [--fix=lf]
26+
27+
28+
# Per the ruff documentation, this should be before black
29+
- repo: https://github.com/astral-sh/ruff-pre-commit
30+
# Ruff version.
31+
rev: v0.11.13
32+
hooks:
33+
# Run the linter.
34+
- id: ruff
35+
args: [--fix]
36+
2637
- repo: https://github.com/psf/black
2738
rev: 25.1.0
2839
hooks:

pyproject.toml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,22 @@ exclude_lines = [
6666
"if __name__ == .__main__.:",
6767
"if TYPE_CHECKING:",
6868
]
69+
70+
[tool.black]
71+
line-length = 88
72+
73+
[tool.ruff]
74+
# ruff 0.6.0 started automatically linting notebooks. We are not ready for that yet.
75+
extend-exclude = ["*.ipynb"]
76+
77+
[tool.ruff.lint]
78+
select = [
79+
"E", # E and W are the checks done by pycodestyle
80+
"W",
81+
"F", # pyflakes checks
82+
"ARG", # flake8-unused-arguments
83+
"UP", # language updates
84+
"NPY", # check for numpy deprecations
85+
"I", # isort checks
86+
"B", # flake8-bugbear
87+
]

src/astro_image_display_api/dummy_viewer.py

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@
1111
from astropy.nddata import CCDData, NDData
1212
from astropy.table import Table, vstack
1313
from astropy.units import Quantity
14-
from astropy.wcs import WCS
15-
from astropy.wcs.utils import proj_plane_pixel_scales
1614
from astropy.visualization import (
1715
AsymmetricPercentileInterval,
1816
BaseInterval,
1917
BaseStretch,
2018
LinearStretch,
2119
ManualInterval,
2220
)
21+
from astropy.wcs import WCS
22+
from astropy.wcs.utils import proj_plane_pixel_scales
2323
from numpy.typing import ArrayLike
2424

2525
from .interface_definition import ImageViewerInterface
@@ -114,7 +114,8 @@ def _resolve_catalog_label(self, catalog_label: str | None) -> str:
114114
catalog_label = user_keys[0]
115115
case _:
116116
raise ValueError(
117-
"Multiple catalog styles defined. Please specify a catalog_label to get the style."
117+
"Multiple catalog styles defined. Please specify a "
118+
"catalog_label to get the style."
118119
)
119120

120121
return catalog_label
@@ -141,7 +142,8 @@ def get_stretch(self, image_label: str | None = None) -> BaseStretch:
141142
def set_stretch(self, value: BaseStretch, image_label: str | None = None) -> None:
142143
if not isinstance(value, BaseStretch):
143144
raise TypeError(
144-
f"Stretch option {value} is not valid. Must be an Astropy.visualization Stretch object."
145+
f"Stretch option {value} is not valid. Must be an "
146+
"`astropy.visualization` Stretch object."
145147
)
146148
image_label = self._resolve_image_label(image_label)
147149
if image_label not in self._images:
@@ -169,7 +171,8 @@ def set_cuts(
169171
self._cuts = value
170172
else:
171173
raise TypeError(
172-
"Cuts must be an Astropy.visualization Interval object or a tuple of two values."
174+
"Cuts must be an Astropy.visualization Interval object or a tuple "
175+
"of two values."
173176
)
174177
image_label = self._resolve_image_label(image_label)
175178
if image_label not in self._images:
@@ -206,7 +209,8 @@ def cursor(self) -> str:
206209
def cursor(self, value: str) -> None:
207210
if value not in self.ALLOWED_CURSOR_LOCATIONS:
208211
raise ValueError(
209-
f"Cursor location {value} is not valid. Must be one of {self.ALLOWED_CURSOR_LOCATIONS}."
212+
f"Cursor location {value} is not valid. Must be one of "
213+
f"{self.ALLOWED_CURSOR_LOCATIONS}."
210214
)
211215
self._cursor = value
212216

@@ -296,7 +300,8 @@ def _resolve_image_label(self, image_label: str | None) -> str:
296300
image_label = user_keys[0]
297301
case _:
298302
raise ValueError(
299-
"Multiple image labels defined. Please specify a image_label to get the style."
303+
"Multiple image labels defined. Please specify a image_label "
304+
"to get the style."
300305
)
301306

302307
return image_label
@@ -324,9 +329,9 @@ def load_image(
324329
if image_label in self._images:
325330
del self._images[image_label]
326331

327-
if isinstance(file, (str, os.PathLike)):
332+
if isinstance(file, str | os.PathLike):
328333
if isinstance(file, str):
329-
is_adsf = file.endswith(".asdf")
334+
is_asdf = file.endswith(".asdf")
330335
else:
331336
is_asdf = file.suffix == ".asdf"
332337
if is_asdf:
@@ -567,8 +572,8 @@ def remove_catalog(self, catalog_label: str | None = None) -> None:
567572

568573
try:
569574
del self._catalogs[catalog_label]
570-
except KeyError:
571-
raise ValueError(f"Catalog label {catalog_label} not found.")
575+
except KeyError as err:
576+
raise ValueError(f"Catalog label {catalog_label} not found.") from err
572577

573578
def get_catalog(
574579
self,
@@ -623,11 +628,12 @@ def set_viewport(
623628
fov = current_viewport.fov
624629

625630
# If either center or fov is None these checks will raise an appropriate error
626-
if not isinstance(center, (SkyCoord, tuple)):
631+
if not isinstance(center, SkyCoord | tuple):
627632
raise TypeError(
628-
"Invalid value for center. Center must be a SkyCoord or tuple of (X, Y)."
633+
"Invalid value for center. Center must be a SkyCoord or tuple "
634+
"of (X, Y)."
629635
)
630-
if not isinstance(fov, (Quantity, numbers.Real)):
636+
if not isinstance(fov, Quantity | numbers.Real):
631637
raise TypeError(
632638
"Invalid value for fov. fov must be an angular Quantity or float."
633639
)
@@ -640,8 +646,9 @@ def set_viewport(
640646
# Check that the center and fov are compatible with the current image
641647
if self._images[image_label].wcs is None:
642648
if current_viewport.center is not None:
643-
# If there is a WCS either input is fine. If there is no WCS then we only
644-
# check wther the new center is the same type as the current center.
649+
# If there is a WCS either input is fine. If there is no WCS then we
650+
# only check wther the new center is the same type as the
651+
# current center.
645652
if isinstance(center, SkyCoord) and not isinstance(
646653
current_viewport.center, SkyCoord
647654
):
@@ -711,7 +718,8 @@ def get_viewport(
711718
# was not already sky, so we need to convert them or fail
712719
if viewport.wcs is None:
713720
raise ValueError(
714-
"WCS is not set. Cannot convert pixel coordinates to sky coordinates."
721+
"WCS is not set. Cannot convert pixel coordinates to "
722+
"sky coordinates."
715723
)
716724
else:
717725
center = viewport.wcs.pixel_to_world(
@@ -726,7 +734,8 @@ def get_viewport(
726734
if isinstance(viewport.center, SkyCoord):
727735
if viewport.wcs is None:
728736
raise ValueError(
729-
"WCS is not set. Cannot convert sky coordinates to pixel coordinates."
737+
"WCS is not set. Cannot convert sky coordinates to "
738+
"pixel coordinates."
730739
)
731740
center = viewport.wcs.world_to_pixel(viewport.center)
732741
else:

src/astro_image_display_api/interface_definition.py

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
from typing import Protocol, runtime_checkable, Any
2-
from abc import abstractmethod
31
import numbers
42
import os
3+
from abc import abstractmethod
4+
from typing import Any, Protocol, runtime_checkable
55

66
from astropy.coordinates import SkyCoord
77
from astropy.table import Table
88
from astropy.units import Quantity
99
from astropy.visualization import BaseInterval, BaseStretch
1010

11-
1211
# Allowed locations for cursor display
1312
ALLOWED_CURSOR_LOCATIONS = ("top", "bottom", None)
1413

@@ -78,8 +77,8 @@ def set_cuts(
7877
Raises
7978
------
8079
TypeError
81-
If the `cuts` parameter is not a tuple or an `astropy.visualization.BaseInterval`
82-
object.
80+
If the `cuts` parameter is not a tuple or an
81+
`astropy.visualization.BaseInterval` object.
8382
8483
ValueError
8584
If the `image_label` is not provided when there are multiple images loaded,
@@ -204,8 +203,8 @@ def get_colormap(self, image_label: str | None = None) -> str:
204203
Raises
205204
------
206205
ValueError
207-
If the `image_label` is not provided when there are multiple images loaded or if
208-
the `image_label` does not correspond to a loaded image.
206+
If the `image_label` is not provided when there are multiple images loaded
207+
or if the `image_label` does not correspond to a loaded image.
209208
"""
210209
raise NotImplementedError
211210

@@ -287,7 +286,7 @@ def set_catalog_style(
287286
shape: str = "circle",
288287
color: str = "red",
289288
size: float = 5.0,
290-
**kwargs
289+
**kwargs,
291290
):
292291
"""
293292
Set the style of the catalog markers.
@@ -408,7 +407,8 @@ def get_catalog(
408407
Raises
409408
------
410409
ValueError
411-
If the `catalog_label` is not provided when there are multiple catalogs loaded.
410+
If the `catalog_label` is not provided when there are multiple catalogs
411+
loaded.
412412
"""
413413
raise NotImplementedError
414414

@@ -441,8 +441,9 @@ def set_viewport(
441441
The center of the viewport. If not given, the current center is used.
442442
fov : `astropy.units.Quantity` or float, optional
443443
The field of view (FOV) of the viewport. If not given, the current FOV
444-
is used. If a float is given, it is interpreted a size in pixels. For images that are
445-
not square, the FOV is interpreted as the size of the longer side of the image.
444+
is used. If a float is given, it is interpreted a size in pixels. For images
445+
that are not square, the FOV is interpreted as the size of the longer side
446+
of the image.
446447
image_label : str, optional
447448
The label of the image to set the viewport for. If not given and there is
448449
only one image loaded, the viewport for that image is set. If there are
@@ -476,12 +477,12 @@ def get_viewport(
476477
If 'sky', the center will be returned as a `SkyCoord` object.
477478
If 'pixel', the center will be returned as a tuple of pixel coordinates.
478479
If `None`, the default behavior is to return the center as a `SkyCoord` if
479-
possible, or as a tuple of floats if the image is in pixel coordinates and has
480-
no WCS information.
480+
possible, or as a tuple of floats if the image is in pixel coordinates and
481+
has no WCS information.
481482
image_label : str, optional
482-
The label of the image to get the viewport for. If not given and there is only one
483-
image loaded, the viewport for that image is returned. If there are multiple images
484-
and no label is provided, an error is raised.
483+
The label of the image to get the viewport for. If not given and there is
484+
only one image loaded, the viewport for that image is returned. If there
485+
are multiple images and no label is provided, an error is raised.
485486
486487
Returns
487488
-------
@@ -495,8 +496,8 @@ def get_viewport(
495496
Raises
496497
-------
497498
ValueError
498-
If the `sky_or_pixel` parameter is not one of 'sky', 'pixel', or `None`, or if
499-
the `image_label` is not provided when there are multiple images loaded, or if
500-
the `image_label` does not correspond to a loaded image.
499+
If the `sky_or_pixel` parameter is not one of 'sky', 'pixel', or `None`,
500+
or if the `image_label` is not provided when there are multiple images
501+
loaded, or if the `image_label` does not correspond to a loaded image.
501502
"""
502503
raise NotImplementedError

src/astro_image_display_api/widget_api_test.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,20 @@
11
import numbers
22

3-
import pytest
4-
53
import numpy as np
6-
4+
import pytest
5+
from astropy import units as u
76
from astropy.coordinates import SkyCoord
87
from astropy.io import fits
98
from astropy.nddata import CCDData, NDData
109
from astropy.table import Table
11-
from astropy import units as u
12-
from astropy.wcs import WCS
1310
from astropy.visualization import (
1411
AsymmetricPercentileInterval,
1512
BaseInterval,
1613
BaseStretch,
1714
LogStretch,
1815
ManualInterval,
1916
)
17+
from astropy.wcs import WCS
2018

2119
from .interface_definition import ImageViewerInterface
2220

@@ -49,7 +47,7 @@ def wcs(self):
4947
return w
5048

5149
@pytest.fixture
52-
def catalog(self, setup: None, wcs: WCS) -> Table:
50+
def catalog(self, wcs: WCS) -> Table:
5351
"""
5452
A catalog fixture that returns an empty table with the
5553
expected columns.
@@ -177,7 +175,8 @@ def test_set_get_viewport_errors(self, data, wcs):
177175
center=(10, 10), fov=100, image_label="not a valid label"
178176
)
179177

180-
# Getting a viewport for an image_label that does not exist should raise an error
178+
# Getting a viewport for an image_label that does not exist should
179+
# raise an error
181180
with pytest.raises(ValueError, match="[Ii]mage label.*not found"):
182181
self.image.get_viewport(image_label="not a valid label")
183182

@@ -464,7 +463,7 @@ def test_load_get_single_catalog_with_without_label(self, catalog, catalog_label
464463
retrieved_catalog = self.image.get_catalog(catalog_label=catalog_label)
465464
assert (retrieved_catalog == catalog).all()
466465

467-
def test_load_catalog_does_not_modify_input_catalog(self, catalog, data):
466+
def test_load_catalog_does_not_modify_input_catalog(self, catalog):
468467
# Adding a catalog should not modify the input data table.
469468
orig_tab = catalog.copy()
470469
self.image.load_catalog(catalog)

tests/test_astro_image_display_api.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,12 @@ def test_api_test_class_completeness():
2424
attr_present.append(f"{image_viewer_name}.{attr}" in widget_api_test_content)
2525

2626
missing_attributes = [
27-
attr for attr, present in zip(required_attributes, attr_present) if not present
27+
attr
28+
for attr, present in zip(required_attributes, attr_present, strict=False)
29+
if not present
2830
]
2931
missing_attributes_msg = "\n".join(missing_attributes)
30-
assert all(
31-
attr_present
32-
), f"ImageWidgetAPITest does not access these attributes/methods:\n{missing_attributes_msg}\n"
32+
assert all(attr_present), (
33+
"ImageWidgetAPITest does not access these "
34+
f"attributes/methods:\n{missing_attributes_msg}\n"
35+
)

tests/test_dummy_viewer.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1+
from astro_image_display_api import ImageViewerInterface, ImageWidgetAPITest
12
from astro_image_display_api.dummy_viewer import ImageViewer
2-
from astro_image_display_api import ImageViewerInterface
3-
from astro_image_display_api import ImageWidgetAPITest
43

54

65
def test_instance():

0 commit comments

Comments
 (0)