TINKERPOP-1562 Hooked up GremlinJythonScriptEngine to Customizers GremlnJythonScriptEngine is now initialized the same way that GremlinGroovyScriptEngine is.
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/05ff0c0f Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/05ff0c0f Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/05ff0c0f Branch: refs/heads/master Commit: 05ff0c0fe957a9fe697c5b1a176c682837ee0c64 Parents: a2ac1f2 Author: Stephen Mallette <sp...@genoprime.com> Authored: Thu Nov 24 08:11:35 2016 -0500 Committer: Stephen Mallette <sp...@genoprime.com> Committed: Fri Dec 2 06:31:49 2016 -0500 ---------------------------------------------------------------------- .../jsr223/GremlinJythonScriptEngine.java | 167 ++++++++++++------- .../GremlinJythonScriptEngineFactory.java | 5 +- .../jsr223/GremlinJythonScriptEngineTest.java | 12 +- .../jsr223/GremlinEnabledScriptEngineTest.java | 1 - 4 files changed, 120 insertions(+), 65 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/05ff0c0f/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/GremlinJythonScriptEngine.java ---------------------------------------------------------------------- diff --git a/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/GremlinJythonScriptEngine.java b/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/GremlinJythonScriptEngine.java index 554d80a..1b95a02 100644 --- a/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/GremlinJythonScriptEngine.java +++ b/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/GremlinJythonScriptEngine.java @@ -19,8 +19,10 @@ package org.apache.tinkerpop.gremlin.python.jsr223; +import org.apache.tinkerpop.gremlin.jsr223.Customizer; import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngine; import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngineFactory; +import org.apache.tinkerpop.gremlin.jsr223.ImportCustomizer; import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource; @@ -35,7 +37,13 @@ import javax.script.ScriptContext; import javax.script.ScriptException; import java.io.Reader; import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; /** * @author Marko A. Rodriguez (http://markorodriguez.com) @@ -44,6 +52,10 @@ public class GremlinJythonScriptEngine implements GremlinScriptEngine { private final PyScriptEngine pyScriptEngine; + /** + * @deprecated As of release 3.2.4, replaced by {@link #GremlinJythonScriptEngine(Customizer...)}. + */ + @Deprecated public GremlinJythonScriptEngine() { this.pyScriptEngine = (PyScriptEngine) new PyScriptEngineFactory().getScriptEngine(); try { @@ -61,70 +73,48 @@ public class GremlinJythonScriptEngine implements GremlinScriptEngine { this.pyScriptEngine.eval(SymbolHelper.toPython(x.name()) + " = " + x.getDeclaringClass().getSimpleName() + "." + x.name()); } - // add sugar methods - this.pyScriptEngine.eval("def getitem_bypass(self, index):\n" + - " if isinstance(index,int):\n return self.range(index,index+1)\n" + - " elif isinstance(index,slice):\n return self.range(index.start,index.stop)\n" + - " else:\n return TypeError('Index must be int or slice')"); - this.pyScriptEngine.eval(GraphTraversal.class.getSimpleName() + ".__getitem__ = getitem_bypass"); - this.pyScriptEngine.eval(GraphTraversal.class.getSimpleName() + ".__getattr__ = lambda self, key: self.values(key)\n"); - this.pyScriptEngine.eval("\n" + - "from java.lang import Long\n" + - "import org.apache.tinkerpop.gremlin.util.function.Lambda\n" + // todo: remove or remove imported subclass names? (choose) - "from org.apache.tinkerpop.gremlin.util.function.Lambda import AbstractLambda\n" + - "from org.apache.tinkerpop.gremlin.util.function.Lambda import UnknownArgLambda\n" + - "from org.apache.tinkerpop.gremlin.util.function.Lambda import ZeroArgLambda\n" + - "from org.apache.tinkerpop.gremlin.util.function.Lambda import OneArgLambda\n" + - "from org.apache.tinkerpop.gremlin.util.function.Lambda import TwoArgLambda\n\n" + - - "class JythonUnknownArgLambda(UnknownArgLambda):\n" + - " def __init__(self,func,script='none',lang='gremlin-jython'):\n" + - " UnknownArgLambda.__init__(self, script, lang, -1)\n" + - " self.func = func\n" + - " def __repr__(self):\n" + - " return self.getLambdaScript()\n\n" + - - "class JythonZeroArgLambda(ZeroArgLambda):\n" + - " def __init__(self,func,script='none',lang='gremlin-jython'):\n" + - " ZeroArgLambda.__init__(self, script, lang)\n" + - " self.func = func\n" + - " def __repr__(self):\n" + - " return self.getLambdaScript()\n" + - " def get(self):\n" + - " return self.func()\n\n" + - - "class JythonOneArgLambda(OneArgLambda):\n" + - " def __init__(self,func,script='none',lang='gremlin-jython'):\n" + - " OneArgLambda.__init__(self, script, lang)\n" + - " self.func = func\n" + - " def __repr__(self):\n" + - " return self.getLambdaScript()\n" + - " def test(self,a):\n" + - " return self.func(a)\n" + - " def apply(self,a):\n" + - " return self.func(a)\n" + - " def accept(self,a):\n" + - " self.func(a)\n" + - " def compare(self,a,b):\n" + - " return self.func(a,b)\n\n" + - - "class JythonTwoArgLambda(TwoArgLambda):\n" + - " def __init__(self,func,script='none',lang='gremlin-jython'):\n" + - " TwoArgLambda.__init__(self, script, lang)\n" + - " self.func = func\n" + - " def __repr__(self):\n" + - " return self.getLambdaScript()\n" + - " def apply(self,a,b):\n" + - " return self.func(a,b)\n" + - " def compare(self,a,b):\n" + - " return self.func(a,b)\n" - ); + loadSugar(); } catch (final ScriptException e) { throw new IllegalStateException(e.getMessage(), e); } } + public GremlinJythonScriptEngine(final Customizer... customizers) { + this.pyScriptEngine = (PyScriptEngine) new PyScriptEngineFactory().getScriptEngine(); + final List<Customizer> listOfCustomizers = Arrays.asList(customizers); + + final List<ImportCustomizer> importCustomizers = listOfCustomizers.stream() + .filter(p -> p instanceof ImportCustomizer) + .map(p -> (ImportCustomizer) p) + .collect(Collectors.toList()); + + try { + for (ImportCustomizer ic : importCustomizers) { + for (Class<?> c : ic.getClassImports()) { + if (null == c.getDeclaringClass()) + this.pyScriptEngine.eval("from " + c.getPackage().getName() + " import " + c.getSimpleName()); + else + this.pyScriptEngine.eval("from " + c.getPackage().getName() + "." + c.getDeclaringClass().getSimpleName() + " import " + c.getSimpleName()); + } + + for (Method m : ic.getMethodImports()) { + this.pyScriptEngine.eval(SymbolHelper.toPython(m.getName()) + " = " + m.getDeclaringClass().getSimpleName() + "." + m.getName()); + } + + // enums need to import after methods for some reason or else label comes in as a PyReflectedFunction + for (Enum e : ic.getEnumImports()) { + this.pyScriptEngine.eval(SymbolHelper.toPython(e.name()) + " = " + e.getDeclaringClass().getSimpleName() + "." + e.name()); + } + } + + loadSugar(); + + } catch (Exception ex) { + throw new IllegalStateException(ex); + } + } + @Override public Traversal.Admin eval(final Bytecode bytecode, final Bindings bindings) throws ScriptException { bindings.putAll(bytecode.getBindings()); @@ -209,4 +199,65 @@ public class GremlinJythonScriptEngine implements GremlinScriptEngine { public GremlinScriptEngineFactory getFactory() { return new GremlinJythonScriptEngineFactory(); } + + private void loadSugar() throws ScriptException { + // add sugar methods + this.pyScriptEngine.eval("def getitem_bypass(self, index):\n" + + " if isinstance(index,int):\n return self.range(index,index+1)\n" + + " elif isinstance(index,slice):\n return self.range(index.start,index.stop)\n" + + " else:\n return TypeError('Index must be int or slice')"); + this.pyScriptEngine.eval(GraphTraversal.class.getSimpleName() + ".__getitem__ = getitem_bypass"); + this.pyScriptEngine.eval(GraphTraversal.class.getSimpleName() + ".__getattr__ = lambda self, key: self.values(key)\n"); + this.pyScriptEngine.eval("\n" + + "from java.lang import Long\n" + + "import org.apache.tinkerpop.gremlin.util.function.Lambda\n" + // todo: remove or remove imported subclass names? (choose) + "from org.apache.tinkerpop.gremlin.util.function.Lambda import AbstractLambda\n" + + "from org.apache.tinkerpop.gremlin.util.function.Lambda import UnknownArgLambda\n" + + "from org.apache.tinkerpop.gremlin.util.function.Lambda import ZeroArgLambda\n" + + "from org.apache.tinkerpop.gremlin.util.function.Lambda import OneArgLambda\n" + + "from org.apache.tinkerpop.gremlin.util.function.Lambda import TwoArgLambda\n\n" + + + "class JythonUnknownArgLambda(UnknownArgLambda):\n" + + " def __init__(self,func,script='none',lang='gremlin-jython'):\n" + + " UnknownArgLambda.__init__(self, script, lang, -1)\n" + + " self.func = func\n" + + " def __repr__(self):\n" + + " return self.getLambdaScript()\n\n" + + + "class JythonZeroArgLambda(ZeroArgLambda):\n" + + " def __init__(self,func,script='none',lang='gremlin-jython'):\n" + + " ZeroArgLambda.__init__(self, script, lang)\n" + + " self.func = func\n" + + " def __repr__(self):\n" + + " return self.getLambdaScript()\n" + + " def get(self):\n" + + " return self.func()\n\n" + + + "class JythonOneArgLambda(OneArgLambda):\n" + + " def __init__(self,func,script='none',lang='gremlin-jython'):\n" + + " OneArgLambda.__init__(self, script, lang)\n" + + " self.func = func\n" + + " def __repr__(self):\n" + + " return self.getLambdaScript()\n" + + " def test(self,a):\n" + + " return self.func(a)\n" + + " def apply(self,a):\n" + + " return self.func(a)\n" + + " def accept(self,a):\n" + + " self.func(a)\n" + + " def compare(self,a,b):\n" + + " return self.func(a,b)\n\n" + + + "class JythonTwoArgLambda(TwoArgLambda):\n" + + " def __init__(self,func,script='none',lang='gremlin-jython'):\n" + + " TwoArgLambda.__init__(self, script, lang)\n" + + " self.func = func\n" + + " def __repr__(self):\n" + + " return self.getLambdaScript()\n" + + " def apply(self,a,b):\n" + + " return self.func(a,b)\n" + + " def compare(self,a,b):\n" + + " return self.func(a,b)\n" + ); + } } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/05ff0c0f/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/GremlinJythonScriptEngineFactory.java ---------------------------------------------------------------------- diff --git a/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/GremlinJythonScriptEngineFactory.java b/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/GremlinJythonScriptEngineFactory.java index c94e94f..696c2ea 100644 --- a/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/GremlinJythonScriptEngineFactory.java +++ b/gremlin-python/src/main/java/org/apache/tinkerpop/gremlin/python/jsr223/GremlinJythonScriptEngineFactory.java @@ -19,6 +19,7 @@ package org.apache.tinkerpop.gremlin.python.jsr223; +import org.apache.tinkerpop.gremlin.jsr223.Customizer; import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngine; import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngineFactory; import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngineManager; @@ -100,6 +101,8 @@ public class GremlinJythonScriptEngineFactory extends PyScriptEngineFactory impl @Override public GremlinScriptEngine getScriptEngine() { - return new GremlinJythonScriptEngine(); + final List<Customizer> customizers = manager.getCustomizers(GREMLIN_JYTHON); + return (customizers.isEmpty()) ? new GremlinJythonScriptEngine() : + new GremlinJythonScriptEngine(customizers.toArray(new Customizer[customizers.size()])); } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/05ff0c0f/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/GremlinJythonScriptEngineTest.java ---------------------------------------------------------------------- diff --git a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/GremlinJythonScriptEngineTest.java b/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/GremlinJythonScriptEngineTest.java index 8bc60a5..8ec1cf4 100644 --- a/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/GremlinJythonScriptEngineTest.java +++ b/gremlin-python/src/test/java/org/apache/tinkerpop/gremlin/python/jsr223/GremlinJythonScriptEngineTest.java @@ -36,6 +36,8 @@ import java.math.BigInteger; import java.util.Arrays; import java.util.HashSet; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsInstanceOf.instanceOf; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -56,11 +58,11 @@ public class GremlinJythonScriptEngineTest { @Test public void shouldHaveCoreImports() throws Exception { final ScriptEngine engine = new DefaultGremlinScriptEngineManager().getEngineByName("gremlin-jython"); - assertTrue(engine.eval("Graph") instanceof Class); - assertTrue(engine.eval("__") instanceof Class); - assertTrue(engine.eval("T") instanceof Class); - assertTrue(engine.eval("label") instanceof T); - assertTrue(engine.eval("T.label") instanceof T); + assertThat(engine.eval("Graph"), instanceOf(Class.class)); + assertThat(engine.eval("__"), instanceOf(Class.class)); + assertThat(engine.eval("T"), instanceOf(Class.class)); + assertThat(engine.eval("label"), instanceOf(T.class)); + assertThat(engine.eval("T.label"), instanceOf(T.class)); assertEquals(SackFunctions.Barrier.class, engine.eval("Barrier")); assertEquals(SackFunctions.Barrier.normSack, engine.eval("Barrier.normSack")); assertEquals(Column.class, engine.eval("Column")); http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/05ff0c0f/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinEnabledScriptEngineTest.java ---------------------------------------------------------------------- diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinEnabledScriptEngineTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinEnabledScriptEngineTest.java index 723d898..f6bbcb8 100644 --- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinEnabledScriptEngineTest.java +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinEnabledScriptEngineTest.java @@ -55,7 +55,6 @@ public class GremlinEnabledScriptEngineTest { } } - @org.junit.Ignore("TEMPORARY - until GremlinJythonScriptEngine supports this stuff") @Test public void shouldSupportDeprecatedGremlinModules() throws Exception { final GremlinScriptEngineManager mgr = new DefaultGremlinScriptEngineManager();