[Zope-CVS] CVS: Packages/pypes/pypes - query.py:1.1 exceptions.py:1.4

Casey Duncan casey at zope.com
Tue Mar 30 23:58:39 EST 2004


Update of /cvs-repository/Packages/pypes/pypes
In directory cvs.zope.org:/tmp/cvs-serv9981

Modified Files:
	exceptions.py 
Added Files:
	query.py 
Log Message:
Add basic scan and sort query primitives w/tests


=== Added File Packages/pypes/pypes/query.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Pypes declarative object queries

Queries consist of inputs and operations. Operations denote query search
criteria  and output format. When executed, queries return a result which is
the output of the query operations applied in succession to the inputs.

Inputs for queries are collections of identified persistent objects in the
database, e.g. sets, extents or query results. The inputs define the maximal
extent of the query; the objects which will be considered by the operations.
Queries results cannot contain objects that do not appear in the inputs, other
than None.

Each input must provide a name, or have a name provided for it. These names can
be used by operations to refer to members of the cooresponding input
collection.

Operations define the semantics of the query; the process performed on the
inputs to derive the results. Operations are typically of the following kinds:
    
  filter -- filters determine which objects occur in the results.
  
  join -- joins determine how members of multiple input collections are 
          combined.
  
  sort -- sorts determine the order of the results.
  
  projection -- projections determines how the the result values are derived.
  
Operations are typically declared using Python expression strings. These
expressions describe the operation's behavior by using the query inputs 
and other objects provided by the calling program.

$Id: query.py,v 1.1 2004/03/31 04:58:08 caseman Exp $"""

from zope.interface import implements
from pypes.interfaces import IQueryEngine
from pypes.exceptions import PypesLookupError, PypesQueryInputError

## Exported constants ##

descending = 'descending'
ascending = 'ascending'

## Query Operations ##

def scan(*named_inputs, **inputs):
    """A generator of dicts comprising the product of the inputs which
    are iterable sequence of objects.
    
    The yielded dicts have each input name and one input member as their
    respective keys and values. inputs are either self-named on which case
    their name is derived from their __name__ attribute. self-named inputs
    are provided as positional arguments (order is not significant). Inputs
    which are not named, or for which an alias is desired are passed in as
    keyword arguments where the keyword denotes the name.
    
    Inputs may be any iterable sequence of objects. In general inputs are 
    homogenous sets of objects.
    
    Note that the yielded dict object is reused for each generation. Because
    of this, the application *must* make a copy of this dict if it wishes
    to persist a reference to it after the next one is generated.
    This is to efficiently handle the common case, where the generated
    product will be filtered and only a fraction of the generated "rows"
    will be used. Since scan_inputs generates a quantity of results equal
    to all of the inputs multiplied together, this greatly reduces the
    number of objects created by the scan
    """
    for ipt in named_inputs:
        try:
            name = ipt.__name__
        except AttributeError:
            raise PypesQueryInputError, 'unamed input %r' % ipt
        if name not in inputs:
            inputs[name] = ipt
        else:
            raise PypesQueryInputError, 'duplicate input name %s' % name
    # Prime the input iterators and get the first row
    row = {}
    input_iters = []
    for name, ipt in inputs.items():
        obj_iter = iter(ipt)
        input_iters.append((name, obj_iter))
        row[name] = obj_iter.next()
    yield row
    # Get subsequent rows by combining inputs
    i = 0
    while True:
        try:
            name, obj_iter = input_iters[i]
        except IndexError:
            break
        while True:
            try:
                row[name] = obj_iter.next()
            except StopIteration:
                obj_iter = iter(inputs[name])
                input_iters[i] = name, obj_iter
                row[name] = obj_iter.next()
                i += 1
                break
            else:
                yield row
                if i > 0:
                    i = 0
                    break

def sort(iterable, expression, order=ascending, limit=None):
    """Return a sequence containing the elements of iterable sorted in order
    by the values returned by applying expression, a callable object accepting
    a single argument, to each element. 
    
    order may be the constants ascending and descending to specify the
    resulting sort order. limit, if specified is an integer value representing
    the  number of elements to sort. When limit is specified, a partial sort
    will be performed and sort will return as soon as the limit count is
    reached.
    
    In order for the sort to perform properly, the expression should generate
    a homogenous set of values that support total ordering.
    """
    sortable = [(expression(i), i) for i in iterable]
    sortable.sort()
    if order == descending:
        sortable.reverse()
    if limit is not None:
        # XXX Implement N-Best algorithm for this
        sortable = sortable[:limit]
    # XXX We should be make this lazy
    return [i for key, i in sortable]


=== Packages/pypes/pypes/exceptions.py 1.3 => 1.4 ===
--- Packages/pypes/pypes/exceptions.py:1.3	Mon Feb  9 16:14:57 2004
+++ Packages/pypes/pypes/exceptions.py	Tue Mar 30 23:58:08 2004
@@ -46,3 +46,9 @@
     
 class GraphCycleError(PypesError):
     """Cycle detected during operation for acyclic graph"""
+    
+class PypesQueryError(PypesError):
+    """General error performing query"""
+
+class PypesQueryInputError(PypesQueryError):
+    """Invalid input to pypes query"""




More information about the Zope-CVS mailing list