@@ -53,19 +53,27 @@ class ViewportInfo:
5353 data : ArrayLike | NDData | CCDData | None = None
5454
5555
56+ def docs_from_interface (cls ):
57+ """
58+ Decorator to copy the docstrings from the interface methods to the
59+ methods in the class.
60+ """
61+ for name , method in cls .__dict__ .items ():
62+ if not name .startswith ("_" ):
63+ interface_method = getattr (ImageViewerInterface , name , None )
64+ if interface_method :
65+ method .__doc__ = interface_method .__doc__
66+ return cls
67+
68+
5669@dataclass
70+ @docs_from_interface
5771class ImageViewerLogic :
5872 """
5973 This viewer does not do anything except making changes to its internal
6074 state to simulate the behavior of a real viewer.
6175 """
6276
63- # These are attributes, not methods. The type annotations are there
64- # to make sure Protocol knows they are attributes. Python does not
65- # do any checking at all of these types.
66- image_width : int = 0
67- image_height : int = 0
68- zoom_level : float = 1
6977 _cuts : BaseInterval | tuple [float , float ] = AsymmetricPercentileInterval (
7078 upper_percentile = 95
7179 )
@@ -206,8 +214,6 @@ def set_colormap(
206214 )
207215 self ._images [image_label ].colormap = map_name
208216
209- set_colormap .__doc__ = ImageViewerInterface .set_colormap .__doc__
210-
211217 def get_colormap (
212218 self ,
213219 image_label : str | None = None ,
@@ -220,28 +226,13 @@ def get_colormap(
220226 )
221227 return self ._images [image_label ].colormap
222228
223- get_colormap .__doc__ = ImageViewerInterface .get_colormap .__doc__
224-
225229 # The methods, grouped loosely by purpose
226230
227231 def get_catalog_style (
228232 self ,
229233 catalog_label = None ,
230234 ** kwargs , # noqa: ARG002
231235 ) -> dict [str , Any ]:
232- """
233- Get the style for the catalog.
234-
235- Parameters
236- ----------
237- catalog_label : str, optional
238- The label of the catalog. Default is ``None``.
239-
240- Returns
241- -------
242- dict
243- The style for the catalog.
244- """
245236 catalog_label = self ._resolve_catalog_label (catalog_label )
246237
247238 style = self ._catalogs [catalog_label ].style .copy ()
@@ -256,22 +247,6 @@ def set_catalog_style(
256247 size : float = 5 ,
257248 ** kwargs ,
258249 ) -> None :
259- """
260- Set the style for the catalog.
261-
262- Parameters
263- ----------
264- catalog_label : str, optional
265- The label of the catalog.
266- shape : str, optional
267- The shape of the markers.
268- color : str, optional
269- The color of the markers.
270- size : float, optional
271- The size of the markers.
272- **kwargs
273- Additional keyword arguments to pass to the marker style.
274- """
275250 catalog_label = self ._resolve_catalog_label (catalog_label )
276251
277252 if self ._catalogs [catalog_label ].data is None :
@@ -324,18 +299,6 @@ def load_image(
324299 image_label : str | None = None ,
325300 ** kwargs , # noqa: ARG002
326301 ) -> None :
327- """
328- Load a FITS file into the viewer.
329-
330- Parameters
331- ----------
332- file : str or array-like
333- The FITS file to load. If a string, it can be a URL or a
334- file path.
335-
336- image_label : str, optional
337- A label for the image.
338- """
339302 image_label = self ._resolve_image_label (image_label )
340303
341304 # Delete the current viewport if it exists
@@ -375,8 +338,6 @@ def get_image(
375338 def image_labels (self ) -> tuple [str , ...]:
376339 return tuple (k for k in self ._images .keys () if k is not None )
377340
378- image_labels .__doc__ = ImageViewerInterface .image_labels .__doc__
379-
380341 def _determine_largest_dimension (self , shape : tuple [int , int ]) -> int :
381342 """
382343 Determine which index is the largest dimension.
@@ -497,19 +458,6 @@ def save(
497458 overwrite : bool = False ,
498459 ** kwargs , # noqa: ARG002
499460 ) -> None :
500- """
501- Save the current view to a file.
502-
503- Parameters
504- ----------
505- filename : str or `os.PathLike`
506- The file to save to. The format is determined by the
507- extension.
508-
509- overwrite : bool, optional
510- If `True`, overwrite the file if it exists. Default is
511- `False`.
512- """
513461 p = Path (filename )
514462 if p .exists () and not overwrite :
515463 raise FileExistsError (
@@ -586,8 +534,6 @@ def load_catalog(
586534
587535 self ._catalogs [catalog_label ].style = catalog_style
588536
589- load_catalog .__doc__ = ImageViewerInterface .load_catalog .__doc__
590-
591537 def remove_catalog (
592538 self ,
593539 catalog_label : str | None = None ,
@@ -645,14 +591,10 @@ def get_catalog(
645591
646592 return result
647593
648- get_catalog .__doc__ = ImageViewerInterface .get_catalog .__doc__
649-
650594 @property
651595 def catalog_names (self ) -> tuple [str , ...]:
652596 return tuple (self ._user_catalog_labels ())
653597
654- catalog_names .__doc__ = ImageViewerInterface .catalog_names .__doc__
655-
656598 # Methods that modify the view
657599 def set_viewport (
658600 self ,
@@ -728,8 +670,6 @@ def set_viewport(
728670 self ._images [image_label ].center = center
729671 self ._images [image_label ].fov = fov
730672
731- set_viewport .__doc__ = ImageViewerInterface .set_viewport .__doc__
732-
733673 def get_viewport (
734674 self ,
735675 sky_or_pixel : str | None = None ,
@@ -805,5 +745,3 @@ def get_viewport(
805745 fov = viewport .fov
806746
807747 return dict (center = center , fov = fov , image_label = image_label )
808-
809- get_viewport .__doc__ = ImageViewerInterface .get_viewport .__doc__
0 commit comments