Skip to content

Commit 8f0c245

Browse files
mwcraigCopilot
andauthored
Add exceptions to docstrings and change a couple of exception types (#50)
* Add exceptions to docstrings * Change some error types to be more appropriate * Update dummy viewer to produce correct errors * Clean up a couple minor things * Update src/astro_image_display_api/interface_definition.py Co-authored-by: Copilot <[email protected]> * Add type clarification * More docstring fixees --------- Co-authored-by: Copilot <[email protected]>
1 parent e719090 commit 8f0c245

File tree

3 files changed

+90
-18
lines changed

3 files changed

+90
-18
lines changed

src/astro_image_display_api/dummy_viewer.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ def get_stretch(self, image_label: str | None = None) -> BaseStretch:
127127

128128
def set_stretch(self, value: BaseStretch, image_label: str | None = None) -> None:
129129
if not isinstance(value, BaseStretch):
130-
raise ValueError(f"Stretch option {value} is not valid. Must be an Astropy.visualization Stretch object.")
130+
raise TypeError(f"Stretch option {value} is not valid. Must be an Astropy.visualization Stretch object.")
131131
image_label = self._resolve_image_label(image_label)
132132
if image_label not in self._images:
133133
raise ValueError(f"Image label '{image_label}' not found. Please load an image first.")
@@ -145,7 +145,7 @@ def set_cuts(self, value: tuple[numbers.Real, numbers.Real] | BaseInterval, imag
145145
elif isinstance(value, BaseInterval):
146146
self._cuts = value
147147
else:
148-
raise ValueError("Cuts must be an Astropy.visualization Interval object or a tuple of two values.")
148+
raise TypeError("Cuts must be an Astropy.visualization Interval object or a tuple of two values.")
149149
image_label = self._resolve_image_label(image_label)
150150
if image_label not in self._images:
151151
raise ValueError(f"Image label '{image_label}' not found. Please load an image first.")
@@ -498,7 +498,7 @@ def remove_catalog(self, catalog_label: str | None = None) -> None:
498498
then all markers will be removed.
499499
"""
500500
if isinstance(catalog_label, list):
501-
raise ValueError(
501+
raise TypeError(
502502
"Cannot remove multiple catalogs from a list. Please specify "
503503
"a single catalog label or use '*' to remove all catalogs."
504504
)

src/astro_image_display_api/interface_definition.py

Lines changed: 83 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from typing import Protocol, runtime_checkable, Any
22
from abc import abstractmethod
3+
import numbers
34
import os
45

56
from astropy.coordinates import SkyCoord
@@ -55,7 +56,7 @@ def load_image(self, data: Any, image_label: str | None = None) -> None:
5556

5657
# Setting and getting image properties
5758
@abstractmethod
58-
def set_cuts(self, cuts: tuple | BaseInterval, image_label: str | None = None) -> None:
59+
def set_cuts(self, cuts: tuple[numbers.Real, numbers.Real] | BaseInterval, image_label: str | None = None) -> None:
5960
"""
6061
Set the cuts for the image.
6162
@@ -69,6 +70,16 @@ def set_cuts(self, cuts: tuple | BaseInterval, image_label: str | None = None) -
6970
image_label : str, optional
7071
The label of the image to set the cuts for. If not given and there is
7172
only one image loaded, the cuts for that image are set.
73+
74+
Raises
75+
------
76+
TypeError
77+
If the `cuts` parameter is not a tuple or an `astropy.visualization.BaseInterval`
78+
object.
79+
80+
ValueError
81+
If the `image_label` is not provided when there are multiple images loaded,
82+
or if the `image_label` does not correspond to a loaded image.
7283
"""
7384
raise NotImplementedError
7485

@@ -88,6 +99,12 @@ def get_cuts(self, image_label: str | None = None) -> BaseInterval:
8899
-------
89100
cuts : `~astropy.visualization.BaseInterval`
90101
The Astropy interval object representing the current cuts.
102+
103+
Raises
104+
------
105+
ValueError
106+
If the `image_label` is not provided when there are multiple images loaded,
107+
or if the `image_label` does not correspond to a loaded image.
91108
"""
92109
raise NotImplementedError
93110

@@ -103,8 +120,17 @@ def set_stretch(self, stretch: BaseStretch, image_label: str | None = None) -> N
103120
`~astropy.visualization.BaseStretch`.
104121
105122
image_label : str, optional
106-
The label of the image to set the cuts for. If not given and there is
107-
only one image loaded, the cuts for that image are set.
123+
The label of the image to set the stretch for. If not given and there is
124+
only one image loaded, the stretch for that image are set.
125+
126+
Raises
127+
------
128+
TypeError
129+
If the `stretch` is not a valid `BaseStretch` object
130+
131+
ValueError
132+
if the `image_label` is not provided when there are multiple images loaded
133+
or if the `image_label` does not correspond to a loaded image.
108134
"""
109135
raise NotImplementedError
110136

@@ -194,6 +220,11 @@ def save(self, filename: str | os.PathLike, overwrite: bool = False) -> None:
194220
overwrite : bool, optional
195221
If `True`, overwrite the file if it exists. Default is
196222
`False`.
223+
224+
Raises
225+
------
226+
FileExistsError
227+
If the file already exists and `overwrite` is `False`.
197228
"""
198229
raise NotImplementedError
199230

@@ -229,6 +260,13 @@ def load_catalog(self, table: Table, x_colname: str = 'x', y_colname: str = 'y',
229260
A dictionary that specifies the style of the markers used to
230261
represent the catalog. See `ImageViewerInterface.set_catalog_style`
231262
for details.
263+
264+
Raises
265+
------
266+
ValueError
267+
If the `table` does not contain the required columns, or if
268+
the `catalog_label` is not provided when there are multiple
269+
catalogs loaded.
232270
"""
233271
raise NotImplementedError
234272

@@ -262,6 +300,13 @@ def set_catalog_style(
262300
-----
263301
The following shapes are supported: "circle", "square", "crosshair", "plus",
264302
"diamond".
303+
304+
Raises
305+
------
306+
ValueError
307+
If there are multiple catalog styles set and the user has not
308+
specified a `catalog_label` for which to set the style, or if
309+
an style is set for a catalog that does not exist.
265310
"""
266311
raise NotImplementedError
267312

@@ -270,6 +315,15 @@ def get_catalog_style(self, catalog_label: str | None = None) -> dict:
270315
"""
271316
Get the style of the catalog markers.
272317
318+
Parameters
319+
----------
320+
catalog_label : str, optional
321+
The name of the catalog. If not given and there is
322+
only one catalog loaded, the style for that catalog is returned.
323+
If there are multiple catalogs and no label is provided, an error
324+
is raised. If the label does not correspond to a loaded
325+
catalog, an empty dictionary is returned.
326+
273327
Returns
274328
-------
275329
dict
@@ -281,26 +335,39 @@ def get_catalog_style(self, catalog_label: str | None = None) -> dict:
281335
ValueError
282336
If there are multiple catalog styles set and the user has not
283337
specified a `catalog_label` for which to get the style.
338+
284339
"""
285340
raise NotImplementedError
286341

287342
@abstractmethod
288-
def remove_catalog(self, catalog_label: str | list[str] | None = None) -> None:
343+
def remove_catalog(self, catalog_label: str | None = None) -> None:
289344
"""
290345
Remove markers from the image.
291346
292347
Parameters
293348
----------
294349
catalog_label : str, optional
295-
The name of the marker set to remove. If the value is ``"all"``,
296-
then all markers will be removed.
350+
The name of the catalog to remove. The value ``'*'`` can be used to
351+
remove all catalogs. If not given and there is
352+
only one catalog loaded, that catalog is removed.
353+
354+
Raises
355+
------
356+
ValueError
357+
If the `catalog_label` is not provided when there are multiple
358+
catalogs loaded, or if the `catalog_label` does not correspond to a
359+
loaded catalog.
360+
361+
TypeError
362+
If the `catalog_label` is not a string or `None`, or if it is not
363+
one of the allowed values.
297364
"""
298365
raise NotImplementedError
299366

300367
@abstractmethod
301368
def get_catalog(self, x_colname: str = 'x', y_colname: str = 'y',
302369
skycoord_colname: str = 'coord',
303-
catalog_label: str | list[str] | None = None) -> Table:
370+
catalog_label: str | None = None) -> Table:
304371
"""
305372
Get the marker positions.
306373
@@ -315,15 +382,19 @@ def get_catalog(self, x_colname: str = 'x', y_colname: str = 'y',
315382
skycoord_colname : str, optional
316383
The name of the column containing the sky coordinates. Default
317384
is ``'coord'``.
318-
catalog_label : str or list of str, optional
319-
The name of the marker set to use. If that value is ``"all"``,
320-
then all markers will be returned.
385+
catalog_label : str, optional
386+
The name of the catalog set to get.
321387
322388
Returns
323389
-------
324390
table : `astropy.table.Table`
325391
The table containing the marker positions. If no markers match the
326392
``catalog_label`` parameter, an empty table is returned.
393+
394+
Raises
395+
------
396+
ValueError
397+
If the `catalog_label` is not provided when there are multiple catalogs loaded.
327398
"""
328399
raise NotImplementedError
329400

@@ -408,6 +479,7 @@ def get_viewport(self, sky_or_pixel: str | None = None, image_label: str | None
408479
-------
409480
ValueError
410481
If the `sky_or_pixel` parameter is not one of 'sky', 'pixel', or `None`, or if
411-
the `image_label` is not provided when there are multiple images loaded.
482+
the `image_label` is not provided when there are multiple images loaded, or if
483+
the `image_label` does not correspond to a loaded image.
412484
"""
413485
raise NotImplementedError

src/astro_image_display_api/widget_api_test.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@ def test_remove_catalog_does_not_accept_list(self):
616616
self.image.load_catalog(tab, catalog_label='test2', use_skycoord=False)
617617

618618
with pytest.raises(
619-
ValueError,
619+
TypeError,
620620
match='Cannot remove multiple catalogs from a list'
621621
):
622622
self.image.remove_catalog(catalog_label=['test1', 'test2'])
@@ -646,7 +646,7 @@ def test_adding_catalog_as_world(self, data, wcs):
646646
def test_stretch(self):
647647
original_stretch = self.image.get_stretch()
648648

649-
with pytest.raises(ValueError, match=r'Stretch.*not valid.*'):
649+
with pytest.raises(TypeError, match=r'Stretch.*not valid.*'):
650650
self.image.set_stretch('not a valid value')
651651

652652
# A bad value should leave the stretch unchanged
@@ -658,10 +658,10 @@ def test_stretch(self):
658658
assert isinstance(self.image.get_stretch(), LogStretch)
659659

660660
def test_cuts(self, data):
661-
with pytest.raises(ValueError, match='[mM]ust be'):
661+
with pytest.raises(TypeError, match='[mM]ust be'):
662662
self.image.set_cuts('not a valid value')
663663

664-
with pytest.raises(ValueError, match='[mM]ust be'):
664+
with pytest.raises(TypeError, match='[mM]ust be'):
665665
self.image.set_cuts((1, 10, 100))
666666

667667
# Setting using histogram requires data

0 commit comments

Comments
 (0)