Created some gremlin-python abstractions - feel free to add! See description for gist

344 views
Skip to first unread message

Josh Wolff

unread,
Jul 1, 2019, 2:46:01 AM7/1/19
to Gremlin-users
I am trying to improve the amount of info about what is out there regarding gremlin-python and its differences from groovy.

I just started with gremlin, but I prefer to use Python and not Java. The differences with the Python module are not well documented.

Stephen Mallette

unread,
Jul 1, 2019, 6:26:50 AM7/1/19
to gremli...@googlegroups.com
Setting the identifier just requires T.id, thus:

g.addV().property(T.id,"customId")

or if you import T in Python as we typically do in all language variants:

from gremlin_python.process.traversal import T

then it looks like every other piece of Gremlin code out there:

g.addV().property(id,"customId")

The common imports required are all described in the python documentation:


When those are added, Python Gremlin pretty much looks like all other Gremlin. The only other real differences are in certain step renaming situation where an underscore is added to a step name that is in conflict with the Python language like the in() step which becomes in_(). Those too are documented, but with the step documentation. For example, see the vertex steps for the note on in_() in the Python box:


Were there other things that you noticed that were different? If so, I'd like to incorporate them into our reference documentation. 


--
You received this message because you are subscribed to the Google Groups "Gremlin-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to gremlin-user...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/gremlin-users/9961cf79-4c54-49bd-9792-06e7b7e2b042%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Stephen Mallette

unread,
Jul 1, 2019, 9:26:00 AM7/1/19
to gremli...@googlegroups.com
Also, as a minor nit, regarding:


please prefer:

g.V(v1).addE(label).to(V(v2)).next() 

Adding the "g" to anonymous traversals isn't necessary. I've been seeing more folks do that lately and while it works I think it makes it look like new "top-level" traversals are being created when they are really just anonymous...I think that's confusing to the eye.

Chris Forman Orth

unread,
Jul 1, 2019, 11:47:02 AM7/1/19
to Gremlin-users
We do something like this for our add_vertex method, which for newbies took us an embarrassingly long time to work out.

        query = g.V().addV(label)
        for key, val in keys.items():
                if (val is not None):
                    query.property(key,val)
        result = query.id().toList()

We also have an "upsert" method which splits the property values into separate keys and properties dicts. "keys" are for indexed/unique sets of identifying properties that shouldn't change, while the properties dict are things that will get updated in the upsert.

for key, val in keys.items():
            if (val is not None):
                query.has(key,val)
                addV.property(key,val)
query.fold().coalesce(__.unfold(),addV)
if properties:
       for key, val in properties.items():
            if (val is not None):
                query.property(key,val)
result = query.id().toList()
To unsubscribe from this group and stop receiving emails from it, send an email to gremli...@googlegroups.com.

Kelvin Lawrence

unread,
Jul 2, 2019, 4:31:28 PM7/2/19
to Gremlin-users
One thing that I have seen bite people with Gremlin Python is if you do

statics.load_statics(globals())


then you will get weird, hard to understand errors due to collisions with Python function names such as `range`, `map` and `sum`.
You end up needing to explicitly do a series of deletes along the lines of

del globals()['range']


For this reason I tend to avoid using the statics.load_statics and live with having to be a bit more specific.

Kelvin

On Monday, July 1, 2019 at 5:26:50 AM UTC-5, Stephen Mallette wrote:
Setting the identifier just requires T.id, thus:

g.addV().property(T.id,"customId")

or if you import T in Python as we typically do in all language variants:

from gremlin_python.process.traversal import T

then it looks like every other piece of Gremlin code out there:

g.addV().property(id,"customId")

The common imports required are all described in the python documentation:


When those are added, Python Gremlin pretty much looks like all other Gremlin. The only other real differences are in certain step renaming situation where an underscore is added to a step name that is in conflict with the Python language like the in() step which becomes in_(). Those too are documented, but with the step documentation. For example, see the vertex steps for the note on in_() in the Python box:


Were there other things that you noticed that were different? If so, I'd like to incorporate them into our reference documentation. 


On Mon, Jul 1, 2019 at 2:46 AM Josh Wolff <josh....@gmail.com> wrote:
I am trying to improve the amount of info about what is out there regarding gremlin-python and its differences from groovy.

