Repository: sunpy/sunpy

Issue:
VSO query and the show function
Hi,

I am trying out the new style VSO query.  So to start with I tried

qr=client.query(vso.attrs.Time(datetime(2001,1,1), datetime(2001,1,2)), vso.attrs.Instrument('eit'))

and then used

qr.show()

which printed out a simple list of the properties of the files.  My next query was to look for the EIT and MDI data available for that day:

qr2=client.query(vso.attrs.Time(datetime(2001,1,1), datetime(2001,1,2)), vso.attrs.Instrument('eit') | vso.attrs.Instrument('mdi'))

I know more records have been returned since qr2.num_records() > qr.num_records() .  However, when I try qr2.show() I get the following error
## In [14]: qr2.show()

TypeError                                 Traceback (most recent call last)
/Users/ireland/<ipython-input-14-e822933b189a> in <module>()
----> 1 qr2.show()

/Users/ireland/sunpy/sunpy/net/vso/**init**.pyc in show(self)
    190           record.source,
    191           record.instrument,
--> 192           record.extent.type] for record in self]
    193         table.insert(0, ['----------','--------','------','----------','----'])
    194         table.insert(0, ['Start time','End time','Source','Instrument','Type'])

TypeError: must be string, not None

Was the original query mis-specified in some way, or maybe there is something funky with MDI data?  I think it must be what is returned from the VSO about MDI data.  If I try

qr3=client.query(vso.attrs.Time(datetime(2001,1,1), datetime(2001,1,2)), vso.attrs.Instrument('mdi') )

and try qr3.show(), I get the same error.  Perhaps some checking is required for fields which return 'None'.

Thanks!



Discussion:

Resolving patch:
diff --git a/sunpy/net/attr.py b/sunpy/net/attr.py
--- a/sunpy/net/attr.py
+++ b/sunpy/net/attr.py
@@ -113,7 +113,7 @@ def __hash__(self):
         return hash(frozenset(self.attrs))
     
     def collides(self, other):
-        return any(elem.collides(other) for elem in self)
+        return any(elem.collides(other) for elem in self.attrs)
 
 
 class AttrOr(Attr):
@@ -164,7 +164,7 @@ def __hash__(self):
         return hash(frozenset(self.attrs))
     
     def collides(self, other):
-        return all(elem.collides(other) for elem in self)
+        return all(elem.collides(other) for elem in self.attrs)
 
 
 class ValueAttr(Attr):
diff --git a/sunpy/net/vso/__init__.py b/sunpy/net/vso/__init__.py
--- a/sunpy/net/vso/__init__.py
+++ b/sunpy/net/vso/__init__.py
@@ -16,7 +16,6 @@
 import os
 import sys
 import random
-import tempfile
 import threading
 
 
@@ -26,6 +25,7 @@
 from string import ascii_lowercase
 from suds import client, TypeNotFound
 
+from sunpy import config
 from sunpy.net import download
 from sunpy.net.util import get_filename, slugify
 from sunpy.net.attr import and_, Attr
@@ -118,7 +118,7 @@ def add_error(self, exception):
 
 
 def _parse_waverange(string):
-    min_, max_, unit = RANGE.match(string)[::2]
+    min_, max_, unit = RANGE.match(string).groups()[::2]
     return {
         'wave_wavemin': min_,
         'wave_wavemax': min_ if max_ is None else max_,
@@ -177,19 +177,27 @@ def time_range(self):
         """ Return total time-range all records span across. """
         return (
             datetime.strptime(
-                min(record.time.start for record in self), TIMEFORMAT),
+                min(record.time.start for record in self
+                  if record.time.start is not None), TIMEFORMAT),
             datetime.strptime(
-                max(record.time.end for record in self), TIMEFORMAT)
+                max(record.time.end for record in self
+                  if record.time.end is not None), TIMEFORMAT)
         )
 
     def show(self):
         """Print out human-readable summary of records retrieved"""
 
-        table = [[str(datetime.strptime(record.time.start, TIMEFORMAT)), 
-          str(datetime.strptime(record.time.end, TIMEFORMAT)), 
-          record.source,
-          record.instrument,
-          record.extent.type] for record in self]
+        table = [
+          [
+            str(datetime.strptime(record.time.start, TIMEFORMAT))
+              if record.time.start is not None else 'N/A',
+            str(datetime.strptime(record.time.end, TIMEFORMAT))
+              if record.time.end is not None else 'N/A',
+            record.source,
+            record.instrument,
+            record.extent.type
+              if record.extent.type is not None else 'N/A'
+          ] for record in self]
         table.insert(0, ['----------','--------','------','----------','----'])        
         table.insert(0, ['Start time','End time','Source','Instrument','Type'])
 
@@ -524,7 +532,8 @@ def get(self, query_response, path=None, methods=('URL-FILE',), downloader=None)
                 lambda _: None, 1, lambda mp: self.link(query_response, mp)
             )
         if path is None:
-            path = os.path.join(tempfile.mkdtemp(), '{file}')
+            path = os.path.join(config.get('downloads','download_dir'),
+                                '{file}')
         fileids = VSOClient.by_fileid(query_response)
         if not fileids:
             res.poke()
diff --git a/sunpy/net/vso/attrs.py b/sunpy/net/vso/attrs.py
--- a/sunpy/net/vso/attrs.py
+++ b/sunpy/net/vso/attrs.py
@@ -53,7 +53,7 @@ def __contains__(self, other):
 class Wave(Attr, _Range):
     def __init__(self, wavemin, wavemax, waveunit='Angstrom'):
         self.min, self.max = sorted(
-            to_angstrom(v, waveunit) for v in [wavemin, wavemax]
+            to_angstrom(v, waveunit) for v in [float(wavemin), float(wavemax)]
         )
         self.unit = 'Angstrom'
         
@@ -316,9 +316,13 @@ def _(attr, results):
     return set(
         it for it in results
         if
-        attr.min <= to_angstrom(it.wave.wavemax, it.wave.waveunit)
+        it.wave.wavemax is not None
         and
-        attr.max >= to_angstrom(it.wave.wavemin, it.wave.waveunit)
+        attr.min <= to_angstrom(float(it.wave.wavemax), it.wave.waveunit)
+        and
+        it.wave.wavemin is not None
+        and
+        attr.max >= to_angstrom(float(it.wave.wavemin), it.wave.waveunit)
     )
 
 @filter_results.add_dec(Time)
@@ -326,8 +330,12 @@ def _(attr, results):
     return set(
         it for it in results
         if
+        it.time.end is not None
+        and
         attr.min <= datetime.strptime(it.time.end, TIMEFORMAT)
         and
+        it.time.start is not None
+        and
         attr.max >= datetime.strptime(it.time.start, TIMEFORMAT)
     )
 
@@ -335,5 +343,8 @@ def _(attr, results):
 def _(attr, results):
     return set(
         it for it in results
-        if it.extent.type.lower() == attr.type.lower()
+        if
+        it.extent.type is not None
+        and
+        it.extent.type.lower() == attr.type.lower()
     )


Test patch: