Repository: sunpy/sunpy

Issue:
Creating a HeliographicStonyhurst frame with SkyCoord does not always return a 3D frame
### Description
```python
from astropy.coordinates import SkyCoord
import astropy.units as u
from sunpy.coordinates import frames

SkyCoord([1,2,3,4], [1,3,4,5], unit=u.deg, frame=frames.HeliographicStonyhurst(obstime="2011-06-07T06:32:11.000"))
```
### Expected behaviour
The returned frame should be 3D with the rsun value as the distance coordinate.

### Actual behaviour

The frame is has a `UnitSpherical` representation:
```
<SkyCoord (HeliographicStonyhurst: obstime=2011-06-07T06:32:11.000): (lon, lat) in deg
    [(1., 1.), (2., 3.), (3., 4.), (4., 5.)]>
```



Discussion:
Ok, so... one MWE and a pdb session later:
```
226  ->	        if not _rep_kwarg:
227  	            if isinstance(self._data, UnitSphericalRepresentation):
228  	                self._data = self.spherical
(Pdb) args
self = <HeliographicStonyhurst Coordinate (obstime=2011-06-07T06:32:11.000): (lon, lat) in deg
    [(1., 1.), (2., 3.), (3., 4.), (4., 5.)]>
args = ()
kwargs = {'copy': True, 'obstime': <Time object: scale='utc' format='isot' value=2011-06-07T06:32:11.000>, 'representation_type': <class 'astropy.coordinates.representation.SphericalRepresentation'>, 'lon': <Longitude [1., 2., 3., 4.] deg>, 'lat': <Latitude [1., 3., 4., 5.] deg>}
(Pdb) self._data
<UnitSphericalRepresentation (lon, lat) in deg
    [(1., 1.), (2., 3.), (3., 4.), (4., 5.)]>
(Pdb) self.spherical
<SphericalRepresentation (lon, lat, distance) in (deg, deg, km)
    [(1., 1., 695700.), (2., 3., 695700.), (3., 4., 695700.),
     (4., 5., 695700.)]>
```

It appears that in this situation, `SkyCoord` initializes the `HeliogrphicStonyhurst` frame with `lon`, `lat` and a `representation_type` of `SphericalRepresentation` although the `self._data` is `UnitSphericalRepresentation`. So I *think* the best fix here is to modify our `if _rep_kwarg` line to detect `representation_type=SphericalRepresentation` and then still call out to `self.spherical` in that case.

Resolving patch:
diff --git a/sunpy/coordinates/frames.py b/sunpy/coordinates/frames.py
--- a/sunpy/coordinates/frames.py
+++ b/sunpy/coordinates/frames.py
@@ -221,21 +221,10 @@ def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
 
         # Make 3D if specified as 2D
-        # If representation was explicitly passed, do not change the rep.
-        if not _rep_kwarg:
-            if isinstance(self._data, UnitSphericalRepresentation):
-                self._data = self.spherical
+        if (self._data is not None and self._data.norm().unit is u.one
+            and u.allclose(self._data.norm(), 1*u.one)):
 
-    def represent_as(self, base, s='base', in_frame_units=False):
-        """
-        Unless the requested representation is UnitSphericalRepresentation, scale a coordinate with
-        dimensionless length so that it has the length of the solar radius.
-        """
-        data = super().represent_as(base, s, in_frame_units=in_frame_units)
-        if not isinstance(data, UnitSphericalRepresentation) and \
-           data.norm().unit is u.one and u.allclose(data.norm(), 1*u.one):
-            data *= _RSUN.to(u.km)
-        return data
+            self._data *= _RSUN.to(u.km)
 
 
 @add_common_docstring(**_frame_parameters())


Test patch:
diff --git a/sunpy/coordinates/tests/test_frames.py b/sunpy/coordinates/tests/test_frames.py
--- a/sunpy/coordinates/tests/test_frames.py
+++ b/sunpy/coordinates/tests/test_frames.py
@@ -40,11 +40,9 @@ def init_frame(frame, args, kwargs):
 two_D_parameters = [
     ([0 * u.deg, 0 * u.arcsec], None),
     ([0 * u.deg, 0 * u.arcsec], {'obstime': '2011/01/01T00:00:00'}),
-    ([0 * u.deg, 0 * u.arcsec], {'representation_type': 'unitspherical'}),
     ([UnitSphericalRepresentation(0 * u.deg, 0 * u.arcsec)], None),
-    ([UnitSphericalRepresentation(0 * u.deg, 0 * u.arcsec)], None), (
-        [UnitSphericalRepresentation(0 * u.deg, 0 * u.arcsec)],
-        {'obstime': '2011/01/01T00:00:00'})
+    ([UnitSphericalRepresentation(0 * u.deg, 0 * u.arcsec)], {'obstime': '2011/01/01T00:00:00'}),
+    ([0 * u.deg, 0 * u.arcsec], {'representation_type': 'unitspherical'})
 ]
 """
 These are common 3D params, kwargs are frame specific
@@ -238,7 +236,7 @@ def test_HEE_creation():
 
 @pytest.mark.parametrize('frame',
                          [HeliographicStonyhurst, HeliographicCarrington])
-@pytest.mark.parametrize("args, kwargs", two_D_parameters[:2] + two_D_parameters[4:] +
+@pytest.mark.parametrize("args, kwargs", two_D_parameters[:4] +
                          [(None, {'lat': 0*u.deg, 'lon': 0*u.arcsec})])
 def test_create_hgs_2d(frame, args, kwargs):
     hgs1 = init_frame(frame, args, kwargs)
@@ -265,7 +263,7 @@ def test_create_hgs_2d(frame, args, kwargs):
 
 @pytest.mark.parametrize('frame',
                          [HeliographicStonyhurst, HeliographicCarrington])
-@pytest.mark.parametrize("args, kwargs", two_D_parameters[2:4])
+@pytest.mark.parametrize("args, kwargs", two_D_parameters[4:])
 def test_create_hgs_force_2d(frame, args, kwargs):
     hgs1 = init_frame(frame, args, kwargs)
 
@@ -274,8 +272,7 @@ def test_create_hgs_force_2d(frame, args, kwargs):
 
     rep_kwarg = kwargs.get('representation_type', None) if kwargs else None
 
-    if rep_kwarg == 'unitspherical':
-        assert isinstance(hgs1._data, UnitSphericalRepresentation)
+    assert not hasattr(hgs1, 'radius')
 
     # Check the attrs are correct
     assert hgs1.lon == 0 * u.deg
@@ -394,6 +391,8 @@ def test_hcc_default_observer():
 
 two_D_parameters = [
     ([0 * u.deg, 0 * u.arcsec], {}),
+    ([[0, 1, 2, 3], [5, 6, 7, 8]], {'unit': u.deg}),
+    ([0 * u.deg, 0 * u.arcsec], {'representation_type': SphericalRepresentation}),
     ([UnitSphericalRepresentation(0 * u.deg, 0 * u.arcsec)], {}),
     ([UnitSphericalRepresentation(0 * u.deg, 0 * u.arcsec)], {}),
     ([SphericalRepresentation(0 * u.deg, 0 * u.arcsec, 1*u.one)], {}),
@@ -419,7 +418,7 @@ def test_skycoord_hpc(args, kwargs):
 @pytest.mark.parametrize("args, kwargs", two_D_parameters)
 def test_skycoord_hgs(args, kwargs):
     """
-    Test that when instantiating a HPC frame with SkyCoord correctly replaces
+    Test that when instantiating a HGS frame with SkyCoord correctly replaces
     distance.
 
     Note: We only need to test HGS here not HGC as they share the same
@@ -427,6 +426,9 @@ def test_skycoord_hgs(args, kwargs):
     """
 
     RSUN_METERS = sun.constants.get('radius').si
-    sc = SkyCoord(*args, **kwargs, frame="heliographic_stonyhurst", obstime="2011-01-01T00:00:00")
+    sc = SkyCoord(*args, **kwargs, frame=HeliographicStonyhurst(obstime="2011-01-01T00:00:00"))
 
+    # Check that we have upgraded the data to Spherical
+    assert isinstance(sc.frame._data, SphericalRepresentation)
+    # Check the value is correct
     assert_quantity_allclose(sc.radius, RSUN_METERS)