def _set_axis_physical_types(self, pht=None): """ Set the physical type of the coordinate axes using VO UCD1+ v1.23 definitions. """ if pht is not None: if isinstance(pht, str): pht = (pht,) elif not isiterable(pht): raise TypeError("axis_physical_types must be of type string or iterable of strings") if len(pht) != self.naxes: raise ValueError('"axis_physical_types" must be of length {}'.format(self.naxes)) ph_type = [] for axt in pht: if axt not in VALID_UCDS and not axt.startswith("custom:"): ph_type.append("custom:{}".format(axt)) else: ph_type.append(axt) validate_physical_types(ph_type) return tuple(ph_type) if isinstance(self, CelestialFrame): if isinstance(self.reference_frame, coord.Galactic): ph_type = "pos.galactic.lon", "pos.galactic.lat" elif isinstance(self.reference_frame, (coord.GeocentricTrueEcliptic, coord.GCRS, coord.PrecessedGeocentric)): ph_type = "pos.bodyrc.lon", "pos.bodyrc.lat" elif isinstance(self.reference_frame, coord.builtin_frames.BaseRADecFrame): ph_type = "pos.eq.ra", "pos.eq.dec" elif isinstance(self.reference_frame, coord.builtin_frames.BaseEclipticFrame): ph_type = "pos.ecliptic.lon", "pos.ecliptic.lat" else: ph_type = tuple("custom:{}".format(t) for t in self.axes_names) elif isinstance(self, SpectralFrame): if self.unit[0].physical_type == "frequency": ph_type = ("em.freq",) elif self.unit[0].physical_type == "length": ph_type = ("em.wl",) elif self.unit[0].physical_type == "energy": ph_type = ("em.energy",) else: ph_type = ("custom:{}".format(self.unit[0].physical_type),) elif isinstance(self, TemporalFrame): ph_type = ("time",) elif isinstance(self, Frame2D): if all(self.axes_names): ph_type = self.axes_names else: ph_type = self.axes_type ph_type = tuple("custom:{}".format(t) for t in ph_type) else: ph_type = tuple("custom:{}".format(t) for t in self.axes_type) validate_physical_types(ph_type) return ph_type
def validate_physical_types(physical_types): """ Validate a list of physical types against the UCD1+ standard """ try: low_level_api.validate_physical_types(physical_types) except ValueError as e: invalid_type = str(e).split(':')[1].strip() raise ValueError( f"'{invalid_type}' is not a valid IOVA UCD1+ physical type. " "It must be a string specified in the list (http://www.ivoa.net/documents/latest/UCDlist.html) " "or if no matching type exists it can be any string prepended with 'custom:'." )
def test_validate_physical_types(): # Check valid cases validate_physical_types(['pos.eq.ra', 'pos.eq.ra']) validate_physical_types(['spect.dopplerVeloc.radio', 'custom:spam']) validate_physical_types(['time', None]) # Make sure validation is case sensitive with raises(ValueError, match=r"'Pos\.eq\.dec' is not a valid IOVA UCD1\+ physical type"): validate_physical_types(['pos.eq.ra', 'Pos.eq.dec']) # Make sure nonsense types are picked up with raises(ValueError, match=r"'spam' is not a valid IOVA UCD1\+ physical type"): validate_physical_types(['spam'])
def test_validate_physical_types(): # Check valid cases validate_physical_types(['pos.eq.ra', 'pos.eq.ra']) validate_physical_types(['spect.dopplerVeloc.radio', 'custom:spam']) validate_physical_types(['time', None]) # Make sure validation is case sensitive with raises(ValueError) as exc: validate_physical_types(['pos.eq.ra', 'Pos.eq.dec']) assert exc.value.args[0] == 'Invalid physical type: Pos.eq.dec' # Make sure nonsense types are picked up with raises(ValueError) as exc: validate_physical_types(['spam']) assert exc.value.args[0] == 'Invalid physical type: spam'