We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Support the use of SunPyBaseCoordinateFrame outside of core library
### Describe the feature

* It would be useful to be able to use `SunPyBaseCoordinateFrame` outside of sunpy but currently doing so is alkward as the `frame_to_wcs` and `wcs_to_frame` mappings are hardcode to the current frames / wcs' and raise an error you you try to do so
* The name clearly implies this is SunPy specific but there a lot of boiler plate code that would have to be copied to provide the same thing.

At the moment to make this work you have to make sure what ever frames are added are added before the sunpy function e.g.

`astropy.wcs.utils.FRAME_WCS_MAPPINGS.insert(1, [my_wcs_to_frame])`

### Proposed solution

Don't raise an error the if the frame is a subclass of `SunPyBaseCoordinateFrame` but not one of the frame implemented in sunpy return `None` 

Specifically L198 raise an error as xcoord and xcoord are undefined
https://github.com/sunpy/sunpy/blob/2281a2198997e8671efd48dcb531b07a98b86ddf/sunpy/coordinates/wcs_utils.py#L173-L198

A simple solution would be to an a final else clause to this if Elias
```python
        elif isinstance(frame, HeliographicStonyhurst):
            xcoord = 'HGLN' + '-' + projection
            ycoord = 'HGLT' + '-' + projection
            wcs.wcs.cunit = ['deg', 'deg']
        else
            return None

```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `sunpy/coordinates/wcs_utils.py`
Content:
```
1 
2 import astropy.units as u
3 import astropy.wcs.utils
4 from astropy.coordinates import BaseCoordinateFrame, SkyCoord
5 from astropy.wcs import WCS
6 from astropy.wcs.utils import obsgeo_to_frame
7 
8 from sunpy import log
9 from .frames import (
10     Heliocentric,
11     HeliographicCarrington,
12     HeliographicStonyhurst,
13     Helioprojective,
14     SunPyBaseCoordinateFrame,
15 )
16 
17 __all__ = ['solar_wcs_frame_mapping', 'solar_frame_to_wcs_mapping']
18 
19 
20 def solar_wcs_frame_mapping(wcs):
21     """
22     This function registers the coordinates frames to their FITS-WCS coordinate
23     type values in the `astropy.wcs.utils.wcs_to_celestial_frame` registry.
24 
25     Parameters
26     ----------
27     wcs : astropy.wcs.WCS
28 
29     Returns
30     -------
31     astropy.coordinates.BaseCoordinateFrame
32     """
33 
34     if hasattr(wcs, "coordinate_frame"):
35         return wcs.coordinate_frame
36 
37     dateobs = wcs.wcs.dateavg or wcs.wcs.dateobs or None
38 
39     # Get observer coordinate from the WCS auxiliary information
40     # Note: the order of the entries is important, as it determines which set
41     # of header keys is given priority below. Stonyhurst should usually be
42     # prioritized, as it is defined more consistently across implementations,
43     # and so it should occur before Carrington here.
44     required_attrs = {HeliographicStonyhurst: ['hgln_obs', 'hglt_obs', 'dsun_obs'],
45                       HeliographicCarrington: ['crln_obs', 'hglt_obs', 'dsun_obs']}
46 
47     # Get rsun from the WCS auxiliary information
48     rsun = wcs.wcs.aux.rsun_ref
49     if rsun is not None:
50         rsun *= u.m
51 
52     # TODO: remove these errors in sunpy 4.1
53     bad_attrs = [f'.{attr}' for attr in ['rsun', 'heliographic_observer']
54                  if hasattr(wcs, attr)]
55     if len(bad_attrs):
56         raise ValueError(f"The {' and '.join(bad_attrs)} attribute(s) on a WCS "
57                          "are no longer supported.")
58 
59     observer = None
60     for frame, attr_names in required_attrs.items():
61         attrs = [getattr(wcs.wcs.aux, attr_name) for attr_name in attr_names]
62         if all([attr is not None for attr in attrs]):
63             kwargs = {'obstime': dateobs}
64             if rsun is not None:
65                 kwargs['rsun'] = rsun
66             if issubclass(frame, HeliographicCarrington):
67                 kwargs['observer'] = 'self'
68 
69             observer = frame(attrs[0] * u.deg,
70                              attrs[1] * u.deg,
71                              attrs[2] * u.m,
72                              **kwargs)
73             break
74 
75     # Read the observer out of obsgeo for ground based observers
76     if observer is None:
77         try:
78             observer = obsgeo_to_frame(wcs.wcs.obsgeo, dateobs)
79             observer = SkyCoord(observer, rsun=rsun)
80         except ValueError as e:
81             # The helper function assumes you know the obsgeo coords you are
82             # parsing are good, we are not sure, so catch the error.
83 
84             # This approach could lead to an invalid observer (i.e. one of the
85             # coords being NaN), but only if the WCS has been constructed like that.
86             log.debug(f"Could not parse obsgeo coordinates from WCS:\n{e}")
87 
88     # Collect all of the possible frame attributes, although some may be removed later
89     frame_args = {'obstime': dateobs}
90     if observer is not None:
91         frame_args['observer'] = observer
92     if rsun is not None:
93         frame_args['rsun'] = rsun
94 
95     frame_class = _sunpy_frame_class_from_ctypes(wcs.wcs.ctype)
96 
97     if frame_class:
98         if frame_class == HeliographicStonyhurst:
99             frame_args.pop('observer', None)
100         if frame_class == Heliocentric:
101             frame_args.pop('rsun', None)
102 
103         return frame_class(**frame_args)
104 
105 
106 def _sunpy_frame_class_from_ctypes(ctypes):
107     # Truncate the ctype to the first four letters
108     ctypes = {c[:4] for c in ctypes}
109 
110     mapping = {
111         Helioprojective: {'HPLN', 'HPLT'},
112         HeliographicStonyhurst: {'HGLN', 'HGLT'},
113         HeliographicCarrington: {'CRLN', 'CRLT'},
114         Heliocentric: {'SOLX', 'SOLY'},
115     }
116 
117     for frame_class, ctype_pair in mapping.items():
118         if ctype_pair <= ctypes:
119             return frame_class
120 
121 
122 def _set_wcs_aux_obs_coord(wcs, obs_frame):
123     """
124     Set (in-place) observer coordinate information on a WCS.
125 
126     Parameters
127     ----------
128     wcs : astropy.wcs.WCS
129     obs_frame : astropy.coordinates.SkyCoord, astropy.coordinates.CoordinateFrame
130     """
131     # Sometimes obs_coord can be a SkyCoord, so convert down to a frame
132     if hasattr(obs_frame, 'frame'):
133         obs_frame = obs_frame.frame
134 
135     if isinstance(obs_frame, HeliographicStonyhurst):
136         wcs.wcs.aux.hgln_obs = obs_frame.lon.to_value(u.deg)
137     elif isinstance(obs_frame, HeliographicCarrington):
138         wcs.wcs.aux.crln_obs = obs_frame.lon.to_value(u.deg)
139     else:
140         raise ValueError('obs_coord must be in a Stonyhurst or Carrington frame')
141     # These two keywords are the same for Carrington and Stonyhurst
142     wcs.wcs.aux.hglt_obs = obs_frame.lat.to_value(u.deg)
143     wcs.wcs.aux.dsun_obs = obs_frame.radius.to_value(u.m)
144 
145 
146 def solar_frame_to_wcs_mapping(frame, projection='TAN'):
147     """
148     For a given frame, this function returns the corresponding WCS object.
149     It registers the WCS coordinates types from their associated frame in the
150     `astropy.wcs.utils.celestial_frame_to_wcs` registry.
151 
152     Parameters
153     ----------
154     frame : astropy.coordinates.BaseCoordinateFrame
155     projection : str, optional
156 
157     Returns
158     -------
159     astropy.wcs.WCS
160     """
161     wcs = WCS(naxis=2)
162 
163     if hasattr(frame, 'rsun'):
164         wcs.wcs.aux.rsun_ref = frame.rsun.to_value(u.m)
165 
166     if hasattr(frame, 'observer') and frame.observer is not None:
167         if isinstance(frame.observer, BaseCoordinateFrame):
168             observer = frame.observer
169         elif frame.observer == 'self':
170             observer = frame
171         _set_wcs_aux_obs_coord(wcs, observer)
172 
173     if isinstance(frame, SunPyBaseCoordinateFrame):
174 
175         if frame.obstime:
176             wcs.wcs.dateobs = frame.obstime.utc.isot
177 
178         if isinstance(frame, Helioprojective):
179             xcoord = 'HPLN' + '-' + projection
180             ycoord = 'HPLT' + '-' + projection
181             wcs.wcs.cunit = ['arcsec', 'arcsec']
182         elif isinstance(frame, Heliocentric):
183             xcoord = 'SOLX'
184             ycoord = 'SOLY'
185             wcs.wcs.cunit = ['deg', 'deg']
186         elif isinstance(frame, HeliographicCarrington):
187             xcoord = 'CRLN' + '-' + projection
188             ycoord = 'CRLT' + '-' + projection
189             wcs.wcs.cunit = ['deg', 'deg']
190         elif isinstance(frame, HeliographicStonyhurst):
191             xcoord = 'HGLN' + '-' + projection
192             ycoord = 'HGLT' + '-' + projection
193             wcs.wcs.cunit = ['deg', 'deg']
194 
195     else:
196         return None
197 
198     wcs.wcs.ctype = [xcoord, ycoord]
199 
200     return wcs
201 
202 
203 astropy.wcs.utils.WCS_FRAME_MAPPINGS.append([solar_wcs_frame_mapping])
204 astropy.wcs.utils.FRAME_WCS_MAPPINGS.append([solar_frame_to_wcs_mapping])
205
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/sunpy/coordinates/wcs_utils.py b/sunpy/coordinates/wcs_utils.py
--- a/sunpy/coordinates/wcs_utils.py
+++ b/sunpy/coordinates/wcs_utils.py
@@ -191,6 +191,9 @@
             xcoord = 'HGLN' + '-' + projection
             ycoord = 'HGLT' + '-' + projection
             wcs.wcs.cunit = ['deg', 'deg']
+        else:
+            # A subclass not supported by the core library
+            return None
 
     else:
         return None

{"golden_diff": "diff --git a/sunpy/coordinates/wcs_utils.py b/sunpy/coordinates/wcs_utils.py\n--- a/sunpy/coordinates/wcs_utils.py\n+++ b/sunpy/coordinates/wcs_utils.py\n@@ -191,6 +191,9 @@\n             xcoord = 'HGLN' + '-' + projection\n             ycoord = 'HGLT' + '-' + projection\n             wcs.wcs.cunit = ['deg', 'deg']\n+        else:\n+            # A subclass not supported by the core library\n+            return None\n \n     else:\n         return None\n", "issue": "Support the use of SunPyBaseCoordinateFrame outside of core library\n### Describe the feature\r\n\r\n* It would be useful to be able to use `SunPyBaseCoordinateFrame` outside of sunpy but currently doing so is alkward as the `frame_to_wcs` and `wcs_to_frame` mappings are hardcode to the current frames / wcs' and raise an error you you try to do so\r\n* The name clearly implies this is SunPy specific but there a lot of boiler plate code that would have to be copied to provide the same thing.\r\n\r\nAt the moment to make this work you have to make sure what ever frames are added are added before the sunpy function e.g.\r\n\r\n`astropy.wcs.utils.FRAME_WCS_MAPPINGS.insert(1, [my_wcs_to_frame])`\r\n\r\n### Proposed solution\r\n\r\nDon't raise an error the if the frame is a subclass of `SunPyBaseCoordinateFrame` but not one of the frame implemented in sunpy return `None` \r\n\r\nSpecifically L198 raise an error as xcoord and xcoord are undefined\r\nhttps://github.com/sunpy/sunpy/blob/2281a2198997e8671efd48dcb531b07a98b86ddf/sunpy/coordinates/wcs_utils.py#L173-L198\r\n\r\nA simple solution would be to an a final else clause to this if Elias\r\n```python\r\n        elif isinstance(frame, HeliographicStonyhurst):\r\n            xcoord = 'HGLN' + '-' + projection\r\n            ycoord = 'HGLT' + '-' + projection\r\n            wcs.wcs.cunit = ['deg', 'deg']\r\n        else\r\n            return None\r\n\r\n```\n", "before_files": [{"content": "\nimport astropy.units as u\nimport astropy.wcs.utils\nfrom astropy.coordinates import BaseCoordinateFrame, SkyCoord\nfrom astropy.wcs import WCS\nfrom astropy.wcs.utils import obsgeo_to_frame\n\nfrom sunpy import log\nfrom .frames import (\n    Heliocentric,\n    HeliographicCarrington,\n    HeliographicStonyhurst,\n    Helioprojective,\n    SunPyBaseCoordinateFrame,\n)\n\n__all__ = ['solar_wcs_frame_mapping', 'solar_frame_to_wcs_mapping']\n\n\ndef solar_wcs_frame_mapping(wcs):\n    \"\"\"\n    This function registers the coordinates frames to their FITS-WCS coordinate\n    type values in the `astropy.wcs.utils.wcs_to_celestial_frame` registry.\n\n    Parameters\n    ----------\n    wcs : astropy.wcs.WCS\n\n    Returns\n    -------\n    astropy.coordinates.BaseCoordinateFrame\n    \"\"\"\n\n    if hasattr(wcs, \"coordinate_frame\"):\n        return wcs.coordinate_frame\n\n    dateobs = wcs.wcs.dateavg or wcs.wcs.dateobs or None\n\n    # Get observer coordinate from the WCS auxiliary information\n    # Note: the order of the entries is important, as it determines which set\n    # of header keys is given priority below. Stonyhurst should usually be\n    # prioritized, as it is defined more consistently across implementations,\n    # and so it should occur before Carrington here.\n    required_attrs = {HeliographicStonyhurst: ['hgln_obs', 'hglt_obs', 'dsun_obs'],\n                      HeliographicCarrington: ['crln_obs', 'hglt_obs', 'dsun_obs']}\n\n    # Get rsun from the WCS auxiliary information\n    rsun = wcs.wcs.aux.rsun_ref\n    if rsun is not None:\n        rsun *= u.m\n\n    # TODO: remove these errors in sunpy 4.1\n    bad_attrs = [f'.{attr}' for attr in ['rsun', 'heliographic_observer']\n                 if hasattr(wcs, attr)]\n    if len(bad_attrs):\n        raise ValueError(f\"The {' and '.join(bad_attrs)} attribute(s) on a WCS \"\n                         \"are no longer supported.\")\n\n    observer = None\n    for frame, attr_names in required_attrs.items():\n        attrs = [getattr(wcs.wcs.aux, attr_name) for attr_name in attr_names]\n        if all([attr is not None for attr in attrs]):\n            kwargs = {'obstime': dateobs}\n            if rsun is not None:\n                kwargs['rsun'] = rsun\n            if issubclass(frame, HeliographicCarrington):\n                kwargs['observer'] = 'self'\n\n            observer = frame(attrs[0] * u.deg,\n                             attrs[1] * u.deg,\n                             attrs[2] * u.m,\n                             **kwargs)\n            break\n\n    # Read the observer out of obsgeo for ground based observers\n    if observer is None:\n        try:\n            observer = obsgeo_to_frame(wcs.wcs.obsgeo, dateobs)\n            observer = SkyCoord(observer, rsun=rsun)\n        except ValueError as e:\n            # The helper function assumes you know the obsgeo coords you are\n            # parsing are good, we are not sure, so catch the error.\n\n            # This approach could lead to an invalid observer (i.e. one of the\n            # coords being NaN), but only if the WCS has been constructed like that.\n            log.debug(f\"Could not parse obsgeo coordinates from WCS:\\n{e}\")\n\n    # Collect all of the possible frame attributes, although some may be removed later\n    frame_args = {'obstime': dateobs}\n    if observer is not None:\n        frame_args['observer'] = observer\n    if rsun is not None:\n        frame_args['rsun'] = rsun\n\n    frame_class = _sunpy_frame_class_from_ctypes(wcs.wcs.ctype)\n\n    if frame_class:\n        if frame_class == HeliographicStonyhurst:\n            frame_args.pop('observer', None)\n        if frame_class == Heliocentric:\n            frame_args.pop('rsun', None)\n\n        return frame_class(**frame_args)\n\n\ndef _sunpy_frame_class_from_ctypes(ctypes):\n    # Truncate the ctype to the first four letters\n    ctypes = {c[:4] for c in ctypes}\n\n    mapping = {\n        Helioprojective: {'HPLN', 'HPLT'},\n        HeliographicStonyhurst: {'HGLN', 'HGLT'},\n        HeliographicCarrington: {'CRLN', 'CRLT'},\n        Heliocentric: {'SOLX', 'SOLY'},\n    }\n\n    for frame_class, ctype_pair in mapping.items():\n        if ctype_pair <= ctypes:\n            return frame_class\n\n\ndef _set_wcs_aux_obs_coord(wcs, obs_frame):\n    \"\"\"\n    Set (in-place) observer coordinate information on a WCS.\n\n    Parameters\n    ----------\n    wcs : astropy.wcs.WCS\n    obs_frame : astropy.coordinates.SkyCoord, astropy.coordinates.CoordinateFrame\n    \"\"\"\n    # Sometimes obs_coord can be a SkyCoord, so convert down to a frame\n    if hasattr(obs_frame, 'frame'):\n        obs_frame = obs_frame.frame\n\n    if isinstance(obs_frame, HeliographicStonyhurst):\n        wcs.wcs.aux.hgln_obs = obs_frame.lon.to_value(u.deg)\n    elif isinstance(obs_frame, HeliographicCarrington):\n        wcs.wcs.aux.crln_obs = obs_frame.lon.to_value(u.deg)\n    else:\n        raise ValueError('obs_coord must be in a Stonyhurst or Carrington frame')\n    # These two keywords are the same for Carrington and Stonyhurst\n    wcs.wcs.aux.hglt_obs = obs_frame.lat.to_value(u.deg)\n    wcs.wcs.aux.dsun_obs = obs_frame.radius.to_value(u.m)\n\n\ndef solar_frame_to_wcs_mapping(frame, projection='TAN'):\n    \"\"\"\n    For a given frame, this function returns the corresponding WCS object.\n    It registers the WCS coordinates types from their associated frame in the\n    `astropy.wcs.utils.celestial_frame_to_wcs` registry.\n\n    Parameters\n    ----------\n    frame : astropy.coordinates.BaseCoordinateFrame\n    projection : str, optional\n\n    Returns\n    -------\n    astropy.wcs.WCS\n    \"\"\"\n    wcs = WCS(naxis=2)\n\n    if hasattr(frame, 'rsun'):\n        wcs.wcs.aux.rsun_ref = frame.rsun.to_value(u.m)\n\n    if hasattr(frame, 'observer') and frame.observer is not None:\n        if isinstance(frame.observer, BaseCoordinateFrame):\n            observer = frame.observer\n        elif frame.observer == 'self':\n            observer = frame\n        _set_wcs_aux_obs_coord(wcs, observer)\n\n    if isinstance(frame, SunPyBaseCoordinateFrame):\n\n        if frame.obstime:\n            wcs.wcs.dateobs = frame.obstime.utc.isot\n\n        if isinstance(frame, Helioprojective):\n            xcoord = 'HPLN' + '-' + projection\n            ycoord = 'HPLT' + '-' + projection\n            wcs.wcs.cunit = ['arcsec', 'arcsec']\n        elif isinstance(frame, Heliocentric):\n            xcoord = 'SOLX'\n            ycoord = 'SOLY'\n            wcs.wcs.cunit = ['deg', 'deg']\n        elif isinstance(frame, HeliographicCarrington):\n            xcoord = 'CRLN' + '-' + projection\n            ycoord = 'CRLT' + '-' + projection\n            wcs.wcs.cunit = ['deg', 'deg']\n        elif isinstance(frame, HeliographicStonyhurst):\n            xcoord = 'HGLN' + '-' + projection\n            ycoord = 'HGLT' + '-' + projection\n            wcs.wcs.cunit = ['deg', 'deg']\n\n    else:\n        return None\n\n    wcs.wcs.ctype = [xcoord, ycoord]\n\n    return wcs\n\n\nastropy.wcs.utils.WCS_FRAME_MAPPINGS.append([solar_wcs_frame_mapping])\nastropy.wcs.utils.FRAME_WCS_MAPPINGS.append([solar_frame_to_wcs_mapping])\n", "path": "sunpy/coordinates/wcs_utils.py"}], "after_files": [{"content": "\nimport astropy.units as u\nimport astropy.wcs.utils\nfrom astropy.coordinates import BaseCoordinateFrame, SkyCoord\nfrom astropy.wcs import WCS\nfrom astropy.wcs.utils import obsgeo_to_frame\n\nfrom sunpy import log\nfrom .frames import (\n    Heliocentric,\n    HeliographicCarrington,\n    HeliographicStonyhurst,\n    Helioprojective,\n    SunPyBaseCoordinateFrame,\n)\n\n__all__ = ['solar_wcs_frame_mapping', 'solar_frame_to_wcs_mapping']\n\n\ndef solar_wcs_frame_mapping(wcs):\n    \"\"\"\n    This function registers the coordinates frames to their FITS-WCS coordinate\n    type values in the `astropy.wcs.utils.wcs_to_celestial_frame` registry.\n\n    Parameters\n    ----------\n    wcs : astropy.wcs.WCS\n\n    Returns\n    -------\n    astropy.coordinates.BaseCoordinateFrame\n    \"\"\"\n\n    if hasattr(wcs, \"coordinate_frame\"):\n        return wcs.coordinate_frame\n\n    dateobs = wcs.wcs.dateavg or wcs.wcs.dateobs or None\n\n    # Get observer coordinate from the WCS auxiliary information\n    # Note: the order of the entries is important, as it determines which set\n    # of header keys is given priority below. Stonyhurst should usually be\n    # prioritized, as it is defined more consistently across implementations,\n    # and so it should occur before Carrington here.\n    required_attrs = {HeliographicStonyhurst: ['hgln_obs', 'hglt_obs', 'dsun_obs'],\n                      HeliographicCarrington: ['crln_obs', 'hglt_obs', 'dsun_obs']}\n\n    # Get rsun from the WCS auxiliary information\n    rsun = wcs.wcs.aux.rsun_ref\n    if rsun is not None:\n        rsun *= u.m\n\n    # TODO: remove these errors in sunpy 4.1\n    bad_attrs = [f'.{attr}' for attr in ['rsun', 'heliographic_observer']\n                 if hasattr(wcs, attr)]\n    if len(bad_attrs):\n        raise ValueError(f\"The {' and '.join(bad_attrs)} attribute(s) on a WCS \"\n                         \"are no longer supported.\")\n\n    observer = None\n    for frame, attr_names in required_attrs.items():\n        attrs = [getattr(wcs.wcs.aux, attr_name) for attr_name in attr_names]\n        if all([attr is not None for attr in attrs]):\n            kwargs = {'obstime': dateobs}\n            if rsun is not None:\n                kwargs['rsun'] = rsun\n            if issubclass(frame, HeliographicCarrington):\n                kwargs['observer'] = 'self'\n\n            observer = frame(attrs[0] * u.deg,\n                             attrs[1] * u.deg,\n                             attrs[2] * u.m,\n                             **kwargs)\n            break\n\n    # Read the observer out of obsgeo for ground based observers\n    if observer is None:\n        try:\n            observer = obsgeo_to_frame(wcs.wcs.obsgeo, dateobs)\n            observer = SkyCoord(observer, rsun=rsun)\n        except ValueError as e:\n            # The helper function assumes you know the obsgeo coords you are\n            # parsing are good, we are not sure, so catch the error.\n\n            # This approach could lead to an invalid observer (i.e. one of the\n            # coords being NaN), but only if the WCS has been constructed like that.\n            log.debug(f\"Could not parse obsgeo coordinates from WCS:\\n{e}\")\n\n    # Collect all of the possible frame attributes, although some may be removed later\n    frame_args = {'obstime': dateobs}\n    if observer is not None:\n        frame_args['observer'] = observer\n    if rsun is not None:\n        frame_args['rsun'] = rsun\n\n    frame_class = _sunpy_frame_class_from_ctypes(wcs.wcs.ctype)\n\n    if frame_class:\n        if frame_class == HeliographicStonyhurst:\n            frame_args.pop('observer', None)\n        if frame_class == Heliocentric:\n            frame_args.pop('rsun', None)\n\n        return frame_class(**frame_args)\n\n\ndef _sunpy_frame_class_from_ctypes(ctypes):\n    # Truncate the ctype to the first four letters\n    ctypes = {c[:4] for c in ctypes}\n\n    mapping = {\n        Helioprojective: {'HPLN', 'HPLT'},\n        HeliographicStonyhurst: {'HGLN', 'HGLT'},\n        HeliographicCarrington: {'CRLN', 'CRLT'},\n        Heliocentric: {'SOLX', 'SOLY'},\n    }\n\n    for frame_class, ctype_pair in mapping.items():\n        if ctype_pair <= ctypes:\n            return frame_class\n\n\ndef _set_wcs_aux_obs_coord(wcs, obs_frame):\n    \"\"\"\n    Set (in-place) observer coordinate information on a WCS.\n\n    Parameters\n    ----------\n    wcs : astropy.wcs.WCS\n    obs_frame : astropy.coordinates.SkyCoord, astropy.coordinates.CoordinateFrame\n    \"\"\"\n    # Sometimes obs_coord can be a SkyCoord, so convert down to a frame\n    if hasattr(obs_frame, 'frame'):\n        obs_frame = obs_frame.frame\n\n    if isinstance(obs_frame, HeliographicStonyhurst):\n        wcs.wcs.aux.hgln_obs = obs_frame.lon.to_value(u.deg)\n    elif isinstance(obs_frame, HeliographicCarrington):\n        wcs.wcs.aux.crln_obs = obs_frame.lon.to_value(u.deg)\n    else:\n        raise ValueError('obs_coord must be in a Stonyhurst or Carrington frame')\n    # These two keywords are the same for Carrington and Stonyhurst\n    wcs.wcs.aux.hglt_obs = obs_frame.lat.to_value(u.deg)\n    wcs.wcs.aux.dsun_obs = obs_frame.radius.to_value(u.m)\n\n\ndef solar_frame_to_wcs_mapping(frame, projection='TAN'):\n    \"\"\"\n    For a given frame, this function returns the corresponding WCS object.\n    It registers the WCS coordinates types from their associated frame in the\n    `astropy.wcs.utils.celestial_frame_to_wcs` registry.\n\n    Parameters\n    ----------\n    frame : astropy.coordinates.BaseCoordinateFrame\n    projection : str, optional\n\n    Returns\n    -------\n    astropy.wcs.WCS\n    \"\"\"\n    wcs = WCS(naxis=2)\n\n    if hasattr(frame, 'rsun'):\n        wcs.wcs.aux.rsun_ref = frame.rsun.to_value(u.m)\n\n    if hasattr(frame, 'observer') and frame.observer is not None:\n        if isinstance(frame.observer, BaseCoordinateFrame):\n            observer = frame.observer\n        elif frame.observer == 'self':\n            observer = frame\n        _set_wcs_aux_obs_coord(wcs, observer)\n\n    if isinstance(frame, SunPyBaseCoordinateFrame):\n\n        if frame.obstime:\n            wcs.wcs.dateobs = frame.obstime.utc.isot\n\n        if isinstance(frame, Helioprojective):\n            xcoord = 'HPLN' + '-' + projection\n            ycoord = 'HPLT' + '-' + projection\n            wcs.wcs.cunit = ['arcsec', 'arcsec']\n        elif isinstance(frame, Heliocentric):\n            xcoord = 'SOLX'\n            ycoord = 'SOLY'\n            wcs.wcs.cunit = ['deg', 'deg']\n        elif isinstance(frame, HeliographicCarrington):\n            xcoord = 'CRLN' + '-' + projection\n            ycoord = 'CRLT' + '-' + projection\n            wcs.wcs.cunit = ['deg', 'deg']\n        elif isinstance(frame, HeliographicStonyhurst):\n            xcoord = 'HGLN' + '-' + projection\n            ycoord = 'HGLT' + '-' + projection\n            wcs.wcs.cunit = ['deg', 'deg']\n        else:\n            # A subclass not supported by the core library\n            return None\n\n    else:\n        return None\n\n    wcs.wcs.ctype = [xcoord, ycoord]\n\n    return wcs\n\n\nastropy.wcs.utils.WCS_FRAME_MAPPINGS.append([solar_wcs_frame_mapping])\nastropy.wcs.utils.FRAME_WCS_MAPPINGS.append([solar_frame_to_wcs_mapping])\n", "path": "sunpy/coordinates/wcs_utils.py"}]}