def _getTsVar(self,
               station_dict,
               major_minor_tuple,
               explain_exception=True):
     if not isinstance(station_dict, AsciiSafeDict):
         _station_dict = AsciiSafeDict.makeSafe(station_dict, True)
     else:
         _station_dict = station_dict
     major, minor = major_minor_tuple
     data = self.ucan.get_data()
     try:
         if _station_dict['network'] == 'icao':
             station_id = self._getStationId(_station_dict, True)
             return data.newTSVarNative(major, minor, station_id)
         else:
             return data.newTSVar(major, minor, _station_dict['ucanid'])
     except Exception as e:
         data.release()
         if explain_exception:
             msg = '(%d,%d) is not a valid tsvar for the network/ucanid combination.'
             explain = explainException(e, station_dict,
                                        msg % (major, minor))
             raise UcanInvalidTsvarError, explain
         else:
             raise e
    def getTsVar(self, station_dict, element_name):
        network = station_dict['network'].encode('iso-8859-1')
        if not isinstance(station_dict, AsciiSafeDict):
            _station_dict = AsciiSafeDict.makeSafe(station_dict, True)
        else:
            _station_dict = station_dict
        stn_id = self._getStationId(_station_dict, True)

        exception = None
        major_minor_group = None
        tsvar_groups = getTsVarCodeset(network, element_name)
        for major_minor_group in tsvar_groups:
            try:
                return self._getTsVar(_station_dict, major_minor_group, False)
            except Exception as e:
                if 'UnknownUcanId' in e.__class__.__name__:
                    exception = e
                else:
                    raise e

        uid = _station_dict['ucanid']
        msg = 'Unable to acquire tsvar for %s element of station %s (%s)'
        detail = msg % (element_name, station_dict['sid'],
                        station_dict['name'])
        mms = str(major_minor_group)
        #mms = ' and '.join( ['(%d,%d)' % major_minor
        #                     for major_minor in major_minor_group])
        msg = '%s are not valid tsvars for the station/network combination.'
        detail = msg % mms
        raise UcanInvalidTsvarError, explainException(exception, station_dict,
                                                      detail)
    def getValidDateRange(self, station_dict, elem, debug=False):
        _station_dict = AsciiSafeDict.makeSafe(station_dict, True)
        if isinstance(elem, (tuple, list)):
            ts_var = self._getTsVar(_station_dict, elem)
        else:
            ts_var = self.getTsVar(_station_dict, elem)

        start_time, end_time = ts_var.getValidDateRange()
        ts_var.release()

        return start_time, end_time
 def getMetadata(self, station_dict):
     _station_dict = AsciiSafeDict.makeSafe(station_dict, True)
     query = self.ucan.get_query()
     try:
         metadata = query.getInfoForUcanIdAsSeq(_station_dict['ucanid'], ())
         metadata = ucanCallMethods.NameAny_to_dict(metadata[-1].fields)
         if 'id' in metadata and isinstance(metadata['id'], int):
             metadata['id'] = str(metadata['id'])
         return metadata
     except Exception as e:
         detail = "failed for query metadata using UCAN interface."
         raise UcanDataError, explainException(e, station_dict, detail)
     finally:
         query.release()
 def _getStationId(self, station_dict, encode=True):
     if not isinstance(station_dict, AsciiSafeDict):
         _station_dict = AsciiSafeDict.makeSafe(station_dict, True)
     else:
         _station_dict = station_dict
     if 'id' in _station_dict:
         if isinstance(_station_dict['id'], int):
             return str(_station_dict['id'])
         else:
             if encode: return _station_dict['id'].upper().encode('ascii')
             else: return _station_dict['id']
     else:
         if isinstance(_station_dict['sid'], int):
             return str(_station_dict['sid'])
         else:
             if encode: return _station_dict['sid'].upper().encode('ascii')
             else: return _station_dict['sid']
    def ucanid(self, station_dict):
        network = station_dict['network'].encode('iso-8859-1')
        _station_dict = AsciiSafeDict.makeSafe(station_dict, True)
        station_id = self._getStationId(_station_dict, True)
        try:
            query = self.ucan.get_query()
            result = query.getUcanFromIdAsSeq(station_id, network)
        except Exception as e:
            detail = 'Unable to acquire UCAN ID for station.'
            raise UcanStationIDError, explainException(e, station_dict, detail)
        finally:
            query.release()

        if len(result) > 0:
            return result[-1].ucan_id
        else:
            errmsg = 'UCAN ID was not found for : %s'
            raise KeyError, errmsg % (STATION_INFO % station_dict)
    def getHourlyData(self,
                      station_dict,
                      elem,
                      dtype,
                      units,
                      missing,
                      start_date=None,
                      end_date=None,
                      debug=False):
        if debug: print 'UcanConnection.getHourlyData'

        _station_dict = AsciiSafeDict.makeSafe(station_dict, True)
        sid = self._getStationId(_station_dict, False)
        ucanid = station_dict['ucanid']

        if isinstance(elem, (tuple, list)):
            ts_var = self._getTsVar(_station_dict, elem)
        else:
            ts_var = self.getTsVar(_station_dict, elem)

        try:
            ts_var.setUnits(units)
        except Exception as e:
            detail = "failed call to ts_var.setUnits('%s') for '%s'" % (units,
                                                                        elem)
            raise UcanDataError, explainException(e, station_dict, detail)

        ts_var.setMissingDataAsFloat(-32768.)

        start_range, end_range = ts_var.getValidDateRange()
        if debug:
            print 'as input'
            print sid, ucanid, elem, 'requested', start_date, end_date
            print sid, ucanid, elem, 'available', start_range, end_range

        if start_date is None:
            start_date_ = max(self.base_date, tuple(start_range))
        else:
            start_date_ = max(copy(start_date), tuple(start_range))
            if len(start_date_) == 3: start_date_ += (0, )
        start_date_ = datetime(*start_date_)
        start_range = datetime(*start_range)

        if end_date is None: end_date_ = tuple(end_range)
        else:
            end_date_ = min(copy(end_date), tuple(end_range))
            if len(end_date_) == 3: end_date_ += (23, )
        end_date_ = datetime(*end_date_)
        end_range = datetime(*end_range)

        if debug:
            print 'as datetime'
            print sid, ucanid, elem, 'requested', start_date_, end_date_
            print sid, ucanid, elem, 'available', start_range, end_range

        # add ONE_HOUR to end_date_ because ts_var always returns one hour
        # less than requested
        end_time = end_date_ + ONE_HOUR

        # break up time span into self.hours_per_request increments due to
        # tsvar/ucan server limitations
        start_span = copy(start_date_)
        spans = []
        while start_span < end_time:
            elapsed = self.elapsedHours(start_span, end_time)
            if elapsed > self.hours_per_request:
                end_span = start_span + self.request_delta
            else:
                end_span = end_time
            spans.append(
                (start_span.timetuple()[:4], end_span.timetuple()[:4]))
            # set next 'start_span' to previous `end_span` because ts_var
            # always returns one hour less than requested
            start_span = end_span

        # accumulate data array
        hourly_data = []

        # add retrievable data to array
        for start_span, end_span in spans:
            if debug: print 'set span', start_span, end_span
            try:
                ts_var.setDateRange(start_span, end_span)

            except Data.TSVar.UnavailableDateRange:
                # sometimes we get bad time ranges so we pass back
                # a bunch of missing values
                hours = self.elapsedHours(start_span, end_span)
                tsv_data = [-32768 for hour in range(hours)]

            except Exception as e:
                ts_var.release()
                msg = "failed call to ts_var.setDateRange(%s, %s) for '%s'"
                detail = msg % (str(start_span), str(end_span), elem)
                raise UcanDataError, explainException(e, station_dict, detail)

            else:
                try:
                    tsv_data = ts_var.getDataSeqAsFloat()
                    #print start_span, end_span
                    #print tsv_data
                except Exception as e:
                    ts_var.release()
                    msg = "failed call to ts_var.getDataSeqAsFloat() for '%s' from %s thru %s"
                    detail = msg % (elem, str(start_span), str(end_span))
                    explanation = explainException(e, station_dict, detail)
                    raise UcanDataError, explanation

            hourly_data.extend(tsv_data)

        ts_var.release()

        if debug:
            msg = '%s %d : num hours = %d : num_days = %d'
            num_hours = len(hourly_data)
            print msg % (sid, ucanid, num_hours, num_hours / 24)

        hourly_data = N.array(hourly_data, dtype=dtype)
        if missing != -32768:
            hourly_data[N.where(hourly_data == -32768)] = missing
        return (start_date_.timetuple()[:4], end_date_.timetuple()[:4],
                hourly_data)