I just started with gremlin, but I prefer to use Python and not Java. The differences with the Python module are not well documented.

--
You received this message because you are subscribed to the Google Groups "Gremlin-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to gremli...@googlegroups.com.

Stephen Mallette

unread,
Jul 2, 2019, 5:03:30 PM7/2/19
to gremli...@googlegroups.com
weird, hard to understand errors due to collisions with Python function names

hmm, maybe we should be more selective there to avoid the errors? do you have the list of errors handy to create a ticket in JIRA?

To unsubscribe from this group and stop receiving emails from it, send an email to gremlin-user...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/gremlin-users/a598f92c-6533-440e-be21-e6763b7bc764%40googlegroups.com.

Kelvin Lawrence

unread,
Jul 2, 2019, 5:34:38 PM7/2/19
to Gremlin-users
Hi Stephen, from a quick experiment this (below) seems to be the full list that gets made global. Of these I have probably not yet run into all the ones that cause an issue but for sure : range,max,min,sum,map,id

I suspect it is going to be any that appear in the table at https://docs.python.org/3/library/functions.html

  'statics.load_statics(globals())',
 'V': <function gremlin_python.process.graph_traversal.V(*args)>,
 'addE': <function gremlin_python.process.graph_traversal.addE(*args)>,
 'addV': <function gremlin_python.process.graph_traversal.addV(*args)>,
 'aggregate': <function gremlin_python.process.graph_traversal.aggregate(*args)>,
 'and_': <Operator.and_: 2>,
 'as_': <function gremlin_python.process.graph_traversal.as_(*args)>,
 'barrier': <function gremlin_python.process.graph_traversal.barrier(*args)>,
 'both': <function gremlin_python.process.graph_traversal.both(*args)>,
 'bothE': <function gremlin_python.process.graph_traversal.bothE(*args)>,
 'bothV': <function gremlin_python.process.graph_traversal.bothV(*args)>,
 'branch': <function gremlin_python.process.graph_traversal.branch(*args)>,
 'cap': <function gremlin_python.process.graph_traversal.cap(*args)>,
 'choose': <function gremlin_python.process.graph_traversal.choose(*args)>,
 'coalesce': <function gremlin_python.process.graph_traversal.coalesce(*args)>,
 'coin': <function gremlin_python.process.graph_traversal.coin(*args)>,
 'constant': <function gremlin_python.process.graph_traversal.constant(*args)>,
 'count': <function gremlin_python.process.graph_traversal.count(*args)>,
 'cyclicPath': <function gremlin_python.process.graph_traversal.cyclicPath(*args)>,
 'dedup': <function gremlin_python.process.graph_traversal.dedup(*args)>,
 'drop': <function gremlin_python.process.graph_traversal.drop(*args)>,
 'emit': <function gremlin_python.process.graph_traversal.emit(*args)>,
 'filter': <function gremlin_python.process.graph_traversal.filter(*args)>,
 'flatMap': <function gremlin_python.process.graph_traversal.flatMap(*args)>,
 'fold': <function gremlin_python.process.graph_traversal.fold(*args)>,
 'group': <function gremlin_python.process.graph_traversal.group(*args)>,
 'groupCount': <function gremlin_python.process.graph_traversal.groupCount(*args)>,
 'has': <function gremlin_python.process.graph_traversal.has(*args)>,
 'hasId': <function gremlin_python.process.graph_traversal.hasId(*args)>,
 'hasKey': <function gremlin_python.process.graph_traversal.hasKey(*args)>,
 'hasLabel': <function gremlin_python.process.graph_traversal.hasLabel(*args)>,
 'hasNot': <function gremlin_python.process.graph_traversal.hasNot(*args)>,
 'hasValue': <function gremlin_python.process.graph_traversal.hasValue(*args)>,
 'id': <T.id: 1>,
 'identity': <function gremlin_python.process.graph_traversal.identity(*args)>,
 'inE': <function gremlin_python.process.graph_traversal.inE(*args)>,
 'inV': <function gremlin_python.process.graph_traversal.inV(*args)>,
 'in_': <function gremlin_python.process.graph_traversal.in_(*args)>,
 'index': <function gremlin_python.process.graph_traversal.index(*args)>,
 'inject': <function gremlin_python.process.graph_traversal.inject(*args)>,
 'is_': <function gremlin_python.process.graph_traversal.is_(*args)>,
 'key': <T.key: 2>,
 'label': <T.label: 3>,
 'limit': <function gremlin_python.process.graph_traversal.limit(*args)>,
 'local': <Scope.local: 2>,
 'loops': <function gremlin_python.process.graph_traversal.loops(*args)>,
 'map': <function gremlin_python.process.graph_traversal.map(*args)>,
 'match': <function gremlin_python.process.graph_traversal.match(*args)>,
 'math': <function gremlin_python.process.graph_traversal.math(*args)>,
 'max': <Operator.max: 5>,
 'mean': <function gremlin_python.process.graph_traversal.mean(*args)>,
 'min': <Operator.min: 6>,
 'optional': <function gremlin_python.process.graph_traversal.optional(*args)>,
 'or_': <Operator.or_: 9>,
 'order': <function gremlin_python.process.graph_traversal.order(*args)>,
 'otherV': <function gremlin_python.process.graph_traversal.otherV(*args)>,
 'out': <function gremlin_python.process.graph_traversal.out(*args)>,
 'outE': <function gremlin_python.process.graph_traversal.outE(*args)>,
 'outV': <function gremlin_python.process.graph_traversal.outV(*args)>,
 'path': <function gremlin_python.process.graph_traversal.path(*args)>,
 'project': <function gremlin_python.process.graph_traversal.project(*args)>,
 'properties': <function gremlin_python.process.graph_traversal.properties(*args)>,
 'property': <function gremlin_python.process.graph_traversal.property(*args)>,
 'propertyMap': <function gremlin_python.process.graph_traversal.propertyMap(*args)>,
 'range': <function gremlin_python.process.graph_traversal.range(*args)>,
 'repeat': <function gremlin_python.process.graph_traversal.repeat(*args)>,
 'sack': <function gremlin_python.process.graph_traversal.sack(*args)>,
 'sample': <function gremlin_python.process.graph_traversal.sample(*args)>,
 'select': <function gremlin_python.process.graph_traversal.select(*args)>,
 'sideEffect': <function gremlin_python.process.graph_traversal.sideEffect(*args)>,
 'simplePath': <function gremlin_python.process.graph_traversal.simplePath(*args)>,
 'skip': <function gremlin_python.process.graph_traversal.skip(*args)>,
 'store': <function gremlin_python.process.graph_traversal.store(*args)>,
 'subgraph': <function gremlin_python.process.graph_traversal.subgraph(*args)>,
 'sum': <Operator.sum: 10>,
 'tail': <function gremlin_python.process.graph_traversal.tail(*args)>,
 'timeLimit': <function gremlin_python.process.graph_traversal.timeLimit(*args)>,
 'times': <function gremlin_python.process.graph_traversal.times(*args)>,
 'to': <function gremlin_python.process.graph_traversal.to(*args)>,
 'toE': <function gremlin_python.process.graph_traversal.toE(*args)>,
 'toV': <function gremlin_python.process.graph_traversal.toV(*args)>,
 'tree': <function gremlin_python.process.graph_traversal.tree(*args)>,
 'unfold': <function gremlin_python.process.graph_traversal.unfold(*args)>,
 'union': <function gremlin_python.process.graph_traversal.union(*args)>,
 'until': <function gremlin_python.process.graph_traversal.until(*args)>,
 'value': <T.value: 4>,
 'valueMap': <function gremlin_python.process.graph_traversal.valueMap(*args)>,
 'values': <Column.values: 2>,
 'where': <function gremlin_python.process.graph_traversal.where(*args)>,
 'normSack': <Barrier.normSack: 1>,
 'single': <Cardinality.single: 3>,
 'list_': <Cardinality.list_: 1>,
 'set_': <Cardinality.set_: 2>,
 'keys': <Column.keys: 1>,
 'OUT': <Direction.OUT: 3>,
 'IN': <Direction.IN: 2>,
 'BOTH': <Direction.BOTH: 1>,
 'V1_0': <GryoVersion.V1_0: 1>,
 'V2_0': <GraphSONVersion.V2_0: 2>,
 'V3_0': <GryoVersion.V3_0: 2>,
 'minus': <Operator.minus: 7>,
 'mult': <Operator.mult: 8>,
 'div': <Operator.div: 4>,
 'assign': <Operator.assign: 3>,
 'addAll': <Operator.addAll: 1>,
 'sumLong': <Operator.sumLong: 11>,
 'incr': <Order.incr: 4>,
 'decr': <Order.decr: 2>,
 'shuffle': <Order.shuffle: 5>,
 'asc': <Order.asc: 1>,
 'desc': <Order.desc: 3>,
 'any': <Pick.any: 1>,
 'none': <Pick.none: 2>,
 'first': <Pop.first: 2>,
 'last': <Pop.last: 3>,
 'all_': <Pop.all_: 1>,
 'mixed': <Pop.mixed: 4>,
 'global_': <Scope.global_: 1>,

