home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / python-support / python-rdflib / rdflib / sparql / bison / SPARQLEvaluate.py < prev    next >
Encoding:
Python Source  |  2007-04-04  |  21.8 KB  |  457 lines

  1. ### Utilities for evaluating a parsed SPARQL expression using sparql-p
  2. import rdflib
  3. from rdflib.sparql import sparqlGraph, sparqlOperators, SPARQLError
  4. from rdflib.sparql.sparqlOperators import getValue
  5. from rdflib.sparql.graphPattern import BasicGraphPattern
  6. from rdflib.sparql.Unbound import Unbound
  7. from rdflib.sparql.Query import _variablesToArray, queryObject, SessionBNode
  8. from rdflib.Graph import ConjunctiveGraph, Graph, BackwardCompatGraph,ReadOnlyGraphAggregate
  9. from rdflib import URIRef,Variable,BNode, Literal, plugin, RDF
  10. from rdflib.store import Store
  11. from rdflib.Literal import XSDToPython
  12. from IRIRef import NamedGraph,RemoteGraph
  13. from GraphPattern import ParsedAlternativeGraphPattern,ParsedOptionalGraphPattern
  14. from Resource import *
  15. from Triples import ParsedConstrainedTriples
  16. from QName import *
  17. from PreProcessor import *
  18. from Expression import *
  19. from Util import ListRedirect
  20. from Operators import *
  21. from FunctionLibrary import *
  22. from SolutionModifier import ASCENDING_ORDER
  23. from Query import AskQuery, SelectQuery
  24.  
  25. DEBUG = False
  26.  
  27. BinaryOperatorMapping = {
  28.     LessThanOperator           : 'sparqlOperators.lt(%s,%s)%s',
  29.     EqualityOperator           : 'sparqlOperators.eq(%s,%s)%s',
  30.     NotEqualOperator           : 'sparqlOperators.neq(%s,%s)%s',
  31.     LessThanOrEqualOperator    : 'sparqlOperators.le(%s,%s)%s',
  32.     GreaterThanOperator        : 'sparqlOperators.gt(%s,%s)%s',
  33.     GreaterThanOrEqualOperator : 'sparqlOperators.ge(%s,%s)%s',
  34. }
  35.  
  36. UnaryOperatorMapping = {
  37.     LogicalNegation : 'not(%s)',
  38.     NumericNegative : '-(%s)',
  39. }
  40.  
  41. CAMEL_CASE_BUILTINS = {
  42.     'isuri':'sparqlOperators.isURI',
  43.     'isiri':'sparqlOperators.isIRI',
  44.     'isblank':'sparqlOperators.isBlank',
  45.     'isliteral':'sparqlOperators.isLiteral',
  46. }
  47.  
  48. def convertTerm(term,queryProlog):
  49.     """
  50.     Utility function  for converting parsed Triple components into Unbound 
  51.     """
  52.     if isinstance(term,Variable):
  53.         return Unbound(term[1:])
  54.     elif isinstance(term,BNode):
  55.         return term
  56.     elif isinstance(term,QName):
  57.         #QNames and QName prefixes are the same in the grammar
  58.         if not term.prefix:
  59.             return URIRef(queryProlog.baseDeclaration + term.localname)
  60.         elif term.prefix == '_':
  61.             #Told BNode See: http://www.w3.org/2001/sw/DataAccess/issues#bnodeRef
  62.             import warnings
  63.             warnings.warn("The verbatim interpretation of explicit bnode identifiers is contrary to (current) DAWG stance",SyntaxWarning)
  64.             return SessionBNode(term.localname)        
  65.         else:
  66.             return URIRef(queryProlog.prefixBindings[term.prefix] + term.localname)
  67.     elif isinstance(term,QNamePrefix):
  68.         return URIRef(queryProlog.baseDeclaration + term)
  69.     elif isinstance(term,ParsedString):
  70.         return Literal(term)
  71.     else:
  72.         return term
  73.  
  74. def unRollCollection(collection,queryProlog):
  75.     nestedComplexTerms = []
  76.     listStart = convertTerm(collection.identifier,queryProlog)
  77.     if not collection._list:
  78.         yield (listStart,RDF.rest,RDF.nil)
  79.     elif len(collection._list) == 1:
  80.         singleItem = collection._list[0]
  81.         if isinstance(singleItem,RDFTerm):
  82.             nestedComplexTerms.append(singleItem)
  83.             yield (listStart,RDF.first,convertTerm(singleItem.identifier,queryProlog))
  84.         else:
  85.             yield (listStart,RDF.first,convertTerm(singleItem,queryProlog))
  86.         yield (listStart,RDF.rest,RDF.nil)
  87.     else:
  88.         yield (listStart,RDF.first,collection._list[0].identifier)
  89.         prevLink = listStart
  90.         for colObj in collection._list[1:]:
  91.             linkNode = convertTerm(BNode(),queryProlog)
  92.             if isinstance(colObj,RDFTerm):
  93.                 nestedComplexTerms.append(colObj)
  94.                 yield (linkNode,RDF.first,convertTerm(colObj.identifier,queryProlog))
  95.             else:
  96.                 yield (linkNode,RDF.first,convertTerm(colObj,queryProlog))            
  97.             yield (prevLink,RDF.rest,linkNode)            
  98.             prevLink = linkNode                        
  99.         yield (prevLink,RDF.rest,RDF.nil)
  100.     
  101.     for additionalItem in nestedComplexTerms:
  102.         for item in unRollRDFTerm(additionalItem,queryProlog):
  103.             yield item    
  104.  
  105. def unRollRDFTerm(item,queryProlog):
  106.     nestedComplexTerms = []
  107.     for propVal in item.propVals:
  108.         for propObj in propVal.objects:
  109.             if isinstance(propObj,RDFTerm):
  110.                 nestedComplexTerms.append(propObj)
  111.                 yield (convertTerm(item.identifier,queryProlog),
  112.                        convertTerm(propVal.property,queryProlog),
  113.                        convertTerm(propObj.identifier,queryProlog))
  114.             else:
  115.                yield (convertTerm(item.identifier,queryProlog),
  116.                       convertTerm(propVal.property,queryProlog),
  117.                       convertTerm(propObj,queryProlog))
  118.     if isinstance(item,ParsedCollection):
  119.         for rt in unRollCollection(item,queryProlog):
  120.             yield rt  
  121.     for additionalItem in nestedComplexTerms:
  122.         for item in unRollRDFTerm(additionalItem,queryProlog):
  123.             yield item
  124.  
  125. def unRollTripleItems(items,queryProlog):
  126.     """
  127.     Takes a list of Triples (nested lists or ParsedConstrainedTriples)
  128.     and (recursively) returns a generator over all the contained triple patterns
  129.     """ 
  130.     if isinstance(items,RDFTerm):
  131.         for item in unRollRDFTerm(items,queryProlog):
  132.             yield item
  133.     else:
  134.         for item in items:
  135.             if isinstance(item,RDFTerm):
  136.                 for i in unRollRDFTerm(item,queryProlog):
  137.                     yield i
  138.             else:
  139.                 for i in unRollTripleItems(item,queryProlog):
  140.                     yield item
  141.  
  142. def mapToOperator(expr,prolog,combinationArg=None):
  143.     """
  144.     Reduces certain expressions (operator expressions, function calls, terms, and combinator expressions)
  145.     into strings of their Python equivalent
  146.     """
  147.     combinationInvokation = combinationArg and '(%s)'%combinationArg or ""
  148.     if isinstance(expr,ListRedirect):
  149.         expr = expr.reduce()
  150.     if isinstance(expr,UnaryOperator):
  151.         return UnaryOperatorMapping[type(expr)]%(mapToOperator(expr.argument,prolog,combinationArg))
  152.     elif isinstance(expr,BinaryOperator):
  153.         return BinaryOperatorMapping[type(expr)]%(mapToOperator(expr.left,prolog,combinationArg),mapToOperator(expr.right,prolog,combinationArg),combinationInvokation)
  154.     elif isinstance(expr,(Variable,Unbound)):
  155.         return '"%s"'%expr
  156.     elif isinstance(expr,ParsedREGEXInvocation):
  157.         return 'sparqlOperators.regex(%s,%s%s)%s'%(mapToOperator(expr.arg1,prolog,combinationArg),
  158.                                                  mapToOperator(expr.arg2,prolog,combinationArg),
  159.                                                  expr.arg3 and ',"'+expr.arg3 + '"' or '',
  160.                                                  combinationInvokation)
  161.     elif isinstance(expr,BuiltinFunctionCall):
  162.         normBuiltInName = FUNCTION_NAMES[expr.name].lower()
  163.         normBuiltInName = CAMEL_CASE_BUILTINS.get(normBuiltInName,'sparqlOperators.'+normBuiltInName)
  164.         return "%s(%s)%s"%(normBuiltInName,",".join([mapToOperator(i,prolog,combinationArg) for i in expr.arguments]),combinationInvokation)
  165.     elif isinstance(expr,Literal):
  166.         return str(expr)
  167.     elif isinstance(expr,URIRef):
  168.         import warnings
  169.         warnings.warn("There is the possibility of __repr__ being deprecated in python3K",DeprecationWarning,stacklevel=3)        
  170.         return repr(expr)    
  171.     elif isinstance(expr,(QName,basestring)):
  172.         return "'%s'"%convertTerm(expr,prolog)
  173.     elif isinstance(expr,ParsedAdditiveExpressionList):
  174.         return 'Literal(%s)'%(sparqlOperators.addOperator([mapToOperator(item,prolog,combinationArg='i') for item in expr],combinationArg))
  175.     elif isinstance(expr,FunctionCall):
  176.         if isinstance(expr.name,QName):
  177.             fUri = convertTerm(expr.name,prolog)
  178.         if fUri in XSDToPython:
  179.             return "sparqlOperators.XSDCast(%s,'%s')%s"%(mapToOperator(expr.arguments[0],prolog,combinationArg='i'),fUri,combinationInvokation)
  180.         raise Exception("Whats do i do with %s (a %s)?"%(expr,type(expr).__name__))
  181.     else:
  182.         if isinstance(expr,ListRedirect):
  183.             expr = expr.reduce()
  184.             if expr.pyBooleanOperator:
  185.                 return expr.pyBooleanOperator.join([mapToOperator(i,prolog) for i in expr]) 
  186.         raise Exception("What do i do with %s (a %s)?"%(expr,type(expr).__name__))
  187.  
  188. def createSPARQLPConstraint(filter,prolog):
  189.     """
  190.     Takes an instance of either ParsedExpressionFilter or ParsedFunctionFilter
  191.     and converts it to a sparql-p operator by composing a python string of lambda functions and SPARQL operators
  192.     This string is then evaluated to return the actual function for sparql-p
  193.     """
  194.     reducedFilter = isinstance(filter.filter,ListRedirect) and filter.filter.reduce() or filter.filter
  195.     if isinstance(reducedFilter,ParsedConditionalAndExpressionList):
  196.         combinationLambda = 'lambda(i): %s'%(' or '.join(['%s'%mapToOperator(expr,prolog,combinationArg='i') for expr in reducedFilter]))
  197.         if prolog.DEBUG:
  198.             print "sparql-p operator(s): %s"%combinationLambda
  199.         return eval(combinationLambda)
  200.     elif isinstance(reducedFilter,ParsedRelationalExpressionList):
  201.         combinationLambda = 'lambda(i): %s'%(' and '.join(['%s'%mapToOperator(expr,prolog,combinationArg='i') for expr in reducedFilter]))
  202.         if prolog.DEBUG:
  203.             print "sparql-p operator(s): %s"%combinationLambda
  204.         return eval(combinationLambda)
  205.     elif isinstance(reducedFilter,BuiltinFunctionCall):
  206.         rt=mapToOperator(reducedFilter,prolog)
  207.         if prolog.DEBUG:
  208.             print "sparql-p operator(s): %s"%rt
  209.         return eval(rt)
  210.     elif isinstance(reducedFilter,(ParsedAdditiveExpressionList,UnaryOperator,FunctionCall)):
  211.         rt='lambda(i): %s'%(mapToOperator(reducedFilter,prolog,combinationArg='i'))
  212.         if prolog.DEBUG:
  213.             print "sparql-p operator(s): %s"%rt
  214.         return eval(rt)
  215.     else:
  216.         rt=mapToOperator(reducedFilter,prolog)
  217.         if prolog.DEBUG:
  218.             print "sparql-p operator(s): %s"%rt
  219.         return eval(rt)
  220.  
  221. def sparqlPSetup(groupGraphPattern,prolog):
  222.     """
  223.     This core function takes Where Clause and two lists of rdflib.sparql.graphPattern.BasicGraphPatterns
  224.     (the main patterns - connected by UNION - and an optional patterns)
  225.     This is the core SELECT API of sparql-p
  226.     """
  227.     basicGraphPatterns = []
  228.     patternList = []
  229.     graphGraphPatterns,optionalGraphPatterns,alternativeGraphPatterns = categorizeGroupGraphPattern(groupGraphPattern)
  230.     globalTPs,globalConstraints = reorderBasicGraphPattern(groupGraphPattern[0])
  231.     #UNION alternative graph patterns
  232.     if alternativeGraphPatterns:
  233.         #Global constraints / optionals must be distributed within each alternative GP via:
  234.         #((P1 UNION P2) FILTER R) AND ((P1 FILTER R) UNION (P2 FILTER R)).
  235.         for alternativeGPBlock in alternativeGraphPatterns:
  236.             for alternativeGPs in alternativeGPBlock.nonTripleGraphPattern:
  237.                 triples,constraints = reorderBasicGraphPattern(alternativeGPs[0])
  238.                 constraints.extend(globalConstraints)
  239.                 alternativeGPInst = BasicGraphPattern([t for t in unRollTripleItems(triples,prolog)])
  240.                 alternativeGPInst.addConstraints([createSPARQLPConstraint(constr,prolog) for constr in constraints])
  241.                 basicGraphPatterns.append(alternativeGPInst)
  242.     elif graphGraphPatterns:
  243.         triples,constraints = reorderBasicGraphPattern(graphGraphPatterns[0].nonTripleGraphPattern[0])
  244.         for t in unRollTripleItems(triples,prolog):
  245.             patternList.append(t)
  246.         basicGraphPattern = BasicGraphPattern(patternList)
  247.         for constr in constraints:
  248.             basicGraphPattern.addConstraint(createSPARQLPConstraint(constr,prolog))
  249.         basicGraphPatterns.append(basicGraphPattern)
  250.     else:
  251.         triples,constraints = reorderBasicGraphPattern(groupGraphPattern[0])
  252.         for t in unRollTripleItems(triples,prolog):
  253.             patternList.append(t)
  254.         basicGraphPattern = BasicGraphPattern(patternList)
  255.         for constr in constraints:
  256.             basicGraphPattern.addConstraint(createSPARQLPConstraint(constr,prolog))
  257.         basicGraphPatterns.append(basicGraphPattern)
  258.  
  259.     #Global optional patterns
  260.     rtOptionalGraphPatterns = []
  261.     for opGGP in [g.nonTripleGraphPattern for g in optionalGraphPatterns]:
  262.         opTriples,opConstraints = reorderBasicGraphPattern(opGGP[0])
  263.         #FIXME how do deal with data/local-constr/expr-2.rq?
  264.         #opConstraints.extend(globalConstraints)
  265.         opPatternList = []
  266.         for t in unRollTripleItems(opTriples,prolog):
  267.             opPatternList.append(t)
  268.         opBasicGraphPattern = BasicGraphPattern(opPatternList)
  269.         for constr in opConstraints:# + constraints:
  270.             opBasicGraphPattern.addConstraint(createSPARQLPConstraint(constr,prolog))
  271.             
  272.         rtOptionalGraphPatterns.append(opBasicGraphPattern)
  273.     return basicGraphPatterns,rtOptionalGraphPatterns
  274.  
  275. def isTriplePattern(nestedTriples):
  276.     """
  277.     Determines (recursively) if the BasicGraphPattern contains any Triple Patterns
  278.     returning a boolean flag indicating if it does or not
  279.     """
  280.     if isinstance(nestedTriples,list):
  281.         for i in nestedTriples:
  282.             if isTriplePattern(i):
  283.                 return True
  284.             return False
  285.     elif isinstance(nestedTriples,ParsedConstrainedTriples):
  286.         if nestedTriples.triples:
  287.             return isTriplePattern(nestedTriples.triples)
  288.         else:
  289.             return False
  290.     elif isinstance(nestedTriples,ParsedConstrainedTriples) and not nestedTriples.triples:
  291.         return isTriplePattern(nestedTriples.triples)
  292.     else:
  293.         return True
  294.  
  295. def categorizeGroupGraphPattern(gGP):
  296.     """
  297.     Breaks down a ParsedGroupGraphPattern into mutually exclusive sets of
  298.     ParsedGraphGraphPattern, ParsedOptionalGraphPattern, and ParsedAlternativeGraphPattern units
  299.     """
  300.     assert isinstance(gGP,ParsedGroupGraphPattern), "%s is not a ParsedGroupGraphPattern"%gGP
  301.     graphGraphPatterns       = [gP for gP in gGP if gP.nonTripleGraphPattern and isinstance(gP.nonTripleGraphPattern,ParsedGraphGraphPattern)]
  302.     optionalGraphPatterns    = [gP for gP in gGP if gP.nonTripleGraphPattern and isinstance(gP.nonTripleGraphPattern,ParsedOptionalGraphPattern)]
  303.     alternativeGraphPatterns = [gP for gP in gGP if gP.nonTripleGraphPattern and isinstance(gP.nonTripleGraphPattern,ParsedAlternativeGraphPattern)]
  304.     return graphGraphPatterns,optionalGraphPatterns,alternativeGraphPatterns
  305.  
  306. def validateGroupGraphPattern(gGP,noNesting = False):
  307.     """
  308.     Verifies (recursively) that the Group Graph Pattern is supported
  309.     """
  310.     firstGP = gGP[0]
  311.     graphGraphPatternNo,optionalGraphPatternNo,alternativeGraphPatternNo = [len(gGPKlass) for gGPKlass in categorizeGroupGraphPattern(gGP)]
  312.     if firstGP.triples and isTriplePattern(firstGP.triples) and  isinstance(firstGP.nonTripleGraphPattern,ParsedAlternativeGraphPattern):
  313.         raise NotImplemented(UNION_GRAPH_PATTERN_NOT_SUPPORTED,"%s"%firstGP)
  314.     elif graphGraphPatternNo > 1 or graphGraphPatternNo and alternativeGraphPatternNo:
  315.         raise NotImplemented(GRAPH_GRAPH_PATTERN_NOT_SUPPORTED,"%s"%gGP)
  316.     for gP in gGP:
  317.         if noNesting and isinstance(gP.nonTripleGraphPattern,(ParsedOptionalGraphPattern,ParsedGraphGraphPattern,ParsedAlternativeGraphPattern)):
  318.             raise NotImplemented(GROUP_GRAPH_PATTERN_NESTING_NOT_SUPPORTED,"%s"%gGP)
  319.         if isinstance(gP.nonTripleGraphPattern,ParsedAlternativeGraphPattern):
  320.             for _gGP in gP.nonTripleGraphPattern:
  321.                 validateGroupGraphPattern(_gGP,noNesting = True)
  322.         elif gP.nonTripleGraphPattern:
  323.             validateGroupGraphPattern(gP.nonTripleGraphPattern,noNesting = True)
  324.  
  325. def Evaluate(graph,query,passedBindings = {},DEBUG = False):
  326.     """
  327.     Takes:
  328.         1. a rdflib.Graph.Graph instance 
  329.         2. a SPARQL query instance (parsed using the BisonGen parser)
  330.         3. A dictionary of initial variable bindings (varName -> .. rdflib Term .. )
  331.         4. DEBUG Flag
  332.  
  333.     Returns a list of tuples - each a binding of the selected variables in query order
  334.     """
  335.     if query.prolog:
  336.         query.prolog.DEBUG = DEBUG    
  337.     if query.query.dataSets:
  338.         graphs = []
  339.         for dtSet in query.query.dataSets:
  340.             if isinstance(dtSet,NamedGraph):
  341.                 graphs.append(Graph(graph.store,dtSet))
  342.             else:
  343.                 memStore = plugin.get('IOMemory',Store)()
  344.                 memGraph = Graph(memStore)
  345.                 try:
  346.                     memGraph.parse(dtSet,format='n3')
  347.                 except:
  348.                     #Parse as RDF/XML instead
  349.                     memGraph.parse(dtSet)
  350.                 graphs.append(memGraph)
  351.         tripleStore = sparqlGraph.SPARQLGraph(ReadOnlyGraphAggregate(graphs))
  352.     else:        
  353.         tripleStore = sparqlGraph.SPARQLGraph(graph)    
  354.  
  355.     if isinstance(query.query,SelectQuery) and query.query.variables:
  356.         query.query.variables = [convertTerm(item,query.prolog) for item in query.query.variables]
  357.     else:
  358.         query.query.variables = []
  359.  
  360.     #Interpret Graph Graph Patterns as Named Graphs
  361.     graphGraphPatterns = categorizeGroupGraphPattern(query.query.whereClause.parsedGraphPattern)[0]
  362. #    rt = categorizeGroupGraphPattern(query.query.whereClause.parsedGraphPattern)[0]
  363. #    print rt[0], rt[1]
  364.     if graphGraphPatterns:
  365.         graphGraphP = graphGraphPatterns[0].nonTripleGraphPattern
  366.         if isinstance(graphGraphP.name,Variable):
  367.             if graphGraphP.name in passedBindings:
  368.                 tripleStore = sparqlGraph.SPARQLGraph(Graph(graph.store,passedBindings[graphGraphP.name]))
  369.             else: 
  370.                 #print graphGraphP 
  371.                 #raise Exception("Graph Graph Patterns can only be used with variables bound at the top level or a URIRef or BNode term")
  372.                 tripleStore = sparqlGraph.SPARQLGraph(graph,graphVariable = graphGraphP.name)
  373.         else:
  374.             graphName =  isinstance(graphGraphP.name,Variable) and passedBindings[graphGraphP.name] or graphGraphP.name
  375.             graphName  = convertTerm(graphName,query.prolog)
  376.             if isinstance(graph,ReadOnlyGraphAggregate) and not graph.store:
  377.                 targetGraph = [g for g in graph.graphs if g.identifier == graphName]
  378.                 assert len(targetGraph) == 1
  379.                 targetGraph = targetGraph[0]
  380.             else:
  381.                 targetGraph = Graph(graph.store,graphName)
  382.             tripleStore = sparqlGraph.SPARQLGraph(targetGraph)
  383.  
  384.     gp = reorderGroupGraphPattern(query.query.whereClause.parsedGraphPattern)
  385.     validateGroupGraphPattern(gp)
  386.     basicPatterns,optionalPatterns = sparqlPSetup(gp,query.prolog)
  387.  
  388.     if DEBUG:
  389.         print "## Select Variables ##\n",query.query.variables
  390.         print "## Patterns ##\n",basicPatterns
  391.         print "## OptionalPatterns ##\n",optionalPatterns
  392.  
  393.     result = queryObject(tripleStore, basicPatterns,optionalPatterns,passedBindings)
  394.     if result == None :
  395.         # generate some proper output for the exception :-)
  396.         msg = "Errors in the patterns, no valid query object generated; "
  397.         msg += ("pattern:\n%s\netc..." % basicPatterns[0])
  398.         raise SPARQLError(msg)
  399.  
  400.     if isinstance(query.query,AskQuery):
  401.         return result.ask()
  402.  
  403.     elif isinstance(query.query,SelectQuery):
  404.         orderBy = None
  405.         orderAsc = None
  406.         if query.query.solutionModifier.orderClause:
  407.             orderBy     = []
  408.             orderAsc    = []
  409.             for orderCond in query.query.solutionModifier.orderClause:
  410.                 # is it a variable?
  411.                 if isinstance(orderCond,Variable):
  412.                     orderBy.append(orderCond)
  413.                     orderAsc.append(ASCENDING_ORDER)
  414.                 # is it another expression, only variables are supported
  415.                 else:
  416.                     expr = orderCond.expression
  417.                     assert isinstance(expr,Variable),"Support for ORDER BY with anything other than a variable is not supported: %s"%expr
  418.                     orderBy.append(expr)                    
  419.                     orderAsc.append(orderCond.order == ASCENDING_ORDER)
  420.  
  421.         limit = query.query.solutionModifier.limitClause and int(query.query.solutionModifier.limitClause) or None
  422.  
  423.         offset = query.query.solutionModifier.offsetClause and int(query.query.solutionModifier.offsetClause) or 0
  424.         return result.select(query.query.variables,
  425.                              query.query.distinct,
  426.                              limit,
  427.                              orderBy,
  428.                              orderAsc,
  429.                              offset
  430.                              ),_variablesToArray(query.query.variables,"selection"),result._getAllVariables(),orderBy,query.query.distinct
  431.     else:
  432.         raise NotImplemented(CONSTRUCT_NOT_SUPPORTED,repr(query))
  433.  
  434. OPTIONALS_NOT_SUPPORTED                   = 1
  435. #GRAPH_PATTERN_NOT_SUPPORTED               = 2
  436. UNION_GRAPH_PATTERN_NOT_SUPPORTED         = 3
  437. GRAPH_GRAPH_PATTERN_NOT_SUPPORTED         = 4
  438. GROUP_GRAPH_PATTERN_NESTING_NOT_SUPPORTED = 5
  439. CONSTRUCT_NOT_SUPPORTED                   = 6
  440.  
  441. ExceptionMessages = {
  442.     OPTIONALS_NOT_SUPPORTED                   : 'Nested OPTIONAL not currently supported',
  443.     #GRAPH_PATTERN_NOT_SUPPORTED               : 'Graph Pattern not currently supported',
  444.     UNION_GRAPH_PATTERN_NOT_SUPPORTED         : 'UNION Graph Pattern (currently) can only be combined with OPTIONAL Graph Patterns',
  445.     GRAPH_GRAPH_PATTERN_NOT_SUPPORTED         : 'Graph Graph Pattern (currently) cannot only be used once by themselves or with OPTIONAL Graph Patterns',
  446.     GROUP_GRAPH_PATTERN_NESTING_NOT_SUPPORTED : 'Nesting of Group Graph Pattern (currently) not supported',
  447.     CONSTRUCT_NOT_SUPPORTED                   : '"Construct" is not (currently) supported',
  448. }
  449.  
  450.  
  451. class NotImplemented(Exception):
  452.     def __init__(self,code,msg):
  453.         self.code = code
  454.         self.msg = msg
  455.     def __str__(self):
  456.         return ExceptionMessages[self.code] + ' :' + self.msg
  457.