| # |
| # 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. |
| # |
| |
| import copy |
| import math |
| import threading |
| import uuid |
| import warnings |
| |
| from aenum import Enum |
| from gremlin_python.structure.graph import Vertex, Edge, Path, Property |
| |
| from .. import statics |
| from ..statics import long, SingleByte, short, bigint, BigDecimal |
| from datetime import datetime |
| |
| |
| class Traversal(object): |
| def __init__(self, graph, traversal_strategies, gremlin_lang): |
| self.graph = graph |
| self.traversal_strategies = traversal_strategies |
| self.gremlin_lang = gremlin_lang |
| self.traversers = None |
| self.last_traverser = None |
| |
| def __repr__(self): |
| return self.gremlin_lang.get_gremlin() |
| |
| def __eq__(self, other): |
| if isinstance(other, self.__class__): |
| return self.gremlin_lang.get_gremlin() == other.gremlin_lang.get_gremlin() |
| 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) |
| res = self.last_traverser |
| if isinstance(res, Traverser): |
| obj = res.object |
| self.last_traverser.bulk = self.last_traverser.bulk - 1 |
| if self.last_traverser.bulk <= 0: |
| self.last_traverser = None |
| return obj |
| else: |
| self.last_traverser = None |
| return res |
| |
| def toList(self): |
| warnings.warn( |
| "gremlin_python.process.Traversal.toList will be replaced by " |
| "gremlin_python.process.Traversal.to_list.", |
| DeprecationWarning) |
| return self.to_list() |
| |
| def to_list(self): |
| return list(iter(self)) |
| |
| def toSet(self): |
| warnings.warn( |
| "gremlin_python.process.Traversal.toSet will be replaced by " |
| "gremlin_python.process.Traversal.to_set.", |
| DeprecationWarning) |
| return self.to_set() |
| |
| def to_set(self): |
| return set(iter(self)) |
| |
| def iterate(self): |
| self.gremlin_lang.add_step("discard") |
| while True: |
| try: |
| self.next_traverser() |
| except StopIteration: |
| return self |
| |
| def nextTraverser(self): |
| warnings.warn( |
| "gremlin_python.process.Traversal.nextTraverser will be replaced by " |
| "gremlin_python.process.Traversal.next_traverser.", |
| DeprecationWarning) |
| return self.next_traverser() |
| |
| def next_traverser(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 hasNext(self): |
| warnings.warn( |
| "gremlin_python.process.Traversal.hasNext will be replaced by " |
| "gremlin_python.process.Traversal.has_next.", |
| DeprecationWarning) |
| return self.has_next() |
| |
| def has_next(self): |
| if self.traversers is None: |
| self.traversal_strategies.apply_strategies(self) |
| if self.last_traverser is None: |
| try: |
| self.last_traverser = next(self.traversers) |
| except StopIteration: |
| return False |
| return not (self.last_traverser is None) and self.last_traverser.bulk > 0 if isinstance(self.last_traverser, Traverser) else True |
| |
| 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) |
| 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 norm_sack') |
| |
| statics.add_static('normSack', Barrier.normSack) |
| statics.add_static('norm_sack', Barrier.norm_sack) |
| |
| 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) |
| |
| # alias from_ and to |
| Direction = Enum( |
| value='Direction', |
| names=[ |
| ('BOTH', 'BOTH'), |
| ('IN', 'IN'), |
| ('OUT', 'OUT'), |
| ('from_', "OUT"), |
| ('to', 'IN'), |
| ], |
| ) |
| |
| statics.add_static('OUT', Direction.OUT) |
| statics.add_static('IN', Direction.IN) |
| statics.add_static('BOTH', Direction.BOTH) |
| statics.add_static('from_', Direction.OUT) |
| statics.add_static('to', Direction.IN) |
| |
| DT = Enum('DT', ' second minute hour day') |
| |
| statics.add_static('second', DT.second) |
| statics.add_static('minute', DT.minute) |
| statics.add_static('hour', DT.hour) |
| statics.add_static('day', DT.day) |
| |
| Merge = Enum('Merge', ' on_create on_match out_v in_v') |
| |
| statics.add_static('on_create', Merge.on_create) |
| statics.add_static('on_match', Merge.on_match) |
| statics.add_static('in_v', Merge.in_v) |
| statics.add_static('out_v', Merge.out_v) |
| |
| Order = Enum('Order', ' asc desc shuffle') |
| |
| statics.add_static('shuffle', Order.shuffle) |
| statics.add_static('asc', Order.asc) |
| statics.add_static('desc', Order.desc) |
| |
| Pick = Enum('Pick', ' any_ none unproductive') |
| |
| statics.add_static('any_', Pick.any_) |
| statics.add_static('none', Pick.none) |
| statics.add_static('unproductive', Pick.unproductive) |
| |
| 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 id_ key label value') |
| |
| statics.add_static('id', T.id) |
| statics.add_static('label', T.label) |
| statics.add_static('id_', T.id_) |
| statics.add_static('key', T.key) |
| statics.add_static('value', T.value) |
| |
| Operator = Enum('Operator', ' addAll add_all and_ assign div max max_ min min_ minus mult or_ sum_ sumLong sum_long') |
| |
| 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('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('add_all', Operator.add_all) |
| statics.add_static('sum_long', Operator.sum_long) |
| |
| |
| GType = Enum('GType', ' BIGDECIMAL BIGINT BINARY BOOLEAN BYTE CHAR DATETIME DOUBLE DURATION EDGE FLOAT GRAPH INT LIST LONG MAP NULL NUMBER PATH PROPERTY SET SHORT STRING TREE UUID VERTEX VPROPERTY') |
| |
| statics.add_static('BIGDECIMAL', GType.BIGDECIMAL) |
| statics.add_static('BIGINT', GType.BIGINT) |
| statics.add_static('BINARY', GType.BINARY) |
| statics.add_static('BOOLEAN', GType.BOOLEAN) |
| statics.add_static('BYTE', GType.BYTE) |
| statics.add_static('CHAR', GType.CHAR) |
| statics.add_static('DATETIME', GType.DATETIME) |
| statics.add_static('DOUBLE', GType.DOUBLE) |
| statics.add_static('DURATION', GType.DURATION) |
| statics.add_static('EDGE', GType.EDGE) |
| statics.add_static('FLOAT', GType.FLOAT) |
| statics.add_static('GRAPH', GType.GRAPH) |
| statics.add_static('INT', GType.INT) |
| statics.add_static('LIST', GType.LIST) |
| statics.add_static('LONG', GType.LONG) |
| statics.add_static('MAP', GType.MAP) |
| statics.add_static('NULL', GType.NULL) |
| statics.add_static('NUMBER', GType.NUMBER) |
| statics.add_static('PATH', GType.PATH) |
| statics.add_static('PROPERTY', GType.PROPERTY) |
| statics.add_static('SET', GType.SET) |
| statics.add_static('SHORT', GType.SHORT) |
| statics.add_static('STRING', GType.STRING) |
| statics.add_static('TREE', GType.TREE) |
| statics.add_static('UUID', GType.UUID) |
| statics.add_static('VERTEX', GType.VERTEX) |
| statics.add_static('VPROPERTY', GType.VPROPERTY) |
| |
| |
| 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 type_of(*args): |
| return P("typeOf", *args) |
| |
| @staticmethod |
| def within(*args): |
| if len(args) == 1 and type(args[0]) == list: |
| return P("within", args[0]) |
| elif len(args) == 1 and type(args[0]) == set: |
| return P("within", list(args[0])) |
| else: |
| return P("within", list(args)) |
| |
| @staticmethod |
| def without(*args): |
| if len(args) == 1 and type(args[0]) == list: |
| return P("without", args[0]) |
| elif len(args) == 1 and type(args[0]) == set: |
| return P("without", list(args[0])) |
| else: |
| return P("without", list(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 between(*args): |
| return P.between(*args) |
| |
| |
| def eq(*args): |
| return P.eq(*args) |
| |
| |
| def gt(*args): |
| return P.gt(*args) |
| |
| |
| def gte(*args): |
| return P.gte(*args) |
| |
| |
| def inside(*args): |
| return P.inside(*args) |
| |
| |
| def lt(*args): |
| return P.lt(*args) |
| |
| |
| def lte(*args): |
| return P.lte(*args) |
| |
| |
| def neq(*args): |
| return P.neq(*args) |
| |
| |
| def not_(*args): |
| return P.not_(*args) |
| |
| |
| def outside(*args): |
| return P.outside(*args) |
| |
| |
| def within(*args): |
| return P.within(*args) |
| |
| |
| def without(*args): |
| return P.without(*args) |
| |
| |
| def type_of(*args): |
| return P.type_of(*args) |
| |
| |
| statics.add_static('between', between) |
| |
| statics.add_static('eq', eq) |
| |
| statics.add_static('gt', gt) |
| |
| statics.add_static('gte', gte) |
| |
| statics.add_static('inside', inside) |
| |
| statics.add_static('lt', lt) |
| |
| statics.add_static('lte', lte) |
| |
| statics.add_static('neq', neq) |
| |
| statics.add_static('not_', not_) |
| |
| statics.add_static('outside', outside) |
| |
| statics.add_static('within', within) |
| |
| statics.add_static('without', without) |
| |
| statics.add_static('typeOf', type_of) |
| |
| |
| class TextP(P): |
| def __init__(self, operator, value, other=None): |
| P.__init__(self, operator, value, other) |
| |
| @staticmethod |
| def containing(*args): |
| return TextP("containing", *args) |
| |
| @staticmethod |
| def endingWith(*args): |
| warnings.warn( |
| "gremlin_python.process.TextP.endingWith will be replaced by " |
| "gremlin_python.process.TextP.ending_with.", |
| DeprecationWarning) |
| return TextP("endingWith", *args) |
| |
| @staticmethod |
| def ending_with(*args): |
| return TextP("endingWith", *args) |
| |
| @staticmethod |
| def notContaining(*args): |
| warnings.warn( |
| "gremlin_python.process.TextP.notContaining will be replaced by " |
| "gremlin_python.process.TextP.not_containing.", |
| DeprecationWarning) |
| return TextP("notContaining", *args) |
| |
| @staticmethod |
| def not_containing(*args): |
| return TextP("notContaining", *args) |
| |
| @staticmethod |
| def notEndingWith(*args): |
| warnings.warn( |
| "gremlin_python.process.TextP.notEndingWith will be replaced by " |
| "gremlin_python.process.TextP.not_ending_with.", |
| DeprecationWarning) |
| return TextP("notEndingWith", *args) |
| |
| @staticmethod |
| def not_ending_with(*args): |
| return TextP("notEndingWith", *args) |
| |
| @staticmethod |
| def notStartingWith(*args): |
| warnings.warn( |
| "gremlin_python.process.TextP.notStartingWith will be replaced by " |
| "gremlin_python.process.TextP.not_starting_With.", |
| DeprecationWarning) |
| return TextP("notStartingWith", *args) |
| |
| @staticmethod |
| def not_starting_with(*args): |
| return TextP("notStartingWith", *args) |
| |
| @staticmethod |
| def startingWith(*args): |
| warnings.warn( |
| "gremlin_python.process.TextP.startingWith will be replaced by " |
| "gremlin_python.process.TextP.startingWith.", |
| DeprecationWarning) |
| return TextP("startingWith", *args) |
| |
| @staticmethod |
| def starting_with(*args): |
| return TextP("startingWith", *args) |
| |
| @staticmethod |
| def regex(*args): |
| return TextP("regex", *args) |
| |
| @staticmethod |
| def not_regex(*args): |
| return TextP("notRegex", *args) |
| |
| 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 containing(*args): |
| return TextP.containing(*args) |
| |
| |
| def endingWith(*args): |
| return TextP.ending_with(*args) |
| |
| |
| def ending_with(*args): |
| return TextP.ending_with(*args) |
| |
| |
| def notContaining(*args): |
| return TextP.not_containing(*args) |
| |
| |
| def not_containing(*args): |
| return TextP.not_containing(*args) |
| |
| |
| def notEndingWith(*args): |
| return TextP.not_ending_with(*args) |
| |
| |
| def not_ending_with(*args): |
| return TextP.not_ending_with(*args) |
| |
| |
| def notStartingWith(*args): |
| return TextP.not_starting_with(*args) |
| |
| |
| def not_starting_with(*args): |
| return TextP.not_starting_with(*args) |
| |
| |
| def startingWith(*args): |
| return TextP.starting_with(*args) |
| |
| |
| def starting_with(*args): |
| return TextP.starting_with(*args) |
| |
| def regex(*args): |
| return TextP.regex(*args) |
| |
| def not_regex(*args): |
| return TextP.not_regex(*args) |
| |
| statics.add_static('containing', containing) |
| |
| statics.add_static('endingWith', endingWith) |
| |
| statics.add_static('ending_with', ending_with) |
| |
| statics.add_static('notContaining', notContaining) |
| |
| statics.add_static('not_containing', not_containing) |
| |
| statics.add_static('notEndingWith', notEndingWith) |
| |
| statics.add_static('not_ending_with', not_ending_with) |
| |
| statics.add_static('notStartingWith', notStartingWith) |
| |
| statics.add_static('not_starting_with', not_starting_with) |
| |
| statics.add_static('startingWith', startingWith) |
| |
| statics.add_static('starting_with', starting_with) |
| |
| statics.add_static('regex', regex) |
| |
| statics.add_static('not_regex', not_regex) |
| |
| ''' |
| IO |
| ''' |
| |
| |
| class IO(object): |
| graphml = "graphml" |
| |
| graphson = "graphson" |
| |
| gryo = "gryo" |
| |
| reader = "~tinkerpop.io.reader" |
| |
| registry = "~tinkerpop.io.registry" |
| |
| writer = "~tinkerpop.io.writer" |
| |
| |
| ''' |
| ConnectedComponent |
| ''' |
| |
| |
| class ConnectedComponent(object): |
| component = "gremlin.connectedComponentVertexProgram.component" |
| |
| edges = "~tinkerpop.connectedComponent.edges" |
| |
| propertyName = "~tinkerpop.connectedComponent.propertyName" |
| |
| property_name = "~tinkerpop.connectedComponent.propertyName" |
| |
| |
| ''' |
| ShortestPath |
| ''' |
| |
| |
| class ShortestPath(object): |
| distance = "~tinkerpop.shortestPath.distance" |
| |
| edges = "~tinkerpop.shortestPath.edges" |
| |
| includeEdges = "~tinkerpop.shortestPath.includeEdges" |
| |
| include_edges = "~tinkerpop.shortestPath.includeEdges" |
| |
| maxDistance = "~tinkerpop.shortestPath.maxDistance" |
| |
| max_distance = "~tinkerpop.shortestPath.maxDistance" |
| |
| target = "~tinkerpop.shortestPath.target" |
| |
| |
| ''' |
| PageRank |
| ''' |
| |
| |
| class PageRank(object): |
| edges = "~tinkerpop.pageRank.edges" |
| |
| propertyName = "~tinkerpop.pageRank.propertyName" |
| |
| property_name = "~tinkerpop.pageRank.propertyName" |
| |
| times = "~tinkerpop.pageRank.times" |
| |
| |
| ''' |
| PeerPressure |
| ''' |
| |
| |
| class PeerPressure(object): |
| edges = "~tinkerpop.peerPressure.edges" |
| |
| propertyName = "~tinkerpop.peerPressure.propertyName" |
| |
| property_name = "~tinkerpop.pageRank.propertyName" |
| |
| times = "~tinkerpop.peerPressure.times" |
| |
| |
| ''' |
| 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 STRATEGIES |
| ''' |
| |
| |
| class TraversalStrategies(object): |
| |
| 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, fqcn=None, **kwargs): |
| self.fqcn = fqcn |
| self.strategy_name = type(self).__name__ if strategy_name is None else strategy_name |
| self.configuration = {} if configuration is None else configuration |
| self.configuration = {**kwargs, **self.configuration} # merge additional kwargs into strategy 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 |
| |
| |
| ''' |
| WITH OPTIONS |
| ''' |
| |
| |
| class WithOptions(object): |
| tokens = "~tinkerpop.valueMap.tokens" |
| |
| none = 0 |
| |
| ids = 1 |
| |
| labels = 2 |
| |
| keys = 4 |
| |
| values = 8 |
| |
| all = 15 |
| |
| indexer = "~tinkerpop.index.indexer" |
| |
| list = 0 |
| |
| map = 1 |
| |
| |
| ''' |
| GREMLIN LANGUAGE |
| ''' |
| |
| |
| class GremlinLang(object): |
| conn_p = ['and', 'or'] |
| |
| def __init__(self, gremlin_lang=None): |
| self.empty_array = [] |
| |
| self.gremlin = [] |
| self.parameters = {} |
| self.options_strategies = [] |
| self.param_count = AtomicInteger() |
| |
| if gremlin_lang is not None: |
| self.gremlin = list(gremlin_lang.gremlin) |
| self.parameters = dict(gremlin_lang.parameters) |
| self.options_strategies = list(gremlin_lang.options_strategies) |
| self.param_count = gremlin_lang.param_count |
| |
| def _add_to_gremlin(self, string_name, *args): |
| |
| if string_name == 'CardinalityValueTraversal': |
| self.gremlin.append( |
| f'{self._arg_as_string(args[0][0])}({self._arg_as_string(args[0][1])})') |
| return |
| |
| self.gremlin.extend(['.', string_name, '(']) |
| |
| c = 0 |
| while len(args[0]) > c: |
| if c != 0: |
| self.gremlin.append(',') |
| self.gremlin.append(self._arg_as_string(self._convert_argument(args[0][c]))) |
| c += 1 |
| |
| self.gremlin.append(')') |
| |
| def _arg_as_string(self, arg): |
| |
| if arg is None: |
| return 'null' |
| |
| if isinstance(arg, str): |
| return f'{arg!r}' # use repr() format for canonical string rep |
| # return f'"{arg}"' |
| if isinstance(arg, bool): |
| return 'true' if arg else 'false' |
| |
| if isinstance(arg, SingleByte): |
| return f'{arg}B' |
| if isinstance(arg, short): |
| return f'{arg}S' |
| if isinstance(arg, long): |
| return f'{arg}L' |
| if isinstance(arg, bigint): |
| return f'{arg}N' |
| if isinstance(arg, int): |
| return f'{arg}' |
| if isinstance(arg, float): |
| # converting floats into doubles for script since python doesn't distinguish and java defaults to double |
| if math.isnan(arg): |
| return "NaN" |
| elif math.isinf(arg) and arg > 0: |
| return "+Infinity" |
| elif math.isinf(arg) and arg < 0: |
| return "-Infinity" |
| else: |
| return f'{arg}D' |
| if isinstance(arg, BigDecimal): |
| return f'{arg.value}M' |
| |
| if isinstance(arg, datetime): |
| return f'datetime("{arg.isoformat()}")' |
| |
| if isinstance(arg, uuid.UUID): |
| return f'UUID("{arg}")' |
| |
| if isinstance(arg, Enum): |
| tmp = str(arg) |
| if tmp.endswith('_'): |
| return tmp[0:-1] |
| elif '_' in tmp: |
| return f'{tmp.split("_")[0]}{tmp.split("_")[1].capitalize()}' |
| else: |
| return tmp |
| |
| if isinstance(arg, Vertex): |
| return f'{self._arg_as_string(arg.id)}' |
| |
| if isinstance(arg, P): |
| return self._process_predicate(arg) |
| |
| if isinstance(arg, GremlinLang) or isinstance(arg, Traversal): |
| gremlin_lang = arg if isinstance(arg, GremlinLang) else arg.gremlin_lang |
| self.parameters.update(gremlin_lang.parameters) |
| return gremlin_lang.get_gremlin('__') |
| |
| if isinstance(arg, GValue): |
| key = arg.get_name() |
| |
| if not key.isidentifier(): |
| raise Exception(f'invalid parameter name {key}.') |
| |
| if key in self.parameters: |
| if self.parameters[key] != arg.value: |
| raise Exception(f'parameter with name {key} already exists.') |
| else: |
| self.parameters[key] = arg.value |
| return key |
| |
| if isinstance(arg, dict): |
| return self._process_dict(arg) |
| |
| if isinstance(arg, set): |
| return self._process_set(arg) |
| |
| if isinstance(arg, list): |
| return self._process_list(arg) |
| |
| if hasattr(arg, '__class__'): |
| try: |
| return arg.__name__ |
| except AttributeError: |
| pass |
| |
| return self._as_parameter(arg) |
| |
| def _as_parameter(self, arg): |
| param_name = f'_{self.param_count.get_and_increment()}' |
| self.parameters[param_name] = arg |
| return param_name |
| |
| # Do special processing needed to format predicates that come in |
| # such as "gt(a)" correctly. |
| def _process_predicate(self, p): |
| res = [] |
| if p.operator in self.conn_p: |
| res.append(f'{self._process_predicate(p.value)}.{p.operator}({self._process_predicate(p.other)})') |
| else: |
| res.append(f'{self._process_p_value(p)}') |
| return ''.join(res) |
| |
| # process the value of the predicates |
| def _process_p_value(self, p): |
| c = 0 |
| res = [str(p).split('(')[0] + '('] |
| if isinstance(p.value, list): |
| res.append('[') |
| for v in p.value: |
| if c > 0: |
| res.append(',') |
| res.append(self._arg_as_string(v)) |
| c += 1 |
| res.append(']') |
| else: |
| res.append(self._arg_as_string(p.value)) |
| if p.other is not None: |
| res.append(f',{self._arg_as_string(p.other)}') |
| res.append(')') |
| return ''.join(res) |
| |
| def _process_dict(self, d): |
| c = 0 |
| res = ['['] |
| if len(d) == 0: |
| res.append(':') |
| else: |
| for k, v in d.items(): |
| wrap = not isinstance(k, str) |
| if c > 0: |
| res.append(',') |
| res.append(f'({self._arg_as_string(k)})') if wrap else res.append(self._arg_as_string(k)) |
| res.append(f':{self._arg_as_string(v)}') |
| c += 1 |
| res.append(']') |
| return ''.join(res) |
| |
| def _process_set(self, s): |
| c = 0 |
| res = ['{'] |
| for i in s: |
| if c > 0: |
| res.append(',') |
| res.append(self._arg_as_string(i)) |
| c += 1 |
| res.append('}') |
| return ''.join(res) |
| |
| def _process_list(self, lst): |
| c = 0 |
| res = ['['] |
| for i in lst: |
| if c > 0: |
| res.append(',') |
| res.append(self._arg_as_string(i)) |
| c += 1 |
| res.append(']') |
| return ''.join(res) |
| |
| def get_gremlin(self, g='g'): |
| # special handling for CardinalityValueTraversal |
| if len(self.gremlin) != 0 and self.gremlin[0] != '.': |
| return ''.join(self.gremlin) |
| |
| return g + ''.join(self.gremlin) |
| |
| def get_parameters(self): |
| return self.parameters |
| |
| def add_g(self, g): |
| self.parameters['g'] = g |
| |
| def reset(self): |
| self.param_count.set(0) |
| |
| def add_source(self, source_name, *args): |
| |
| if source_name == 'withStrategies' and len(args) != 0: |
| args = self.build_strategy_args(args) |
| if len(args) != 0: |
| self.gremlin.append('.') |
| self.gremlin.append(f'withStrategies({args})') |
| return |
| self._add_to_gremlin(source_name, args) |
| |
| def build_strategy_args(self, args): |
| res = [] |
| c = 0 |
| for arg in args: |
| if c > 0: |
| res.append(',') |
| # special handling for OptionsStrategy |
| from gremlin_python.process.strategies import OptionsStrategy |
| if isinstance(arg, OptionsStrategy): |
| self.options_strategies.append(arg) |
| break |
| if not arg.configuration: |
| res.append(arg.strategy_name) |
| else: |
| res.append(f'new {str(arg)}(') |
| ct = 0 |
| for key in arg.configuration: |
| if ct > 0: |
| res.append(',') |
| res.append(f'{key}:') |
| val = arg.configuration[key] |
| if isinstance(val, Traversal): |
| res.append(self._arg_as_string(val.gremlin_lang)) |
| else: |
| res.append(self._arg_as_string(val)) |
| ct += 1 |
| res.append(')') |
| c += 1 |
| return ''.join(res) |
| |
| def add_step(self, step_name, *args): |
| self._add_to_gremlin(step_name, args) |
| |
| def __eq__(self, other): |
| if isinstance(other, self.__class__): |
| return ''.join(self.gremlin) == ''.join(self.gremlin) and self.parameters == other.parameters |
| else: |
| return False |
| |
| def __copy__(self): |
| gl = GremlinLang() |
| gl.parameters = self.parameters |
| gl.gremlin = self.gremlin |
| return gl |
| |
| def __deepcopy__(self, memo=None): |
| if memo is None: |
| memo = {} |
| gl = GremlinLang() |
| gl.parameters = copy.deepcopy(self.parameters, memo) |
| gl.gremlin = copy.deepcopy(self.gremlin, memo) |
| return gl |
| |
| def _convert_argument(self, arg): |
| # if arg is None or len(arg) == 0: |
| # return arg |
| if isinstance(arg, Traversal): |
| if arg.graph is not None: |
| raise TypeError("The child traversal of " + str( |
| arg) + "was not spawned anonymously - use the __ class rather than a TraversalSource to construct " |
| "the child traversal.") |
| return arg.gremlin_lang |
| elif isinstance(arg, dict): |
| newDict = {} |
| for key in arg: |
| newDict[self._convert_argument(key)] = self._convert_argument(arg[key]) |
| return newDict |
| elif isinstance(arg, list): |
| newList = [] |
| for item in arg: |
| newList.append(self._convert_argument(item)) |
| return newList |
| elif isinstance(arg, set): |
| newSet = set() |
| for item in arg: |
| newSet.add(self._convert_argument(item)) |
| return newSet |
| else: |
| return arg |
| |
| def __repr__(self): |
| return (''.join(self.gremlin) if len(self.gremlin) > 0 else "") + \ |
| (str(self.parameters) if len(self.parameters) > 0 else "") |
| |
| # TODO to be removed or updated once HTTP transaction is implemented |
| # @staticmethod |
| # def _create_graph_op(name, *values): |
| # bc = Bytecode() |
| # bc.add_source(name, *values) |
| # return bc |
| # |
| # @staticmethod |
| # class GraphOp: |
| # @staticmethod |
| # def commit(): |
| # return Bytecode._create_graph_op("tx", "commit") |
| # |
| # @staticmethod |
| # def rollback(): |
| # return Bytecode._create_graph_op("tx", "rollback") |
| |
| |
| class GValue: |
| def __init__(self, name, value): |
| if name is None: |
| raise Exception("The parameter name cannot be None.") |
| if name.startswith('_'): |
| raise Exception(f'invalid GValue name {name}. Should not start with _.') |
| self.name = name |
| self.value = value |
| |
| def get_name(self): |
| return self.name |
| |
| def is_null(self): |
| return self.value is None |
| |
| def get(self): |
| return self.value |
| |
| |
| class CardinalityValue(GremlinLang): |
| def __init__(self, cardinality, val): |
| super().__init__() |
| self.add_source("CardinalityValueTraversal", cardinality, val) |
| |
| @classmethod |
| def single(cls, val): |
| return CardinalityValue(Cardinality.single, val) |
| |
| @classmethod |
| def list_(cls, val): |
| return CardinalityValue(Cardinality.list_, val) |
| |
| @classmethod |
| def set_(cls, val): |
| return CardinalityValue(Cardinality.set_, val) |
| |
| |
| class AtomicInteger: |
| def __init__(self): |
| self._value = 0 |
| self._lock = threading.Lock() |
| |
| def get_and_increment(self): |
| with self._lock: |
| value = self._value |
| self._value += 1 |
| return value |
| |
| def set(self, value): |
| with self._lock: |
| self._value = value |
| return self._value |
| |
| @property |
| def value(self): |
| with self._lock: |
| return self._value |