11import logging
22
33import numpy
4- import numbers
4+ from numbers import Real
55from math import degrees , sqrt , sin , pi , cos
66from dataclasses import dataclass , field
77from sourcefinder .utility .coordinates import WCS
88from sourcefinder .config import ImgConf
9- from typing import Optional
9+ from typing import Optional , cast
1010
1111logger = logging .getLogger (__name__ )
1212
@@ -84,18 +84,25 @@ class DataAccessor:
8484
8585 def __post_init__ (self ):
8686 if self .conf is not None :
87- bmaj , bmin , bpa = self .conf .bmaj , self .conf .bmin , self .conf .bpa
88- if all (isinstance (x , numbers .Real ) and x is not None for x in
89- (bmaj , bmin , bpa )):
87+ beam_tuple = (self .conf .bmaj , self .conf .bmin , self .conf .bpa )
88+ if self ._is_valid_beam_tuple (beam_tuple ):
9089 deltax , deltay = self .pixelsize
91- self .beam = DataAccessor .degrees2pixels (bmaj , bmin , bpa ,
90+ self .beam = DataAccessor .degrees2pixels (* beam_tuple ,
9291 deltax , deltay )
9392 else :
9493 print (("WARNING: Partial beam specification ignored; "
9594 "one or more of (bmaj, bmin, bpa) are not "
9695 "specified." ))
9796 self .beam = None
9897
98+ @staticmethod
99+ def _is_valid_beam_tuple (b ) -> bool :
100+ return (
101+ isinstance (b , tuple )
102+ and len (b ) == 3
103+ and all (isinstance (x , Real ) and x is not None for x in b )
104+ )
105+
99106 def extract_metadata (self ) -> dict :
100107 """
101108 Massage the class attributes into a flat dictionary with
@@ -124,16 +131,18 @@ def extract_metadata(self) -> dict:
124131 'deltay' : self .pixelsize [1 ],
125132 }
126133
127- if self .beam is not None :
134+
135+ if self ._is_valid_beam_tuple (self .beam ):
136+ beam = cast (tuple [float , float , float ], self .beam )
128137 metadata .update ({
129- 'beam_smaj_pix' : self . beam [0 ],
130- 'beam_smin_pix' : self . beam [1 ],
131- 'beam_pa_rad' : self . beam [2 ],
138+ 'beam_smaj_pix' : beam [0 ],
139+ 'beam_smin_pix' : beam [1 ],
140+ 'beam_pa_rad' : beam [2 ],
132141 })
133142
134143 return metadata
135144
136- def parse_pixelsize (self ):
145+ def parse_pixelsize (self ) -> tuple [ float , float ] :
137146 """
138147 Returns
139148 -------
@@ -165,7 +174,8 @@ def parse_pixelsize(self):
165174 return deltax , deltay
166175
167176 @staticmethod
168- def degrees2pixels (bmaj , bmin , bpa , deltax , deltay ):
177+ def degrees2pixels (bmaj , bmin , bpa , deltax , deltay ) -> (
178+ tuple )[float , float , float ]:
169179 """
170180 Convert beam in degrees to beam in pixels and radians.
171181 For example, FITS beam parameters are in degrees.
@@ -185,12 +195,14 @@ def degrees2pixels(bmaj, bmin, bpa, deltax, deltay):
185195
186196 Returns
187197 -------
188- semimaj : float
189- Beam semi-major axis in pixels.
190- semimin : float
191- Beam semi-minor axis in pixels.
192- theta : float
193- Beam position angle in radians.
198+ tuple
199+ A tuple containing:
200+ - semimaj : float
201+ Beam semi-major axis in pixels.
202+ - semimin : float
203+ Beam semi-minor axis in pixels.
204+ - theta : float
205+ Beam position angle in radians.
194206 """
195207 theta = pi * bpa / 180
196208 semimaj = (bmaj / 2. ) * (sqrt (
0 commit comments