On Tuesday, July 2, 2019 at 4:03:30 PM UTC-5, Stephen Mallette wrote:
weird, hard to understand errors due to collisions with Python function names

hmm, maybe we should be more selective there to avoid the errors? do you have the list of errors handy to create a ticket in JIRA?

Stephen Mallette

unread,
Jul 23, 2019, 5:30:20 PM7/23/19
to gremli...@googlegroups.com
Took me a while to look at this in more detail - Seems like we have collisions with:

filter()
id()
max()
min()  
range()
sum()

I guess we should be simply adding more underscore suffixed steps for gremlin_python and deprecating the old versions to avoid this problem going forward? that approach at least follows our pattern for such things, but ugh, more underscores......




To unsubscribe from this group and stop receiving emails from it, send an email to gremlin-user...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/gremlin-users/0412dcd2-fe6d-4a3b-9bcb-e7283cd239b2%40googlegroups.com.

Kelvin Lawrence

unread,
Jul 23, 2019, 9:38:41 PM7/23/19
to Gremlin-users
Hi Stephen, yes probably,unfortunately. I can't say I'm a fan of the underscores but not sure I have a better suggestion :-)

Kelvin

HadoopMarc

unread,
Jul 24, 2019, 4:47:54 AM7/24/19
to Gremlin-users
Yes, the underscores are ugly. As an alternative you could make the issue explicit by extending load_static with an list of keys that you want to have underscores because of standard lib function name collisions in your current python module, so:

