diff --git a/astropy/coordinates/angle_utilities.py b/astropy/coordinates/angle_utilities.py index ce3e478..2a7a9b6 100644 --- a/astropy/coordinates/angle_utilities.py +++ b/astropy/coordinates/angle_utilities.py @@ -149,21 +149,21 @@ def p_ufloat(p): def p_colon(p): ''' - colon : sign UINT COLON UINT + colon : sign UINT COLON ufloat | sign UINT COLON UINT COLON ufloat ''' if len(p) == 5: - p[0] = (p[1] * p[2], p[4], 0.0) + p[0] = (p[1] * p[2], p[4]) elif len(p) == 7: p[0] = (p[1] * p[2], p[4], p[6]) def p_spaced(p): ''' - spaced : sign UINT UINT + spaced : sign UINT ufloat | sign UINT UINT ufloat ''' if len(p) == 4: - p[0] = (p[1] * p[2], p[3], 0.0) + p[0] = (p[1] * p[2], p[3]) elif len(p) == 5: p[0] = (p[1] * p[2], p[3], p[4]) @@ -182,8 +182,9 @@ def p_generic(p): def p_hms(p): ''' hms : sign UINT HOUR - | sign UINT HOUR UINT + | sign UINT HOUR ufloat | sign UINT HOUR UINT MINUTE + | sign UINT HOUR UFLOAT MINUTE | sign UINT HOUR UINT MINUTE ufloat | sign UINT HOUR UINT MINUTE ufloat SECOND | generic HOUR @@ -193,15 +194,16 @@ def p_hms(p): elif len(p) == 4: p[0] = (p[1] * p[2], u.hourangle) elif len(p) in (5, 6): - p[0] = ((p[1] * p[2], p[4], 0.0), u.hourangle) + p[0] = ((p[1] * p[2], p[4]), u.hourangle) elif len(p) in (7, 8): p[0] = ((p[1] * p[2], p[4], p[6]), u.hourangle) def p_dms(p): ''' dms : sign UINT DEGREE - | sign UINT DEGREE UINT + | sign UINT DEGREE ufloat | sign UINT DEGREE UINT MINUTE + | sign UINT DEGREE UFLOAT MINUTE | sign UINT DEGREE UINT MINUTE ufloat | sign UINT DEGREE UINT MINUTE ufloat SECOND | generic DEGREE @@ -211,7 +213,7 @@ def p_dms(p): elif len(p) == 4: p[0] = (p[1] * p[2], u.degree) elif len(p) in (5, 6): - p[0] = ((p[1] * p[2], p[4], 0.0), u.degree) + p[0] = ((p[1] * p[2], p[4]), u.degree) elif len(p) in (7, 8): p[0] = ((p[1] * p[2], p[4], p[6]), u.degree) @@ -297,6 +299,8 @@ def _check_second_range(sec): """ if np.any(sec == 60.): warn(IllegalSecondWarning(sec, 'Treating as 0 sec, +1 min')) + elif sec is None: + pass elif np.any(sec < -60.) or np.any(sec > 60.): # "Error: seconds not in range [-60,60) ({0}).".format(sec)) raise IllegalSecondError(sec) @@ -361,7 +365,7 @@ def degrees_to_dms(d): return np.floor(sign * d), sign * np.floor(m), sign * s -def dms_to_degrees(d, m, s): +def dms_to_degrees(d, m, s=None): """ Convert degrees, arcminute, arcsecond to a float degrees value. """ @@ -372,13 +376,14 @@ def dms_to_degrees(d, m, s): # determine sign sign = np.copysign(1.0, d) - # TODO: This will fail if d or m have values after the decimal - # place - try: - d = np.floor(np.abs(np.asarray(d))) - m = np.floor(np.abs(np.asarray(m))) - s = np.abs(s) + d = np.floor(np.abs(d)) + if s is None: + m = np.abs(m) + s = 0 + else: + m = np.floor(np.abs(m)) + s = np.abs(s) except ValueError: raise ValueError(format_exception( "{func}: dms values ({1[0]},{2[1]},{3[2]}) could not be " @@ -387,7 +392,7 @@ def dms_to_degrees(d, m, s): return sign * (d + m / 60. + s / 3600.) -def hms_to_hours(h, m, s): +def hms_to_hours(h, m, s=None): """ Convert hour, minute, second to a float hour value. """ @@ -397,13 +402,14 @@ def hms_to_hours(h, m, s): # determine sign sign = np.copysign(1.0, h) - # TODO: This will fail if d or m have values after the decimal - # place - try: h = np.floor(np.abs(h)) - m = np.floor(np.abs(m)) - s = np.abs(s) + if s is None: + m = np.abs(m) + s = 0 + else: + m = np.floor(np.abs(m)) + s = np.abs(s) except ValueError: raise ValueError(format_exception( "{func}: HMS values ({1[0]},{2[1]},{3[2]}) could not be " diff --git a/astropy/coordinates/angles.py b/astropy/coordinates/angles.py index 72353c3..08353eb 100644 --- a/astropy/coordinates/angles.py +++ b/astropy/coordinates/angles.py @@ -137,13 +137,12 @@ def __new__(cls, angle, unit=None, dtype=None, copy=True): @staticmethod def _tuple_to_float(angle, unit): """ - Converts an angle represented as a 3-tuple into a floating + Converts an angle represented as a 3-tuple or 2-tuple into a floating point number in the given unit. """ if isinstance(angle, tuple): # TODO: Numpy array of tuples? if unit is u.hourangle: - util.check_hms_ranges(*angle) angle = util.hms_to_hours(*angle) elif unit is u.degree: angle = util.dms_to_degrees(*angle) diff --git a/astropy/coordinates/sky_coordinate.py b/astropy/coordinates/sky_coordinate.py index 94960b9..f3308ec 100644 --- a/astropy/coordinates/sky_coordinate.py +++ b/astropy/coordinates/sky_coordinate.py @@ -3,6 +3,7 @@ import collections import numpy as np +import re from ..utils.compat.misc import override__dir__ from ..extern import six @@ -18,6 +19,9 @@ __all__ = ['SkyCoord'] +PMRE = re.compile(r'(\+|\-)') +JPMRE = re.compile(r'J([0-9]{6}\.?[0-9]{0,2})([\+\-][0-9]{6}\.?[0-9]{0,2})\s*$') + # Define a convenience mapping. This is used like a module constants # but is actually dynamically evaluated. @@ -915,8 +919,21 @@ def _parse_coordinate_arg(coords, frame, units): if isinstance(coord, six.string_types): coord1 = coord.split() if len(coord1) == 6: - coord1 = (' '.join(coord1[:3]), ' '.join(coord1[3:])) - coord = coord1 + coord = (' '.join(coord1[:3]), ' '.join(coord1[3:])) + elif len(coord1) > 2: + coord = PMRE.split(coord) + coord = (coord[0], ' '.join(coord[1:])) + elif len(coord1) == 1: + try: + coord = JPMRE.match(coord).groups() + coord = ('{0} {1} {2}'. + format(coord[0][0:2], coord[0][2:4], coord[0][4:]), + '{0} {1} {2}'. + format(coord[1][0:3], coord[1][3:5], coord[1][5:])) + except: + coord = coord1 + else: + coord = coord1 vals.append(coord) # This assumes coord is a sequence at this point diff --git a/astropy/coordinates/tests/test_sky_coord.py b/astropy/coordinates/tests/test_sky_coord.py index aa5a1e8..63b255c 100644 --- a/astropy/coordinates/tests/test_sky_coord.py +++ b/astropy/coordinates/tests/test_sky_coord.py @@ -132,9 +132,25 @@ def test_coord_init_string(): assert allclose(sc1.ra, Angle(120 * u.deg)) assert allclose(sc1.dec, Angle(5 * u.deg)) - with pytest.raises(ValueError) as err: - SkyCoord('8 00 -5 00 00.0', unit=(u.hour, u.deg), frame='icrs') - assert 'coordinates have 5 values but spherical representation only accepts 3' in str(err) + sc2 = SkyCoord('8 00 -5 00 00.0', unit=(u.hour, u.deg), frame='icrs') + assert isinstance(sc2, SkyCoord) + assert allclose(sc2.ra, Angle(120 * u.deg)) + assert allclose(sc2.dec, Angle(-5 * u.deg)) + + sc3 = SkyCoord('8 00 -5 00.6', unit=(u.hour, u.deg), frame='icrs') + assert isinstance(sc3, SkyCoord) + assert allclose(sc3.ra, Angle(120 * u.deg)) + assert allclose(sc3.dec, Angle(-5.01 * u.deg)) + + sc4 = SkyCoord('J080000.0-050036.0', unit=(u.hour, u.deg), frame='icrs') + assert isinstance(sc4, SkyCoord) + assert allclose(sc4.ra, Angle(120 * u.deg)) + assert allclose(sc4.dec, Angle(-5.01 * u.deg)) + + sc5 = SkyCoord('8h 00.6m -5d 00.6m', unit=(u.hour, u.deg), frame='icrs') + assert isinstance(sc5, SkyCoord) + assert allclose(sc5.ra, Angle(120.15 * u.deg)) + assert allclose(sc5.dec, Angle(-5.01 * u.deg)) def test_coord_init_unit():