'''
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
'''
from aenum import Enum
from .. import statics
from ..statics import long
[docs]class Traversal(object):
def __init__(self, graph, traversal_strategies, bytecode):
self.graph = graph
self.traversal_strategies = traversal_strategies
self.bytecode = bytecode
self.side_effects = TraversalSideEffects()
self.traversers = None
self.last_traverser = None
def __repr__(self):
return str(self.bytecode)
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.bytecode == other.bytecode
else:
return False
def __iter__(self):
return self
def __next__(self):
if self.traversers is None:
self.traversal_strategies.apply_strategies(self)
if self.last_traverser is None:
self.last_traverser = next(self.traversers)
object = self.last_traverser.object
self.last_traverser.bulk = self.last_traverser.bulk - 1
if self.last_traverser.bulk <= 0:
self.last_traverser = None
return object
def toList(self):
return list(iter(self))
def toSet(self):
return set(iter(self))
def iterate(self):
while True:
try: self.nextTraverser()
except StopIteration: return self
def nextTraverser(self):
if self.traversers is None:
self.traversal_strategies.apply_strategies(self)
if self.last_traverser is None:
return next(self.traversers)
else:
temp = self.last_traverser
self.last_traverser = None
return temp
def next(self, amount=None):
if amount is None:
return self.__next__()
else:
count = 0
tempList = []
while count < amount:
count = count + 1
try: temp = self.__next__()
except StopIteration: return tempList
tempList.append(temp)
return tempList
def promise(self, cb=None):
self.traversal_strategies.apply_async_strategies(self)
future_traversal = self.remote_results
future = type(future_traversal)()
def process(f):
try:
traversal = f.result()
except Exception as e:
future.set_exception(e)
else:
self.traversers = iter(traversal.traversers)
self.side_effects = traversal.side_effects
if cb:
try:
result = cb(self)
except Exception as e:
future.set_exception(e)
else:
future.set_result(result)
else:
future.set_result(self)
future_traversal.add_done_callback(process)
return future
Barrier = Enum('Barrier', ' normSack')
statics.add_static('normSack', Barrier.normSack)
Cardinality = Enum('Cardinality', ' list_ set_ single')
statics.add_static('single', Cardinality.single)
statics.add_static('list_', Cardinality.list_)
statics.add_static('set_', Cardinality.set_)
Column = Enum('Column', ' keys values')
statics.add_static('keys', Column.keys)
statics.add_static('values', Column.values)
Direction = Enum('Direction', ' BOTH IN OUT')
statics.add_static('OUT', Direction.OUT)
statics.add_static('IN', Direction.IN)
statics.add_static('BOTH', Direction.BOTH)
GraphSONVersion = Enum('GraphSONVersion', ' V1_0 V2_0 V3_0')
statics.add_static('V1_0', GraphSONVersion.V1_0)
statics.add_static('V2_0', GraphSONVersion.V2_0)
statics.add_static('V3_0', GraphSONVersion.V3_0)
GryoVersion = Enum('GryoVersion', ' V1_0 V3_0')
statics.add_static('V1_0', GryoVersion.V1_0)
statics.add_static('V3_0', GryoVersion.V3_0)
Operator = Enum('Operator', ' addAll and_ assign div max min minus mult or_ sum sumLong')
statics.add_static('sum', Operator.sum)
statics.add_static('minus', Operator.minus)
statics.add_static('mult', Operator.mult)
statics.add_static('div', Operator.div)
statics.add_static('min', Operator.min)
statics.add_static('max', Operator.max)
statics.add_static('assign', Operator.assign)
statics.add_static('and_', Operator.and_)
statics.add_static('or_', Operator.or_)
statics.add_static('addAll', Operator.addAll)
statics.add_static('sumLong', Operator.sumLong)
Order = Enum('Order', ' decr incr shuffle')
statics.add_static('incr', Order.incr)
statics.add_static('decr', Order.decr)
statics.add_static('shuffle', Order.shuffle)
Pick = Enum('Pick', ' any none')
statics.add_static('any', Pick.any)
statics.add_static('none', Pick.none)
Pop = Enum('Pop', ' all_ first last mixed')
statics.add_static('first', Pop.first)
statics.add_static('last', Pop.last)
statics.add_static('all_', Pop.all_)
statics.add_static('mixed', Pop.mixed)
Scope = Enum('Scope', ' global_ local')
statics.add_static('global_', Scope.global_)
statics.add_static('local', Scope.local)
T = Enum('T', ' id key label value')
statics.add_static('label', T.label)
statics.add_static('id', T.id)
statics.add_static('key', T.key)
statics.add_static('value', T.value)
class P(object):
def __init__(self, operator, value, other=None):
self.operator = operator
self.value = value
self.other = other
@staticmethod
def between(*args):
return P("between", *args)
@staticmethod
def eq(*args):
return P("eq", *args)
@staticmethod
def gt(*args):
return P("gt", *args)
@staticmethod
def gte(*args):
return P("gte", *args)
@staticmethod
def inside(*args):
return P("inside", *args)
@staticmethod
def lt(*args):
return P("lt", *args)
@staticmethod
def lte(*args):
return P("lte", *args)
@staticmethod
def neq(*args):
return P("neq", *args)
@staticmethod
def not_(*args):
return P("not_", *args)
@staticmethod
def outside(*args):
return P("outside", *args)
@staticmethod
def test(*args):
return P("test", *args)
@staticmethod
def within(*args):
return P("within", *args)
@staticmethod
def without(*args):
return P("without", *args)
def and_(self, arg):
return P("and", self, arg)
def or_(self, arg):
return P("or", self, arg)
def __eq__(self, other):
return isinstance(other, self.__class__) and self.operator == other.operator and self.value == other.value and self.other == other.other
def __repr__(self):
return self.operator + "(" + str(self.value) + ")" if self.other is None else self.operator + "(" + str(self.value) + "," + str(self.other) + ")"
def and_(self, arg):
return P("and", self, arg)
def or_(self, arg):
return P("or", self, arg)
def __eq__(self, other):
return isinstance(other, self.__class__) and self.operator == other.operator and self.value == other.value and self.other == other.other
def __repr__(self):
return self.operator + "(" + str(self.value) + ")" if self.other is None else self.operator + "(" + str(self.value) + "," + str(self.other) + ")"
def between(*args):
return P.between(*args)
statics.add_static('between',between)
def eq(*args):
return P.eq(*args)
statics.add_static('eq',eq)
def gt(*args):
return P.gt(*args)
statics.add_static('gt',gt)
def gte(*args):
return P.gte(*args)
statics.add_static('gte',gte)
def inside(*args):
return P.inside(*args)
statics.add_static('inside',inside)
def lt(*args):
return P.lt(*args)
statics.add_static('lt',lt)
def lte(*args):
return P.lte(*args)
statics.add_static('lte',lte)
def neq(*args):
return P.neq(*args)
statics.add_static('neq',neq)
def not_(*args):
return P.not_(*args)
statics.add_static('not_',not_)
def outside(*args):
return P.outside(*args)
statics.add_static('outside',outside)
def test(*args):
return P.test(*args)
statics.add_static('test',test)
def within(*args):
return P.within(*args)
statics.add_static('within',within)
def without(*args):
return P.without(*args)
statics.add_static('without',without)
'''
TRAVERSER
'''
class Traverser(object):
def __init__(self, object, bulk=None):
if bulk is None:
bulk = long(1)
self.object = object
self.bulk = bulk
def __repr__(self):
return str(self.object)
def __eq__(self, other):
return isinstance(other, self.__class__) and self.object == other.object
'''
TRAVERSAL SIDE-EFFECTS
'''
[docs]class TraversalSideEffects(object):
def keys(self):
return set()
def get(self, key):
raise KeyError(key)
def __getitem__(self, key):
return self.get(key)
def __repr__(self):
return "sideEffects[size:" + str(len(self.keys())) + "]"
'''
TRAVERSAL STRATEGIES
'''
[docs]class TraversalStrategies(object):
global_cache = {}
def __init__(self, traversal_strategies=None):
self.traversal_strategies = traversal_strategies.traversal_strategies if traversal_strategies is not None else []
def add_strategies(self, traversal_strategies):
self.traversal_strategies = self.traversal_strategies + traversal_strategies
def apply_strategies(self, traversal):
for traversal_strategy in self.traversal_strategies:
traversal_strategy.apply(traversal)
def apply_async_strategies(self, traversal):
for traversal_strategy in self.traversal_strategies:
traversal_strategy.apply_async(traversal)
def __repr__(self):
return str(self.traversal_strategies)
class TraversalStrategy(object):
def __init__(self, strategy_name=None, configuration=None):
self.strategy_name = type(self).__name__ if strategy_name is None else strategy_name
self.configuration = {} if configuration is None else configuration
def apply(self, traversal):
return
def apply_async(self, traversal):
return
def __eq__(self, other):
return isinstance(other, self.__class__)
def __hash__(self):
return hash(self.strategy_name)
def __repr__(self):
return self.strategy_name
'''
BYTECODE
'''
[docs]class Bytecode(object):
def __init__(self, bytecode=None):
self.source_instructions = []
self.step_instructions = []
self.bindings = {}
if bytecode is not None:
self.source_instructions = list(bytecode.source_instructions)
self.step_instructions = list(bytecode.step_instructions)
def add_source(self, source_name, *args):
instruction = [source_name]
for arg in args:
instruction.append(self.__convertArgument(arg))
self.source_instructions.append(instruction)
def add_step(self, step_name, *args):
instruction = [step_name]
for arg in args:
instruction.append(self.__convertArgument(arg))
self.step_instructions.append(instruction)
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.source_instructions == other.source_instructions and self.step_instructions == other.step_instructions
else:
return False
def __convertArgument(self,arg):
if isinstance(arg, Traversal):
self.bindings.update(arg.bytecode.bindings)
return arg.bytecode
elif isinstance(arg, dict):
newDict = {}
for key in arg:
newDict[self.__convertArgument(key)] = self.__convertArgument(arg[key])
return newDict
elif isinstance(arg, list):
newList = []
for item in arg:
newList.append(self.__convertArgument(item))
return newList
elif isinstance(arg, set):
newSet = set()
for item in arg:
newSet.add(self.__convertArgument(item))
return newSet
elif isinstance(arg, tuple) and 2 == len(arg) and isinstance(arg[0], str):
self.bindings[arg[0]] = arg[1]
return Binding(arg[0],self.__convertArgument(arg[1]))
else:
return arg
def __repr__(self):
return (str(self.source_instructions) if len(self.source_instructions) > 0 else "") + \
(str(self.step_instructions) if len(self.step_instructions) > 0 else "")
'''
BINDINGS
'''
class Bindings(object):
def of(self,key,value):
if not isinstance(key, str):
raise TypeError("Key must be str")
return (key,value)
class Binding(object):
def __init__(self,key,value):
self.key = key
self.value = value
def __eq__(self, other):
return isinstance(other, self.__class__) and self.key == other.key and self.value == other.value
def __hash__(self):
return hash(self.key) + hash(self.value)
def __repr__(self):
return "binding[" + self.key + "=" + str(self.value) + "]"