Beispiel #1
0
    def _attribute(self):
        # Get type and name.
        type_ = self.get_token()
        name = self.get_token()

        # Get values: value_1 (, value_n)*
        values = []
        while not self._check(';'):
            value = self.get_token()

            if type_.lower() in ['string', 'url']:
                value = expr_eval(repr(value))
                value = value.strip('"')
            elif type_.lower() == 'alias':
                # Support for Alias is not documented in the DAP spec. I based
                # this on the Java documentation from the OPeNDAP website at:
                # http://www.opendap.org/api/javaDocs/dods/dap/Alias.html
                if value.startswith('.'):
                    tokens = value[1:].split('.')
                    value = self._dataset
                else:
                    tokens = value.split('.')
                    value = self._target
                for token in tokens:
                    if token in value:
                        value = value[token]
                    elif token:
                        value = value.attributes.get(
                            token, "Alias pointing to non-existing attribute.")
                        break
                    else:
                        value = value.attributes
            elif type_.lower() == 'float32':
                # Convert to right precision; otherwise floats
                # are converted to Float64 automatically by
                # Python.
                value = array.array('f', [float(value)])[0]
            elif type_.lower() == 'float64':
                value = array.array('d', [float(value)])[0]
            else:
                value = int(value)
            values.append(value)

            if self._check(','): self._consume(',')

        self._consume(';')

        # Return single attributes as values, not list.
        if len(values) == 1: values = values[0]

        return name, values
Beispiel #2
0
def buildfilter(queries, vars_):
    """This function is a filter builder.

    Given a list of DAP formatted queries and a list of variable names,
    this function returns a dynamic filter function to filter rows.

    From the example in the DAP specification:

        >>> vars_ = ['index', 'temperature', 'site']
        >>> data = []
        >>> data.append([10, 17.2, 'Diamond_St'])
        >>> data.append([11, 15.1, 'Blacktail_Loop'])
        >>> data.append([12, 15.3, 'Platinum_St'])
        >>> data.append([13, 15.1, 'Kodiak_Trail'])

    Rows where index is greater-than-or-equal 11:

        >>> f = buildfilter(['index>=11'], vars_)
        >>> for line in itertools.ifilter(f, data):
        ...     print line
        [11, 15.1, 'Blacktail_Loop']
        [12, 15.300000000000001, 'Platinum_St']
        [13, 15.1, 'Kodiak_Trail']

    Rows where site ends with '_St':

        >>> f = buildfilter(['site=~".*_St"'], vars_)
        >>> for line in itertools.ifilter(f, data):
        ...     print line
        [10, 17.199999999999999, 'Diamond_St']
        [12, 15.300000000000001, 'Platinum_St']

    Index greater-or-equal-than 11 AND site ends with '_St':

        >>> f = buildfilter(['site=~".*_St"', 'index>=11'], vars_)
        >>> for line in itertools.ifilter(f, data):
        ...     print line
        [12, 15.300000000000001, 'Platinum_St']

    Site is either 'Diamond_St' OR 'Blacktail_Loop':
    
        >>> f = buildfilter(['site={"Diamond_St", "Blacktail_Loop"}'], vars_)
        >>> for line in itertools.ifilter(f, data):
        ...     print line
        [10, 17.199999999999999, 'Diamond_St']
        [11, 15.1, 'Blacktail_Loop']

    Index is either 10 OR 12:

        >>> f = buildfilter(['index={10, 12}'], vars_)
        >>> for line in itertools.ifilter(f, data):
        ...     print line
        [10, 17.199999999999999, 'Diamond_St']
        [12, 15.300000000000001, 'Platinum_St']

    Python is great, isn't it? :)
    """
    filters = []
    p = re.compile(r'''^                          # Start of selection
                       {?                         # Optional { for multi-valued constants
                       (?P<var1>.*?)              # Anything
                       }?                         # Closing }
                       (?P<op><=|>=|!=|=~|>|<|=)  # Operators
                       {?                         # {
                       (?P<var2>.*?)              # Anything
                       }?                         # }
                       $                          # EOL
                    ''', re.VERBOSE)
    for query in queries:
        m = p.match(query)
        if not m: raise ConstraintExpressionError('Invalid constraint expression: %s.' % query)

        # Functions associated with each operator.
        op = {'<' : operator.lt,
              '>' : operator.gt,
              '!=': operator.ne,
              '=' : operator.eq,
              '>=': operator.ge,
              '<=': operator.le,
              '=~': lambda a,b: re.match(b,a),
             }[m.group('op')]
        # Allow multiple comparisons in one line. Python rulez!
        op = multicomp(op)

        # Build the filter for the first variable.
        if m.group('var1') in vars_:
            i = vars_.index(m.group('var1'))
            var1 = lambda L, i=i: operator.getitem(L, i)

            # Build the filter for the second variable. It could be either
            # a name or a constant.
            if m.group('var2') in vars_:
                i = vars_.index(m.group('var2'))
                var2 = lambda L, i=i: operator.getitem(L, i)
            else:
                var2 = lambda x, m=m: expr_eval(m.group('var2'))

            # This is the filter. We apply the function (op) to the variable
            # filters (var1 and var2).
            filter0 = lambda x, op=op, var1=var1, var2=var2: op(var1(x), var2(x))
            filters.append(filter0)

    if filters:
        # We have to join all the filters that were built, using the AND 
        # operator. Believe me, this line does exactly that.
        #
        # You are not expected to understand this.
        filter0 = lambda i: reduce(lambda x,y: x and y, [f(i) for f in filters])
    else:
        filter0 = bool

    return filter0