Repository: sunpy/sunpy

Issue:
Example of reading data/header with io.fits.read is broken
In the docs, we have [the following example of how to read the data and header directly from a file using `sunpy.io.fits.read`](https://docs.sunpy.org/en/stable/code_ref/map.html#fixing-map-metadata),

```python
[data,header] = sunpy.io.fits.read(filename)
```

There are a few problems here.

1. If you have 2 HDUs, this returns the first to `data` and the second to `header`, obviously not the intended behavior.
2. You can use the `hdus` kwarg to select only a specific HDU but it turns out this is broken because the rest of the function expects an `HDUList` and after we slice it, we don't cast it back to an `HDUList` so everything after this explodes in fun and unexpected ways.
3. Even accounting for the first two problems, this function returns a list of data,header pairs, not a list of data and headers so you get a `ValueError` when trying to return this to a tuple as above. Fixing items 1 and 2, this example could be amended to,

```python
data, header = sunpy.io.fits.read(filename)[0]
```


Discussion:

Resolving patch:
diff --git a/sunpy/io/fits.py b/sunpy/io/fits.py
--- a/sunpy/io/fits.py
+++ b/sunpy/io/fits.py
@@ -48,7 +48,7 @@ def read(filepath, hdus=None, memmap=None, **kwargs):
     ----------
     filepath : `str`
         The fits file to be read.
-    hdu: `int` or iterable
+    hdus: `int` or iterable
         The HDU indexes to read from the file.
 
     Returns
@@ -71,7 +71,9 @@ def read(filepath, hdus=None, memmap=None, **kwargs):
             elif isinstance(hdus, collections.Iterable):
                 hdulist = [hdulist[i] for i in hdus]
 
-        hdulist.verify('silentfix+warn')
+        hdulist = fits.hdu.HDUList(hdulist)
+        for h in hdulist:
+            h.verify('silentfix+warn')
 
         headers = get_header(hdulist)
         pairs = []


Test patch:
diff --git a/sunpy/io/tests/test_fits.py b/sunpy/io/tests/test_fits.py
--- a/sunpy/io/tests/test_fits.py
+++ b/sunpy/io/tests/test_fits.py
@@ -21,76 +21,36 @@
 SWAP_LEVEL1_IMAGE = os.path.join(testpath, 'SWAP/resampled1_swap.fits')
 
 
-def read_hdus():
-    pairs = sunpy.io.fits.read(RHESSI_IMAGE)
-    assert len(pairs) == 4
-
-
-def read_hdu_int():
-    pairs = sunpy.io.fits.read(RHESSI_IMAGE, hdus=1)
-    assert len(pairs) == 1
-
-
-def read_hdus_list():
-    pairs = sunpy.io.fits.read(RHESSI_IMAGE, hdus=[1, 2])
-    assert len(pairs) == 2
-
-
-def read_hdus_gen():
-    pairs = sunpy.io.fits.read(RHESSI_IMAGE, hdus=range(0, 1))
-    assert len(pairs) == 2
-
-
-def test_extract_waveunit_missing_waveunit_key_and_missing_wavelnth_comment():
-    waveunit = extract_waveunit(get_header(RHESSI_IMAGE)[0])
-    assert waveunit is None
-
-
-def test_missing_waveunit_in_wavelnth_comment():
-    # the comment of the key WAVELNTH has the value
-    # '171 = Fe IX/X, 195 = Fe XII,' which contains no unit information
-    waveunit = extract_waveunit(get_header(EIT_195_IMAGE)[0])
-    assert waveunit is None
-
-
-def test_extract_waveunit_from_waveunit_key():
-    # the key WAVEUNIT can be accessed and returned directly
-    waveunit = extract_waveunit(get_header(AIA_171_IMAGE)[0])
-    assert waveunit == 'angstrom'
-
-
-def test_extract_waveunit_minus9():
-    # value of WAVEUNIT is -9
-    with pytest.warns(AstropyUserWarning, match='File may have been truncated'):
-        waveunit = extract_waveunit(get_header(MEDN_IMAGE)[0])
-    assert waveunit == 'nm'
-
-
-def test_extract_waveunit_minus10():
-    # value of WAVEUNIT is -10
-    with pytest.warns(AstropyUserWarning, match='File may have been truncated'):
-        waveunit = extract_waveunit(get_header(MQ_IMAGE)[0])
-    assert waveunit == 'angstrom'
-
-
-def test_extract_waveunit_waveunitcomment():
-    # comment of WAVEUNIT is: "in meters"
-    with pytest.warns(AstropyUserWarning, match='File may have been truncated'):
-        waveunit = extract_waveunit(get_header(NA_IMAGE)[0])
-    assert waveunit == 'm'
-
-
-def test_extract_waveunit_wavelnthcomment_brackets():
-    # WAVELNTH comment is: "[Angstrom] bandpass peak response"
-    waveunit = extract_waveunit(get_header(SWAP_LEVEL1_IMAGE)[0])
-    assert waveunit == 'angstrom'
-
-
-def test_extract_waveunit_wavelnthcomment_parentheses():
-    # WAVELNTH comment is: "Observed wavelength (nm)"
-    with pytest.warns(AstropyUserWarning, match='File may have been truncated'):
-        waveunit = extract_waveunit(get_header(SVSM_IMAGE)[0])
-    assert waveunit == 'nm'
+@pytest.mark.parametrize(
+    'fname, hdus, length',
+    [(RHESSI_IMAGE, None, 4),
+     (RHESSI_IMAGE, 1, 1),
+     (RHESSI_IMAGE, [1, 2], 2),
+     (RHESSI_IMAGE, range(0, 1), 2)]
+)
+def read_hdus(fname, hdus, length):
+    pairs = sunpy.io.fits.read(fname, hdus=hdus)
+    assert len(pairs) == length
+
+
+@pytest.mark.parametrize(
+    'fname, waveunit, warn',
+    [(RHESSI_IMAGE, None, False),
+     (EIT_195_IMAGE, None, False),
+     (AIA_171_IMAGE, 'angstrom', False),
+     (MEDN_IMAGE, 'nm', True),
+     (MQ_IMAGE, 'angstrom', True),
+     (NA_IMAGE, 'm', True),
+     (SWAP_LEVEL1_IMAGE, 'angstrom', False),
+     (SVSM_IMAGE, 'nm', True)]
+)
+def test_extract_waveunit(fname, waveunit, warn):
+    if warn:
+        with pytest.warns(AstropyUserWarning, match='File may have been truncated'):
+            waveunit = extract_waveunit(get_header(fname)[0])
+    else:
+        waveunit = extract_waveunit(get_header(fname)[0])
+    assert waveunit is waveunit
 
 
 def test_simple_write(tmpdir):
@@ -138,8 +98,7 @@ def test_fitsheader():
         for ffile in Path(testpath).glob(f"*.{ext}*"):
             fits_file = fits.open(ffile)
             fits_file.verify("fix")
-            data, header = fits_file[0].data, fits_file[0].header
-            meta_header = MetaDict(OrderedDict(header))
+            meta_header = MetaDict(OrderedDict(fits_file[0].header))
             sunpy.io.fits.header_to_fits(meta_header)
             fits_file.close()