statics.load_statics(globals(), underscores=['map', 'sum'])

The statics.py mechanism seems cumbersome anyway and it is not clear to me why the authors did not choose for the more usual definition of __all__ in the  __init__ of the module, so that you can do a simple:

from gremlin_python.process.traversal import *

OK, these were just some ideas to make an informed decision. I guess it is just a matter of taste. Personally. I like explicit imports at the top of my module, so (because python users need not now about a T class in gremlin-java):

from gremlin_python.process.traversal import id  # This does not work in the current gremlin-python
from gremlin_python.process.traversal import id as id_  # Collision case, does not work in the current gremlin-python


Cheers,   Marc


Op woensdag 24 juli 2019 03:38:41 UTC+2 schreef Kelvin Lawrence:

Stephen Mallette

unread,
Jul 24, 2019, 10:47:14 AM7/24/19
to gremli...@googlegroups.com
>  The statics.py mechanism seems cumbersome anyway and it is not clear to me why the authors did not choose for the more usual definition of __all__ in the  __init__ of the module, so that you can do a simple:

i think it's just because we aren't smart about python. :)

i've been interested in making gremlin-python a bit more pythonic the more i've been working with it. if this:

from gremlin_python.process.traversal import * 

is what a normal python developer would expect to do then perhaps it's time to deprecate "statics" and just have that approach you referenced. do python developers agree?

To unsubscribe from this group and stop receiving emails from it, send an email to gremlin-user...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/gremlin-users/a7ab8c48-3eb0-4790-8d30-61bfb335d495%40googlegroups.com.

Stephen Mallette

unread,
Jul 25, 2019, 12:44:49 PM7/25/19
to gremli...@googlegroups.com
Here's the issue after this discussion:


Definitely going to do the underscore thing. Not sure about what happens to statics going forward. 
Reply all
Reply to author
Forward
0 new messages