Repository: sunpy/sunpy

Issue:
unit kev not supported by DatabaseEntry._from_query_result_block
If a query result block stores the wavelength(s) in kev (note that it's written with a lowercase v!), a ValueError is raised because astropy.units.Unit only understand keV, not kev.

Here is the session to reproduce this behaviour:

``` pycon
>>> from sunpy.net import vso
>>> from sunpy.database.tables import DatabaseEntry
>>> qr = vso.search(
...     vso.attrs.Time((2011, 9, 20, 1), (2011, 9, 20, 2)),
...     vso.attrs.Instrument('RHESSI'))
>>> block = qr[0]
>>> DatabaseEntry._from_query_result_block(block)
Traceback (most recent call last):
  File "<pyshell#48>", line 1, in <module>
    DatabaseEntry._from_query_result_block(block)
  File "/home/derdon/repos/python/3rdparty/sunpy/sunpy/database/tables.py", line 289, in _from_query_result_block
    unit = Unit(wave.waveunit)
  File "/usr/lib64/python2.7/site-packages/astropy-0.3-py2.7-linux-x86_64.egg/astropy/units/core.py", line 1711, in __call__
    raise ValueError(msg)
ValueError: 'kev' did not parse as unit format 'generic': At col 0, u'kev' is not a valid unit in string kev
```

This is just to demonstrate the cause of the traceback:

``` pycon
>>> block.wave.waveunit
kev
>>> from astropy.units import Unit
>>> Unit('kev')
Traceback (most recent call last):
  File "<pyshell#51>", line 1, in <module>
    Unit('kev')
  File "/usr/lib64/python2.7/site-packages/astropy-0.3-py2.7-linux-x86_64.egg/astropy/units/core.py", line 1711, in __call__
    raise ValueError(msg)
ValueError: 'kev' did not parse as unit format 'generic': At col 0, 'kev' is not a valid unit in string 'kev'
```

Fortunately, astropy.units.Unit does interpret keV correctly, so catching the lowercase variant and "translating" it to keV should do the trick.



Discussion:

Resolving patch:
diff --git a/sunpy/database/tables.py b/sunpy/database/tables.py
--- a/sunpy/database/tables.py
+++ b/sunpy/database/tables.py
@@ -286,7 +286,12 @@ def _from_query_result_block(cls, qr_block, default_waveunit=None):
             if default_waveunit is not None:
                 unit = Unit(default_waveunit)
         else:
-            unit = Unit(wave.waveunit)
+            # some query response blocks store the unit "kev",
+            # but AstroPy only understands "keV". See issue #766.
+            waveunit = wave.waveunit
+            if waveunit == "kev":
+                waveunit = "keV"
+            unit = Unit(waveunit)
         if wave.wavemin is None:
             wavemin = None
         else:


Test patch:
diff --git a/sunpy/database/tests/test_tables.py b/sunpy/database/tests/test_tables.py
--- a/sunpy/database/tests/test_tables.py
+++ b/sunpy/database/tests/test_tables.py
@@ -40,6 +40,13 @@ def qr_block_with_missing_physobs():
         vso.attrs.Provider('SSC'), vso.attrs.Wave(10, 160, 'kHz'))[0]
 
 
+@pytest.fixture
+def qr_block_with_kev_unit():
+    return vso.VSOClient().query(
+        vso.attrs.Time((2011, 9, 20, 1), (2011, 9, 20, 2)),
+        vso.attrs.Instrument('RHESSI'))[0]
+
+
 def test_fits_header_entry_equality():
     assert FitsHeaderEntry('key', 'value') == FitsHeaderEntry('key', 'value')
     assert not (FitsHeaderEntry('key', 'value') == FitsHeaderEntry('k', 'v'))
@@ -92,6 +99,21 @@ def test_entry_from_qr_block_with_missing_physobs(qr_block_with_missing_physobs)
     assert entry == expected_entry
 
 
+@pytest.mark.online
+def test_entry_from_qr_block_kev(qr_block_with_kev_unit):
+    # See issue #766.
+    entry = DatabaseEntry._from_query_result_block(qr_block_with_kev_unit)
+    assert entry.source == 'RHESSI'
+    assert entry.provider == 'LSSP'
+    assert entry.fileid == '/hessidata/2011/09/20/hsi_20110920_010920'
+    assert entry.observation_time_start == datetime(2011, 9, 20, 1, 9, 20)
+    assert entry.observation_time_end == datetime(2011, 9, 20, 2, 27, 40)
+    assert entry.instrument == 'RHESSI'
+    assert entry.size == -1
+    assert round(entry.wavemin, 3) == 0.413
+    assert round(entry.wavemax, 7) == 0.0000729
+
+
 def test_entries_from_file():
     entries = list(entries_from_file(MQ_IMAGE))
     assert len(entries) == 1