From 11fe4afc2daaa6f68bb11807b018a4cac36dc79b Mon Sep 17 00:00:00 2001
From: jakubs <jakubs>
Date: Mon, 18 Apr 2016 14:02:44 +0000
Subject: [PATCH] SSDM-3510 - make it possible to use jython 2.7 everywhere
 where we use python

SVN: 36200
---
 .../common/jython/evaluator/Evaluator.java    | 488 +---------------
 .../jython/evaluator/IJythonEvaluator.java    | 124 ++++
 .../evaluator/IJythonEvaluatorFactory.java    |  63 +++
 .../JythonEvaluatorSpringComponent.java       |  44 ++
 .../cisd/common/jython/v25/Evaluator25.java   | 532 ++++++++++++++++++
 .../jython/v25/Jython25EvaluatorFactory.java  |  55 ++
 .../cisd/common/jython/v27/Evaluator27.java   |  48 +-
 .../jython/v27/Jython27EvaluatorFactory.java  |  55 ++
 .../common/evaluator/Evaluator25Test.java     |  42 ++
 .../common/evaluator/Evaluator27Test.java     |  43 ++
 .../cisd/common/evaluator/EvaluatorTest.java  | 146 +++--
 11 files changed, 1099 insertions(+), 541 deletions(-)
 create mode 100644 common/source/java/ch/systemsx/cisd/common/jython/evaluator/IJythonEvaluator.java
 create mode 100644 common/source/java/ch/systemsx/cisd/common/jython/evaluator/IJythonEvaluatorFactory.java
 create mode 100644 common/source/java/ch/systemsx/cisd/common/jython/evaluator/JythonEvaluatorSpringComponent.java
 create mode 100644 common/source/java/ch/systemsx/cisd/common/jython/v25/Evaluator25.java
 create mode 100644 common/source/java/ch/systemsx/cisd/common/jython/v25/Jython25EvaluatorFactory.java
 create mode 100644 common/source/java/ch/systemsx/cisd/common/jython/v27/Jython27EvaluatorFactory.java
 create mode 100644 common/sourceTest/java/ch/systemsx/cisd/common/evaluator/Evaluator25Test.java
 create mode 100644 common/sourceTest/java/ch/systemsx/cisd/common/evaluator/Evaluator27Test.java

diff --git a/common/source/java/ch/systemsx/cisd/common/jython/evaluator/Evaluator.java b/common/source/java/ch/systemsx/cisd/common/jython/evaluator/Evaluator.java
index 0fda16012fd..595997174c9 100644
--- a/common/source/java/ch/systemsx/cisd/common/jython/evaluator/Evaluator.java
+++ b/common/source/java/ch/systemsx/cisd/common/jython/evaluator/Evaluator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009 ETH Zuerich, CISD
+ * Copyright 2016 ETH Zuerich, CISD
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,67 +16,11 @@
 
 package ch.systemsx.cisd.common.jython.evaluator;
 
-import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.apache.commons.lang.StringUtils;
-import org.python.core.CompileMode;
-import org.python.core.CompilerFlags;
-import org.python.core.Py;
-import org.python.core.PyBoolean;
-import org.python.core.PyCode;
-import org.python.core.PyException;
-import org.python.core.PyFloat;
-import org.python.core.PyFunction;
-import org.python.core.PyInteger;
-import org.python.core.PyList;
-import org.python.core.PyLong;
-import org.python.core.PyNone;
-import org.python.core.PyObject;
-import org.python.core.PyString;
-import org.python.core.PyStringMap;
-import org.python.core.PySystemState;
-import org.python.core.PyTraceback;
-
-import ch.systemsx.cisd.common.jython.PythonInterpreter;
-import ch.systemsx.cisd.common.shared.basic.string.CommaSeparatedListBuilder;
-
 /**
- * A class for evaluating expressions, based on Jython.
- * <p>
- * This class is optimized for evaluating the same expression with a different set of variables repeatedly and efficient. The mode of usage of this
- * class is:
- * <ol>
- * <li>Construct an {@link Evaluator} with an appropriate expression.</li>
- * <li>Set all variables needed for evaluation via {@link #set(String, Object)}</li>
- * <li>Call one of {@link #getType()}, {@link #evalAsString}, {@link #evalToBoolean()}, {@link #evalToInt()}, {@link #evalToBigInt()},
- * {@link #evalToDouble()}.</li>
- * <li>Repeat from step 2</li>
- * </ol>
- * 
- * @author Bernd Rinn
+ * @author Jakub Straszewski
  */
-public final class Evaluator
+public class Evaluator
 {
-    private final PythonInterpreter interpreter;
-
-    private final String expression;
-
-    private final PyCode compiledExpression;
-
-    /**
-     * Call once before using the object to initialize.
-     */
-    public static void initialize()
-    {
-        PySystemState.initialize();
-    }
-
     /**
      * The return type of this expression.
      */
@@ -85,434 +29,26 @@ public final class Evaluator
         BOOLEAN, INTEGER, BIGINT, DOUBLE, STRING, OTHER
     }
 
-    /**
-     * Creates a new {@link Evaluator} with file system access blocked.
-     * 
-     * @param expression The expression to evaluate.
-     */
-    public Evaluator(String expression) throws EvaluatorException
-    {
-        this(expression, null, null);
-    }
-
-    /**
-     * Creates a new {@link Evaluator} with file system access blocked.
-     * 
-     * @param expression The expression to evaluate.
-     * @param supportFunctionsOrNull If not <code>null</code>, all public static methods of the given class will be available to the evaluator as
-     *            "supporting functions".
-     * @param initialScriptOrNull If not <code>null</code>, this has to be a valid (Python) script which is evaluated initially, e.g. to define some
-     *            new functions. Note: this script is trusted, so don't run any unvalidated code here!
-     */
-    public Evaluator(String expression, Class<?> supportFunctionsOrNull, String initialScriptOrNull)
-            throws EvaluatorException
-    {
-        this(expression, null, supportFunctionsOrNull, initialScriptOrNull, true);
-    }
-
-    /**
-     * Creates a new {@link Evaluator}.
-     * 
-     * @param expression The expression to evaluate.
-     * @param supportFunctionsOrNull If not <code>null</code>, all public static methods of the given class will be available to the evaluator as
-     *            "supporting functions".
-     * @param initialScriptOrNull If not <code>null</code>, this has to be a valid (Python) script which is evaluated initially, e.g. to define some
-     *            new functions. Note: this script is trusted, so don't run any unvalidated code here!
-     * @param blockFileAccess If <code>true</code> the script will not be able to open files.
-     */
-    public Evaluator(String expression, String[] pythonPath, Class<?> supportFunctionsOrNull,
-            String initialScriptOrNull, boolean blockFileAccess) throws EvaluatorException
-    {
-        if (isMultiline(expression))
-        {
-            throw new EvaluatorException("Expression '" + expression + "' contains line breaks");
-        }
-
-        this.interpreter = PythonInterpreter.createIsolatedPythonInterpreter();
-        this.interpreter.addToPath(pythonPath);
-
-        // Security: do not allow file access.
-        try
-        {
-            if (blockFileAccess)
-            {
-                interpreter.exec("def open():\n   pass");
-            }
-            if (supportFunctionsOrNull != null)
-            {
-                interpreter.exec("from " + supportFunctionsOrNull.getCanonicalName() + " import *");
-            }
-            if (initialScriptOrNull != null)
-            {
-                interpreter.exec(initialScriptOrNull);
-            }
-            this.expression = expression;
-
-            this.compiledExpression = doCompile(expression);
-        } catch (PyException ex)
-        {
-            throw toEvaluatorException(ex);
-        }
-    }
-
-    /**
-     * Returns <code>true</code> if specified function is defined in the script.
-     */
-    public boolean hasFunction(String functionName)
-    {
-        PyObject pyObject = interpreter.get(functionName);
-        return pyObject instanceof PyFunction;
-    }
-
-    /**
-     * Evaluates specified function with specified arguments. The arguments are turned into Python Strings if they are Java {@link String} objects.
-     * The return value of the function is returned as a Java object or <code>null</code>.
-     * 
-     * @throws EvaluatorException if evaluation fails.
-     */
-    public Object evalFunction(String functionName, Object... args)
-    {
-        try
-        {
-            PyObject pyObject = interpreter.get(functionName);
-            if (pyObject == null)
-            {
-                throw new PyException(new PyString("Unknown function"), functionName);
-            }
-            if (pyObject instanceof PyFunction == false)
-            {
-                throw new PyException(new PyString("Not a function"), "'" + functionName
-                        + "' is of type " + pyObject.getType().getName() + ".");
-            }
-            PyFunction func = (PyFunction) pyObject;
-            PyObject[] pyArgs = new PyObject[args.length];
-            for (int i = 0; i < args.length; i++)
-            {
-                pyArgs[i] = translateToPython(args[i]);
-            }
-            PyObject result = func.__call__(pyArgs);
-            return translateToJava(result);
-        } catch (PyException ex)
-        {
-            CommaSeparatedListBuilder builder = new CommaSeparatedListBuilder();
-            for (Object argument : args)
-            {
-                builder.append(argument);
-            }
-            throw toEvaluatorException(ex, functionName + "(" + builder + ")");
-        }
-    }
-
-    private PyObject translateToPython(Object javaObject)
-    {
-        if (javaObject instanceof String)
-        {
-            return new PyString((String) javaObject);
-        }
-        return Py.java2py(javaObject);
-    }
+    private static IJythonEvaluatorFactory factory;
 
-    /**
-     * @return compiled <var>expression</var>
-     * @throws EvaluatorException if compilation fails
-     */
-    private static PyCode doCompile(String expression) throws EvaluatorException
+    static void setFactory(IJythonEvaluatorFactory factory)
     {
-        try
-        {
-            return Py.compile_flags("__result__=(" + expression + ")", "expression: " + expression,
-                    CompileMode.exec, new CompilerFlags());
-        } catch (PyException ex)
-        {
-            throw toEvaluatorException(ex, expression);
-        }
+        Evaluator.factory = factory;
     }
 
-    /**
-     * Sets the variable <var>name</var> to <var>value</var> in the evaluator's name space.
-     */
-    public void set(String name, Object value)
-    {
-        interpreter.set(name, value);
-    }
-
-    public Object get(String name)
+    public static IJythonEvaluatorFactory getFactory()
     {
-        return interpreter.get(name);
-    }
-
-    /**
-     * Deletes the variable <var>name</var> from the evaluator's name space.
-     */
-    public void delete(String name)
-    {
-        interpreter.getLocals().__delitem__(name);
-    }
-
-    /**
-     * Returns <code>true</code> if and only if the variable <var>name</var> exists in the evaluator's name space.
-     */
-    public boolean has(String name)
-    {
-        return ((PyStringMap) interpreter.getLocals()).has_key(new PyString(name));
-    }
-
-    /**
-     * Returns the {@link ReturnType} of the expression of this evaluator.
-     */
-    public ReturnType getType()
-    {
-        doEval();
-        final Object obj = getInterpreterResult();
-        if (obj instanceof PyBoolean)
-        {
-            return ReturnType.BOOLEAN;
-        } else if (obj instanceof PyInteger)
-        {
-            return ReturnType.INTEGER;
-        } else if (obj instanceof PyLong)
-        {
-            return ReturnType.BIGINT;
-        } else if (obj instanceof PyFloat)
+        if (factory == null)
         {
-            return ReturnType.DOUBLE;
-        } else if (obj instanceof PyString)
-        {
-            return ReturnType.STRING;
-        } else
-        {
-            return ReturnType.OTHER;
+            // we should make sure that the initialization hapens before first call to this method
+            throw new IllegalStateException(
+                    "Jython evaluator component not initialized. Application context is not initialized properly - JythonEvaluatorSpringComponent must be initialized before jython evaluators are used.");
         }
-    }
-
-    /**
-     * Evaluates the expression of this evaluator and returns the result. Use this method if you do not know what will be the result type.
-     * <p>
-     * <i>This is a legacy function to mimic the old Jython 2.2 Evaluator's behavior which will only return Long, Double or String and doesn't know
-     * boolean.</i>
-     * 
-     * @return evaluation result which can be of Long, Double or String type. All other types are converted to String representation except
-     *         {@link PyNone} that represents null value and will be converted to <code>null</code>.
-     */
-    public Object evalLegacy2_2()
-    {
-        doEval();
-        final PyObject obj = getInterpreterResult();
-        Object result = translateToJavaLegacy(obj);
-        if (result != null && result instanceof Long == false && result instanceof Double == false
-                && result instanceof String == false)
-        {
-            return result.toString();
-        }
-        return result;
-    }
-
-    /**
-     * Evaluates the expression of this evaluator and returns the result. Use this method if you do not know what will be the result type.
-     * 
-     * @return evaluation result as translated by the Jython interpreter..
-     */
-    public Object eval()
-    {
-        doEval();
-        return translateToJava(getInterpreterResult());
-    }
-
-    private Object translateToJavaLegacy(final PyObject obj)
-    {
-        if (obj instanceof PyInteger)
-        {
-            return new Long(((PyInteger) obj).getValue());
-        } else if (obj instanceof PyLong)
-        {
-            return new Long(((PyLong) obj).getValue().longValue());
-        } else if (obj instanceof PyFloat)
-        {
-            return new Double(((PyFloat) obj).getValue());
-        } else if (obj instanceof PyNone)
-        {
-            return null;
-        } else if (obj instanceof PyList)
-        {
-            PyList pyList = (PyList) obj;
-            PyObject[] array = pyList.getArray();
-            List<Object> list = new ArrayList<Object>();
-            for (int i = 0, n = pyList.size(); i < n; i++)
-            {
-                list.add(translateToJavaLegacy(array[i]));
-            }
-            return list;
-        } else
-        {
-            return translateToJava(obj);
-        }
-    }
-
-    private Object translateToJava(final PyObject obj)
-    {
-        return (obj == null) ? null : obj.__tojava__(Object.class);
-    }
-
-    private PyObject getInterpreterResult()
-    {
-        return interpreter.get("__result__");
-    }
-
-    /**
-     * Evaluates the expression of this evaluator and returns the result, assuming that the expression has a boolean return type.
-     */
-    public boolean evalToBoolean() throws EvaluatorException
-    {
-        doEval();
-        try
-        {
-            return ((PyBoolean) getInterpreterResult()).getBooleanValue();
-        } catch (ClassCastException ex)
-        {
-            final ReturnType type = getType();
-            throw new EvaluatorException("Expected a result of type " + ReturnType.BOOLEAN
-                    + ", found " + type);
-        }
-    }
-
-    /**
-     * Evaluates the expression of this evaluator and returns the result, assuming that the expression has an integer return type.
-     */
-    public int evalToInt() throws EvaluatorException
-    {
-        doEval();
-        try
-        {
-            return ((PyInteger) getInterpreterResult()).getValue();
-        } catch (ClassCastException ex)
-        {
-            final ReturnType type = getType();
-            throw new EvaluatorException("Expected a result of type " + ReturnType.INTEGER
-                    + ", found " + type);
-        }
-    }
-
-    /**
-     * Evaluates the expression of this evaluator and returns the result, assuming that the expression has a big integer return type.
-     */
-    public BigInteger evalToBigInt() throws EvaluatorException
-    {
-        doEval();
-        try
-        {
-            return ((PyLong) getInterpreterResult()).getValue();
-        } catch (ClassCastException ex)
-        {
-            final ReturnType type = getType();
-            throw new EvaluatorException("Expected a result of type " + ReturnType.BIGINT
-                    + ", found " + type);
-        }
-    }
-
-    /**
-     * Evaluates the expression of this evaluator and returns the result, assuming that the expression has a floating point (double) return type.
-     */
-    public double evalToDouble() throws EvaluatorException
-    {
-        doEval();
-        try
-        {
-            return ((PyFloat) getInterpreterResult()).getValue();
-        } catch (ClassCastException ex)
-        {
-            final ReturnType type = getType();
-            throw new EvaluatorException("Expected a result of type " + ReturnType.DOUBLE
-                    + ", found " + type);
-        }
-    }
-
-    /**
-     * Evaluates the expression of this evaluator and returns the result as a String. This method can always be called.
-     * <p>
-     * <i>This is a legacy function to mimic the old Jython 2.2 Evaluator's behavior which first translates to Long and Double and doesn't know
-     * boolean.</i>
-     * <p>
-     * NOTE: null will be returned if expression results in {@link PyNone}
-     */
-    public String evalAsStringLegacy2_2() throws EvaluatorException
-    {
-        Object result = evalLegacy2_2();
-        return result == null ? null : result.toString();
-    }
-
-    /**
-     * Evaluates the expression of this evaluator and returns the result as a String. This method can always be called.
-     * <p>
-     * NOTE: null will be returned if expression results in {@link PyNone}
-     */
-    public String evalAsString() throws EvaluatorException
-    {
-        Object result = eval();
-        return result == null ? null : result.toString();
-    }
-
-    private void doEval() throws EvaluatorException
-    {
-        try
-        {
-            interpreter.exec(compiledExpression);
-        } catch (PyException ex)
-        {
-            throw toEvaluatorException(ex);
-        }
-    }
-
-    private EvaluatorException toEvaluatorException(PyException ex)
-    {
-        return toEvaluatorException(ex, expression);
-    }
-
-    private static EvaluatorException toEvaluatorException(PyException ex, String expressionOrNull)
-    {
-        Throwable exception = ex;
-        PyObject value = ex.value;
-        Object object = value.__tojava__(Object.class);
-        if (object instanceof Throwable)
-        {
-            exception = (Throwable) object;
-        }
-        String msg = extractExceptionMessage(ex);
-        if (expressionOrNull != null)
-        {
-            PyTraceback traceback = ex.traceback;
-            String details =
-                    traceback == null ? "" : "occurred in line " + traceback.tb_lineno
-                            + " of the script when ";
-            msg = "Error " + details + "evaluating '" + expressionOrNull + "': " + msg;
-        }
-        return new EvaluatorException(msg, exception);
-    }
-
-    private static String extractExceptionMessage(PyException ex)
-    {
-        final String[] description = StringUtils.split(ex.toString(), '\n');
-        return description[description.length - 1];
+        return factory;
     }
 
     public static boolean isMultiline(String expression)
     {
         return expression.indexOf('\n') >= 0;
     }
-
-    public void releaseResources()
-    {
-        interpreter.releaseResources();
-    }
-
-    public Collection<String> getGlobalVariables()
-    {
-        Set<String> results = new HashSet<String>();
-        PyStringMap locals = (PyStringMap) interpreter.getLocals();
-        for (Object key : locals.keys())
-        {
-            results.add(key.toString());
-        }
-        return Collections.unmodifiableCollection(results);
-    }
-
 }
diff --git a/common/source/java/ch/systemsx/cisd/common/jython/evaluator/IJythonEvaluator.java b/common/source/java/ch/systemsx/cisd/common/jython/evaluator/IJythonEvaluator.java
new file mode 100644
index 00000000000..56b2e2f45ce
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/jython/evaluator/IJythonEvaluator.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2016 ETH Zuerich, CISD
+ *
+ * Licensed 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.
+ */
+
+package ch.systemsx.cisd.common.jython.evaluator;
+
+import java.math.BigInteger;
+import java.util.Collection;
+
+import org.python.core.PyNone;
+
+import ch.systemsx.cisd.common.jython.evaluator.Evaluator.ReturnType;
+
+/**
+ * @author Jakub Straszewski
+ */
+public interface IJythonEvaluator
+{
+    /**
+     * Returns <code>true</code> if specified function is defined in the script.
+     */
+    public boolean hasFunction(String functionName);
+
+    /**
+     * Evaluates specified function with specified arguments. The arguments are turned into Python Strings if they are Java {@link String} objects.
+     * The return value of the function is returned as a Java object or <code>null</code>.
+     * 
+     * @throws EvaluatorException if evaluation fails.
+     */
+    public Object evalFunction(String functionName, Object... args);
+
+    /**
+     * Sets the variable <var>name</var> to <var>value</var> in the evaluator's name space.
+     */
+    public void set(String name, Object value);
+
+    public Object get(String name);
+
+    /**
+     * Deletes the variable <var>name</var> from the evaluator's name space.
+     */
+    public void delete(String name);
+
+    /**
+     * Returns <code>true</code> if and only if the variable <var>name</var> exists in the evaluator's name space.
+     */
+    public boolean has(String name);
+
+    /**
+     * Returns the {@link ReturnType} of the expression of this evaluator.
+     */
+    public ReturnType getType();
+
+    /**
+     * Evaluates the expression of this evaluator and returns the result. Use this method if you do not know what will be the result type.
+     * <p>
+     * <i>This is a legacy function to mimic the old Jython 2.2 Evaluator's behavior which will only return Long, Double or String and doesn't know
+     * boolean.</i>
+     * 
+     * @return evaluation result which can be of Long, Double or String type. All other types are converted to String representation except
+     *         {@link PyNone} that represents null value and will be converted to <code>null</code>.
+     */
+    public Object evalLegacy2_2();
+
+    /**
+     * Evaluates the expression of this evaluator and returns the result. Use this method if you do not know what will be the result type.
+     * 
+     * @return evaluation result as translated by the Jython interpreter..
+     */
+    public Object eval();
+
+    /**
+     * Evaluates the expression of this evaluator and returns the result, assuming that the expression has a boolean return type.
+     */
+    public boolean evalToBoolean();
+
+    /**
+     * Evaluates the expression of this evaluator and returns the result, assuming that the expression has an integer return type.
+     */
+    public int evalToInt();
+
+    /**
+     * Evaluates the expression of this evaluator and returns the result, assuming that the expression has a big integer return type.
+     */
+    public BigInteger evalToBigInt();
+
+    /**
+     * Evaluates the expression of this evaluator and returns the result, assuming that the expression has a floating point (double) return type.
+     */
+    public double evalToDouble();
+
+    /**
+     * Evaluates the expression of this evaluator and returns the result as a String. This method can always be called.
+     * <p>
+     * <i>This is a legacy function to mimic the old Jython 2.2 Evaluator's behavior which first translates to Long and Double and doesn't know
+     * boolean.</i>
+     * <p>
+     * NOTE: null will be returned if expression results in {@link PyNone}
+     */
+    public String evalAsStringLegacy2_2();
+
+    /**
+     * Evaluates the expression of this evaluator and returns the result as a String. This method can always be called.
+     * <p>
+     * NOTE: null will be returned if expression results in {@link PyNone}
+     */
+    public String evalAsString();
+
+    public void releaseResources();
+
+    public Collection<String> getGlobalVariables();
+}
diff --git a/common/source/java/ch/systemsx/cisd/common/jython/evaluator/IJythonEvaluatorFactory.java b/common/source/java/ch/systemsx/cisd/common/jython/evaluator/IJythonEvaluatorFactory.java
new file mode 100644
index 00000000000..1a52ea462ea
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/jython/evaluator/IJythonEvaluatorFactory.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2016 ETH Zuerich, CISD
+ *
+ * Licensed 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.
+ */
+
+package ch.systemsx.cisd.common.jython.evaluator;
+
+import ch.systemsx.cisd.common.jython.v25.Evaluator25;
+
+/**
+ * @author Jakub Straszewski
+ */
+public interface IJythonEvaluatorFactory
+{
+    /**
+     * Call once before using the object to initialize.
+     */
+    public void initialize();
+
+    /**
+     * Creates a new {@link Evaluator25} with file system access blocked.
+     * 
+     * @param expression The expression to evaluate.
+     */
+    public IJythonEvaluator create(String expression) throws EvaluatorException;
+
+    /**
+     * Creates a new {@link IJythonEvaluator} with file system access blocked.
+     * 
+     * @param expression The expression to evaluate.
+     * @param supportFunctionsOrNull If not <code>null</code>, all public static methods of the given class will be available to the evaluator as
+     *            "supporting functions".
+     * @param initialScriptOrNull If not <code>null</code>, this has to be a valid (Python) script which is evaluated initially, e.g. to define some
+     *            new functions. Note: this script is trusted, so don't run any unvalidated code here!
+     */
+    public IJythonEvaluator create(String expression, Class<?> supportFunctionsOrNull, String initialScriptOrNull)
+            throws EvaluatorException;
+
+    /**
+     * Creates a new {@link Evaluator25}.
+     * 
+     * @param expression The expression to evaluate.
+     * @param supportFunctionsOrNull If not <code>null</code>, all public static methods of the given class will be available to the evaluator as
+     *            "supporting functions".
+     * @param initialScriptOrNull If not <code>null</code>, this has to be a valid (Python) script which is evaluated initially, e.g. to define some
+     *            new functions. Note: this script is trusted, so don't run any unvalidated code here!
+     * @param blockFileAccess If <code>true</code> the script will not be able to open files.
+     */
+    public IJythonEvaluator create(String expression, String[] pythonPath, String scriptPath, Class<?> supportFunctionsOrNull,
+            String initialScriptOrNull, boolean blockFileAccess) throws EvaluatorException;
+
+}
diff --git a/common/source/java/ch/systemsx/cisd/common/jython/evaluator/JythonEvaluatorSpringComponent.java b/common/source/java/ch/systemsx/cisd/common/jython/evaluator/JythonEvaluatorSpringComponent.java
new file mode 100644
index 00000000000..17e6bbdc1bf
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/jython/evaluator/JythonEvaluatorSpringComponent.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2016 ETH Zuerich, CISD
+ *
+ * Licensed 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.
+ */
+
+package ch.systemsx.cisd.common.jython.evaluator;
+
+import org.springframework.beans.factory.BeanInitializationException;
+
+import ch.systemsx.cisd.common.jython.v25.Jython25EvaluatorFactory;
+import ch.systemsx.cisd.common.jython.v27.Jython27EvaluatorFactory;
+import ch.systemsx.cisd.common.spring.ExposablePropertyPlaceholderConfigurer;
+
+/**
+ * @author Jakub Straszewski
+ */
+public class JythonEvaluatorSpringComponent
+{
+    public JythonEvaluatorSpringComponent(ExposablePropertyPlaceholderConfigurer propertyConfigurer)
+    {
+        String jythonVersion = propertyConfigurer.getResolvedProps().getProperty("jython-version");
+        if ("2.7".equals(jythonVersion))
+        {
+            Evaluator.setFactory(new Jython27EvaluatorFactory());
+        } else if ("2.5".equals(jythonVersion))
+        {
+            Evaluator.setFactory(new Jython25EvaluatorFactory());
+        } else
+        {
+            throw new BeanInitializationException("The jython-version property must be specified. Since version 16.04 ");
+        }
+    }
+}
diff --git a/common/source/java/ch/systemsx/cisd/common/jython/v25/Evaluator25.java b/common/source/java/ch/systemsx/cisd/common/jython/v25/Evaluator25.java
new file mode 100644
index 00000000000..f5f91cd5690
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/jython/v25/Evaluator25.java
@@ -0,0 +1,532 @@
+/*
+ * Copyright 2009 ETH Zuerich, CISD
+ *
+ * Licensed 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.
+ */
+
+package ch.systemsx.cisd.common.jython.v25;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.commons.lang.StringUtils;
+import org.python.core.CompileMode;
+import org.python.core.CompilerFlags;
+import org.python.core.Py;
+import org.python.core.PyBoolean;
+import org.python.core.PyCode;
+import org.python.core.PyException;
+import org.python.core.PyFloat;
+import org.python.core.PyFunction;
+import org.python.core.PyInteger;
+import org.python.core.PyList;
+import org.python.core.PyLong;
+import org.python.core.PyNone;
+import org.python.core.PyObject;
+import org.python.core.PyString;
+import org.python.core.PyStringMap;
+import org.python.core.PySystemState;
+import org.python.core.PyTraceback;
+
+import ch.systemsx.cisd.common.jython.PythonInterpreter;
+import ch.systemsx.cisd.common.jython.evaluator.Evaluator;
+import ch.systemsx.cisd.common.jython.evaluator.Evaluator.ReturnType;
+import ch.systemsx.cisd.common.jython.evaluator.EvaluatorException;
+import ch.systemsx.cisd.common.jython.evaluator.IJythonEvaluator;
+import ch.systemsx.cisd.common.shared.basic.string.CommaSeparatedListBuilder;
+
+/**
+ * A class for evaluating expressions, based on Jython 2.5.
+ * <p>
+ * This class is optimized for evaluating the same expression with a different set of variables repeatedly and efficient. The mode of usage of this
+ * class is:
+ * <ol>
+ * <li>Construct an {@link Evaluator25} with an appropriate expression.</li>
+ * <li>Set all variables needed for evaluation via {@link #set(String, Object)}</li>
+ * <li>Call one of {@link #getType()}, {@link #evalAsString}, {@link #evalToBoolean()}, {@link #evalToInt()}, {@link #evalToBigInt()},
+ * {@link #evalToDouble()}.</li>
+ * <li>Repeat from step 2</li>
+ * </ol>
+ * 
+ * @author Bernd Rinn
+ */
+public final class Evaluator25 implements IJythonEvaluator
+{
+    private final PythonInterpreter interpreter;
+
+    private final String expression;
+
+    private final PyCode compiledExpression;
+
+    /**
+     * Call once before using the object to initialize.
+     */
+    public static void initialize()
+    {
+        PySystemState.initialize();
+    }
+
+    /**
+     * Creates a new {@link Evaluator25} with file system access blocked.
+     * 
+     * @param expression The expression to evaluate.
+     */
+    public Evaluator25(String expression) throws EvaluatorException
+    {
+        this(expression, null, null);
+    }
+
+    /**
+     * Creates a new {@link Evaluator25} with file system access blocked.
+     * 
+     * @param expression The expression to evaluate.
+     * @param supportFunctionsOrNull If not <code>null</code>, all public static methods of the given class will be available to the evaluator as
+     *            "supporting functions".
+     * @param initialScriptOrNull If not <code>null</code>, this has to be a valid (Python) script which is evaluated initially, e.g. to define some
+     *            new functions. Note: this script is trusted, so don't run any unvalidated code here!
+     */
+    public Evaluator25(String expression, Class<?> supportFunctionsOrNull, String initialScriptOrNull)
+            throws EvaluatorException
+    {
+        this(expression, null, null, supportFunctionsOrNull, initialScriptOrNull, true);
+    }
+
+    /**
+     * Creates a new {@link Evaluator25}.
+     * 
+     * @param expression The expression to evaluate.
+     * @param supportFunctionsOrNull If not <code>null</code>, all public static methods of the given class will be available to the evaluator as
+     *            "supporting functions".
+     * @param initialScriptOrNull If not <code>null</code>, this has to be a valid (Python) script which is evaluated initially, e.g. to define some
+     *            new functions. Note: this script is trusted, so don't run any unvalidated code here!
+     * @param blockFileAccess If <code>true</code> the script will not be able to open files.
+     */
+    public Evaluator25(String expression, String[] pythonPath, String scriptPath, Class<?> supportFunctionsOrNull,
+            String initialScriptOrNull, boolean blockFileAccess) throws EvaluatorException
+    {
+        if (Evaluator.isMultiline(expression))
+        {
+            throw new EvaluatorException("Expression '" + expression + "' contains line breaks");
+        }
+
+        this.interpreter = PythonInterpreter.createIsolatedPythonInterpreter();
+        this.interpreter.addToPath(pythonPath);
+
+        // Security: do not allow file access.
+        try
+        {
+            if (blockFileAccess)
+            {
+                interpreter.exec("def open():\n   pass");
+            }
+            if (supportFunctionsOrNull != null)
+            {
+                interpreter.exec("from " + supportFunctionsOrNull.getCanonicalName() + " import *");
+            }
+            if (initialScriptOrNull != null)
+            {
+                // we need to inject the __file__ variable to import third party python libraries
+                // that are added to the system path inside the python script
+                if (scriptPath != null)
+                {
+                    interpreter.exec("__file__='" + scriptPath + "'");
+                }
+                interpreter.exec(initialScriptOrNull);
+            }
+            this.expression = expression;
+
+            this.compiledExpression = doCompile(expression);
+        } catch (PyException ex)
+        {
+            throw toEvaluatorException(ex);
+        }
+    }
+
+    /**
+     * Returns <code>true</code> if specified function is defined in the script.
+     */
+    @Override
+    public boolean hasFunction(String functionName)
+    {
+        PyObject pyObject = interpreter.get(functionName);
+        return pyObject instanceof PyFunction;
+    }
+
+    /**
+     * Evaluates specified function with specified arguments. The arguments are turned into Python Strings if they are Java {@link String} objects.
+     * The return value of the function is returned as a Java object or <code>null</code>.
+     * 
+     * @throws EvaluatorException if evaluation fails.
+     */
+    @Override
+    public Object evalFunction(String functionName, Object... args)
+    {
+        try
+        {
+            PyObject pyObject = interpreter.get(functionName);
+            if (pyObject == null)
+            {
+                throw new PyException(new PyString("Unknown function"), functionName);
+            }
+            if (pyObject instanceof PyFunction == false)
+            {
+                throw new PyException(new PyString("Not a function"), "'" + functionName
+                        + "' is of type " + pyObject.getType().getName() + ".");
+            }
+            PyFunction func = (PyFunction) pyObject;
+            PyObject[] pyArgs = new PyObject[args.length];
+            for (int i = 0; i < args.length; i++)
+            {
+                pyArgs[i] = translateToPython(args[i]);
+            }
+            PyObject result = func.__call__(pyArgs);
+            return translateToJava(result);
+        } catch (PyException ex)
+        {
+            CommaSeparatedListBuilder builder = new CommaSeparatedListBuilder();
+            for (Object argument : args)
+            {
+                builder.append(argument);
+            }
+            throw toEvaluatorException(ex, functionName + "(" + builder + ")");
+        }
+    }
+
+    private PyObject translateToPython(Object javaObject)
+    {
+        if (javaObject instanceof String)
+        {
+            return new PyString((String) javaObject);
+        }
+        return Py.java2py(javaObject);
+    }
+
+    /**
+     * @return compiled <var>expression</var>
+     * @throws EvaluatorException if compilation fails
+     */
+    private static PyCode doCompile(String expression) throws EvaluatorException
+    {
+        try
+        {
+            return Py.compile_flags("__result__=(" + expression + ")", "expression: " + expression,
+                    CompileMode.exec, new CompilerFlags());
+        } catch (PyException ex)
+        {
+            throw toEvaluatorException(ex, expression);
+        }
+    }
+
+    /**
+     * Sets the variable <var>name</var> to <var>value</var> in the evaluator's name space.
+     */
+    @Override
+    public void set(String name, Object value)
+    {
+        interpreter.set(name, value);
+    }
+
+    @Override
+    public Object get(String name)
+    {
+        return interpreter.get(name);
+    }
+
+    /**
+     * Deletes the variable <var>name</var> from the evaluator's name space.
+     */
+    @Override
+    public void delete(String name)
+    {
+        interpreter.getLocals().__delitem__(name);
+    }
+
+    /**
+     * Returns <code>true</code> if and only if the variable <var>name</var> exists in the evaluator's name space.
+     */
+    @Override
+    public boolean has(String name)
+    {
+        return ((PyStringMap) interpreter.getLocals()).has_key(new PyString(name));
+    }
+
+    /**
+     * Returns the {@link ReturnType} of the expression of this evaluator.
+     */
+    @Override
+    public ReturnType getType()
+    {
+        doEval();
+        final Object obj = getInterpreterResult();
+        if (obj instanceof PyBoolean)
+        {
+            return ReturnType.BOOLEAN;
+        } else if (obj instanceof PyInteger)
+        {
+            return ReturnType.INTEGER;
+        } else if (obj instanceof PyLong)
+        {
+            return ReturnType.BIGINT;
+        } else if (obj instanceof PyFloat)
+        {
+            return ReturnType.DOUBLE;
+        } else if (obj instanceof PyString)
+        {
+            return ReturnType.STRING;
+        } else
+        {
+            return ReturnType.OTHER;
+        }
+    }
+
+    /**
+     * Evaluates the expression of this evaluator and returns the result. Use this method if you do not know what will be the result type.
+     * <p>
+     * <i>This is a legacy function to mimic the old Jython 2.2 Evaluator's behavior which will only return Long, Double or String and doesn't know
+     * boolean.</i>
+     * 
+     * @return evaluation result which can be of Long, Double or String type. All other types are converted to String representation except
+     *         {@link PyNone} that represents null value and will be converted to <code>null</code>.
+     */
+    @Override
+    public Object evalLegacy2_2()
+    {
+        doEval();
+        final PyObject obj = getInterpreterResult();
+        Object result = translateToJavaLegacy(obj);
+        if (result != null && result instanceof Long == false && result instanceof Double == false
+                && result instanceof String == false)
+        {
+            return result.toString();
+        }
+        return result;
+    }
+
+    /**
+     * Evaluates the expression of this evaluator and returns the result. Use this method if you do not know what will be the result type.
+     * 
+     * @return evaluation result as translated by the Jython interpreter..
+     */
+    @Override
+    public Object eval()
+    {
+        doEval();
+        return translateToJava(getInterpreterResult());
+    }
+
+    private Object translateToJavaLegacy(final PyObject obj)
+    {
+        if (obj instanceof PyInteger)
+        {
+            return new Long(((PyInteger) obj).getValue());
+        } else if (obj instanceof PyLong)
+        {
+            return new Long(((PyLong) obj).getValue().longValue());
+        } else if (obj instanceof PyFloat)
+        {
+            return new Double(((PyFloat) obj).getValue());
+        } else if (obj instanceof PyNone)
+        {
+            return null;
+        } else if (obj instanceof PyList)
+        {
+            PyList pyList = (PyList) obj;
+            PyObject[] array = pyList.getArray();
+            List<Object> list = new ArrayList<Object>();
+            for (int i = 0, n = pyList.size(); i < n; i++)
+            {
+                list.add(translateToJavaLegacy(array[i]));
+            }
+            return list;
+        } else
+        {
+            return translateToJava(obj);
+        }
+    }
+
+    private Object translateToJava(final PyObject obj)
+    {
+        return (obj == null) ? null : obj.__tojava__(Object.class);
+    }
+
+    private PyObject getInterpreterResult()
+    {
+        return interpreter.get("__result__");
+    }
+
+    /**
+     * Evaluates the expression of this evaluator and returns the result, assuming that the expression has a boolean return type.
+     */
+    @Override
+    public boolean evalToBoolean() throws EvaluatorException
+    {
+        doEval();
+        try
+        {
+            return ((PyBoolean) getInterpreterResult()).getBooleanValue();
+        } catch (ClassCastException ex)
+        {
+            final ReturnType type = getType();
+            throw new EvaluatorException("Expected a result of type " + ReturnType.BOOLEAN
+                    + ", found " + type);
+        }
+    }
+
+    /**
+     * Evaluates the expression of this evaluator and returns the result, assuming that the expression has an integer return type.
+     */
+    @Override
+    public int evalToInt() throws EvaluatorException
+    {
+        doEval();
+        try
+        {
+            return ((PyInteger) getInterpreterResult()).getValue();
+        } catch (ClassCastException ex)
+        {
+            final ReturnType type = getType();
+            throw new EvaluatorException("Expected a result of type " + ReturnType.INTEGER
+                    + ", found " + type);
+        }
+    }
+
+    /**
+     * Evaluates the expression of this evaluator and returns the result, assuming that the expression has a big integer return type.
+     */
+    @Override
+    public BigInteger evalToBigInt() throws EvaluatorException
+    {
+        doEval();
+        try
+        {
+            return ((PyLong) getInterpreterResult()).getValue();
+        } catch (ClassCastException ex)
+        {
+            final ReturnType type = getType();
+            throw new EvaluatorException("Expected a result of type " + ReturnType.BIGINT
+                    + ", found " + type);
+        }
+    }
+
+    /**
+     * Evaluates the expression of this evaluator and returns the result, assuming that the expression has a floating point (double) return type.
+     */
+    @Override
+    public double evalToDouble() throws EvaluatorException
+    {
+        doEval();
+        try
+        {
+            return ((PyFloat) getInterpreterResult()).getValue();
+        } catch (ClassCastException ex)
+        {
+            final ReturnType type = getType();
+            throw new EvaluatorException("Expected a result of type " + ReturnType.DOUBLE
+                    + ", found " + type);
+        }
+    }
+
+    /**
+     * Evaluates the expression of this evaluator and returns the result as a String. This method can always be called.
+     * <p>
+     * <i>This is a legacy function to mimic the old Jython 2.2 Evaluator's behavior which first translates to Long and Double and doesn't know
+     * boolean.</i>
+     * <p>
+     * NOTE: null will be returned if expression results in {@link PyNone}
+     */
+    @Override
+    public String evalAsStringLegacy2_2() throws EvaluatorException
+    {
+        Object result = evalLegacy2_2();
+        return result == null ? null : result.toString();
+    }
+
+    /**
+     * Evaluates the expression of this evaluator and returns the result as a String. This method can always be called.
+     * <p>
+     * NOTE: null will be returned if expression results in {@link PyNone}
+     */
+    @Override
+    public String evalAsString() throws EvaluatorException
+    {
+        Object result = eval();
+        return result == null ? null : result.toString();
+    }
+
+    private void doEval() throws EvaluatorException
+    {
+        try
+        {
+            interpreter.exec(compiledExpression);
+        } catch (PyException ex)
+        {
+            throw toEvaluatorException(ex);
+        }
+    }
+
+    private EvaluatorException toEvaluatorException(PyException ex)
+    {
+        return toEvaluatorException(ex, expression);
+    }
+
+    private static EvaluatorException toEvaluatorException(PyException ex, String expressionOrNull)
+    {
+        Throwable exception = ex;
+        PyObject value = ex.value;
+        Object object = value.__tojava__(Object.class);
+        if (object instanceof Throwable)
+        {
+            exception = (Throwable) object;
+        }
+        String msg = extractExceptionMessage(ex);
+        if (expressionOrNull != null)
+        {
+            PyTraceback traceback = ex.traceback;
+            String details =
+                    traceback == null ? "" : "occurred in line " + traceback.tb_lineno
+                            + " of the script when ";
+            msg = "Error " + details + "evaluating '" + expressionOrNull + "': " + msg;
+        }
+        return new EvaluatorException(msg, exception);
+    }
+
+    private static String extractExceptionMessage(PyException ex)
+    {
+        final String[] description = StringUtils.split(ex.toString(), '\n');
+        return description[description.length - 1];
+    }
+
+    @Override
+    public void releaseResources()
+    {
+        interpreter.releaseResources();
+    }
+
+    @Override
+    public Collection<String> getGlobalVariables()
+    {
+        Set<String> results = new HashSet<String>();
+        PyStringMap locals = (PyStringMap) interpreter.getLocals();
+        for (Object key : locals.keys())
+        {
+            results.add(key.toString());
+        }
+        return Collections.unmodifiableCollection(results);
+    }
+
+}
diff --git a/common/source/java/ch/systemsx/cisd/common/jython/v25/Jython25EvaluatorFactory.java b/common/source/java/ch/systemsx/cisd/common/jython/v25/Jython25EvaluatorFactory.java
new file mode 100644
index 00000000000..34a4391e3ea
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/jython/v25/Jython25EvaluatorFactory.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2016 ETH Zuerich, CISD
+ *
+ * Licensed 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.
+ */
+
+package ch.systemsx.cisd.common.jython.v25;
+
+import ch.systemsx.cisd.common.jython.evaluator.EvaluatorException;
+import ch.systemsx.cisd.common.jython.evaluator.IJythonEvaluator;
+import ch.systemsx.cisd.common.jython.evaluator.IJythonEvaluatorFactory;
+
+/**
+ * @author Jakub Straszewski
+ */
+public class Jython25EvaluatorFactory implements IJythonEvaluatorFactory
+{
+
+    @Override
+    public void initialize()
+    {
+        Evaluator25.initialize();
+    }
+
+    @Override
+    public IJythonEvaluator create(String expression) throws EvaluatorException
+    {
+        return new Evaluator25(expression);
+    }
+
+    @Override
+    public IJythonEvaluator create(String expression, Class<?> supportFunctionsOrNull, String initialScriptOrNull) throws EvaluatorException
+    {
+        return new Evaluator25(expression, supportFunctionsOrNull, initialScriptOrNull);
+    }
+
+    @Override
+    public IJythonEvaluator create(String expression, String[] pythonPath, String scriptPath, Class<?> supportFunctionsOrNull,
+            String initialScriptOrNull,
+            boolean blockFileAccess) throws EvaluatorException
+    {
+        return new Evaluator25(expression, pythonPath, scriptPath, supportFunctionsOrNull, initialScriptOrNull, blockFileAccess);
+    }
+
+}
diff --git a/common/source/java/ch/systemsx/cisd/common/jython/v27/Evaluator27.java b/common/source/java/ch/systemsx/cisd/common/jython/v27/Evaluator27.java
index 6fdd4204b3f..8d527f6971c 100644
--- a/common/source/java/ch/systemsx/cisd/common/jython/v27/Evaluator27.java
+++ b/common/source/java/ch/systemsx/cisd/common/jython/v27/Evaluator27.java
@@ -25,7 +25,6 @@ import java.util.List;
 import java.util.Set;
 
 import org.apache.commons.lang.StringUtils;
-import org.python.core.PySystemState;
 import org.python27.core.CompileMode;
 import org.python27.core.CompilerFlags;
 import org.python27.core.Py;
@@ -41,9 +40,13 @@ import org.python27.core.PyNone;
 import org.python27.core.PyObject;
 import org.python27.core.PyString;
 import org.python27.core.PyStringMap;
+import org.python27.core.PySystemState;
 import org.python27.core.PyTraceback;
 
+import ch.systemsx.cisd.common.jython.evaluator.Evaluator;
+import ch.systemsx.cisd.common.jython.evaluator.Evaluator.ReturnType;
 import ch.systemsx.cisd.common.jython.evaluator.EvaluatorException;
+import ch.systemsx.cisd.common.jython.evaluator.IJythonEvaluator;
 import ch.systemsx.cisd.common.shared.basic.string.CommaSeparatedListBuilder;
 
 /**
@@ -56,7 +59,7 @@ import ch.systemsx.cisd.common.shared.basic.string.CommaSeparatedListBuilder;
  * 
  * @author Ganime Akin
  */
-public final class Evaluator27
+public final class Evaluator27 implements IJythonEvaluator
 {
     private final PythonInterpreter27 interpreter;
 
@@ -72,14 +75,6 @@ public final class Evaluator27
         PySystemState.initialize();
     }
 
-    /**
-     * The return type of this expression.
-     */
-    public enum ReturnType
-    {
-        BOOLEAN, INTEGER, BIGINT, DOUBLE, STRING, OTHER
-    }
-
     /**
      * Creates a new {@link Evaluator27} with file system access blocked.
      * 
@@ -109,8 +104,8 @@ public final class Evaluator27
      * Creates a new {@link Evaluator27}.
      * 
      * @param expression The expression to evaluate.
-     * @param scriptPath This is passed in so that we can set the __file__ variable to a fixed path to be able to use third party libraries
-     *            copied to the same the folder as the Python script
+     * @param scriptPath This is passed in so that we can set the __file__ variable to a fixed path to be able to use third party libraries copied to
+     *            the same the folder as the Python script
      * @param supportFunctionsOrNull If not <code>null</code>, all public static methods of the given class will be available to the evaluator as
      *            "supporting functions".
      * @param initialScriptOrNull If not <code>null</code>, this has to be a valid (Python) script which is evaluated initially, e.g. to define some
@@ -120,7 +115,7 @@ public final class Evaluator27
     public Evaluator27(String expression, String[] pythonPath, String scriptPath, Class<?> supportFunctionsOrNull,
             String initialScriptOrNull, boolean blockFileAccess) throws EvaluatorException
     {
-        if (isMultiline(expression))
+        if (Evaluator.isMultiline(expression))
         {
             throw new EvaluatorException("Expression '" + expression + "' contains line breaks");
         }
@@ -143,7 +138,10 @@ public final class Evaluator27
             {
                 // we need to inject the __file__ variable to import third party python libraries
                 // that are added to the system path inside the python script
-                interpreter.exec("__file__='" + scriptPath + "'");
+                if (scriptPath != null)
+                {
+                    interpreter.exec("__file__='" + scriptPath + "'");
+                }
                 interpreter.exec(initialScriptOrNull);
             }
             this.expression = expression;
@@ -158,6 +156,7 @@ public final class Evaluator27
     /**
      * Returns <code>true</code> if specified function is defined in the script.
      */
+    @Override
     public boolean hasFunction(String functionName)
     {
         PyObject pyObject = interpreter.get(functionName);
@@ -170,6 +169,7 @@ public final class Evaluator27
      * 
      * @throws EvaluatorException if evaluation fails.
      */
+    @Override
     public Object evalFunction(String functionName, Object... args)
     {
         try
@@ -231,11 +231,13 @@ public final class Evaluator27
     /**
      * Sets the variable <var>name</var> to <var>value</var> in the evaluator's name space.
      */
+    @Override
     public void set(String name, Object value)
     {
         interpreter.set(name, value);
     }
 
+    @Override
     public Object get(String name)
     {
         return interpreter.get(name);
@@ -244,6 +246,7 @@ public final class Evaluator27
     /**
      * Deletes the variable <var>name</var> from the evaluator's name space.
      */
+    @Override
     public void delete(String name)
     {
         interpreter.getLocals().__delitem__(name);
@@ -252,6 +255,7 @@ public final class Evaluator27
     /**
      * Returns <code>true</code> if and only if the variable <var>name</var> exists in the evaluator's name space.
      */
+    @Override
     public boolean has(String name)
     {
         return ((PyStringMap) interpreter.getLocals()).has_key(new PyString(name));
@@ -260,6 +264,7 @@ public final class Evaluator27
     /**
      * Returns the {@link ReturnType} of the expression of this evaluator.
      */
+    @Override
     public ReturnType getType()
     {
         doEval();
@@ -294,6 +299,7 @@ public final class Evaluator27
      * @return evaluation result which can be of Long, Double or String type. All other types are converted to String representation except
      *         {@link PyNone} that represents null value and will be converted to <code>null</code>.
      */
+    @Override
     public Object evalLegacy2_2()
     {
         doEval();
@@ -312,6 +318,7 @@ public final class Evaluator27
      * 
      * @return evaluation result as translated by the Jython interpreter..
      */
+    @Override
     public Object eval()
     {
         doEval();
@@ -361,6 +368,7 @@ public final class Evaluator27
     /**
      * Evaluates the expression of this evaluator and returns the result, assuming that the expression has a boolean return type.
      */
+    @Override
     public boolean evalToBoolean() throws EvaluatorException
     {
         doEval();
@@ -378,6 +386,7 @@ public final class Evaluator27
     /**
      * Evaluates the expression of this evaluator and returns the result, assuming that the expression has an integer return type.
      */
+    @Override
     public int evalToInt() throws EvaluatorException
     {
         doEval();
@@ -395,6 +404,7 @@ public final class Evaluator27
     /**
      * Evaluates the expression of this evaluator and returns the result, assuming that the expression has a big integer return type.
      */
+    @Override
     public BigInteger evalToBigInt() throws EvaluatorException
     {
         doEval();
@@ -412,6 +422,7 @@ public final class Evaluator27
     /**
      * Evaluates the expression of this evaluator and returns the result, assuming that the expression has a floating point (double) return type.
      */
+    @Override
     public double evalToDouble() throws EvaluatorException
     {
         doEval();
@@ -434,6 +445,7 @@ public final class Evaluator27
      * <p>
      * NOTE: null will be returned if expression results in {@link PyNone}
      */
+    @Override
     public String evalAsStringLegacy2_2() throws EvaluatorException
     {
         Object result = evalLegacy2_2();
@@ -445,6 +457,7 @@ public final class Evaluator27
      * <p>
      * NOTE: null will be returned if expression results in {@link PyNone}
      */
+    @Override
     public String evalAsString() throws EvaluatorException
     {
         Object result = eval();
@@ -494,16 +507,13 @@ public final class Evaluator27
         return description[description.length - 1];
     }
 
-    public static boolean isMultiline(String expression)
-    {
-        return expression.indexOf('\n') >= 0;
-    }
-
+    @Override
     public void releaseResources()
     {
         interpreter.releaseResources();
     }
 
+    @Override
     public Collection<String> getGlobalVariables()
     {
         Set<String> results = new HashSet<String>();
diff --git a/common/source/java/ch/systemsx/cisd/common/jython/v27/Jython27EvaluatorFactory.java b/common/source/java/ch/systemsx/cisd/common/jython/v27/Jython27EvaluatorFactory.java
new file mode 100644
index 00000000000..b6dc37a3f97
--- /dev/null
+++ b/common/source/java/ch/systemsx/cisd/common/jython/v27/Jython27EvaluatorFactory.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2016 ETH Zuerich, CISD
+ *
+ * Licensed 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.
+ */
+
+package ch.systemsx.cisd.common.jython.v27;
+
+import ch.systemsx.cisd.common.jython.evaluator.EvaluatorException;
+import ch.systemsx.cisd.common.jython.evaluator.IJythonEvaluator;
+import ch.systemsx.cisd.common.jython.evaluator.IJythonEvaluatorFactory;
+
+/**
+ * @author Jakub Straszewski
+ */
+public class Jython27EvaluatorFactory implements IJythonEvaluatorFactory
+{
+
+    @Override
+    public void initialize()
+    {
+        Evaluator27.initialize();
+    }
+
+    @Override
+    public IJythonEvaluator create(String expression) throws EvaluatorException
+    {
+        return new Evaluator27(expression);
+    }
+
+    @Override
+    public IJythonEvaluator create(String expression, Class<?> supportFunctionsOrNull, String initialScriptOrNull) throws EvaluatorException
+    {
+        return new Evaluator27(expression, supportFunctionsOrNull, initialScriptOrNull);
+    }
+
+    @Override
+    public IJythonEvaluator create(String expression, String[] pythonPath, String scriptPath, Class<?> supportFunctionsOrNull,
+            String initialScriptOrNull,
+            boolean blockFileAccess) throws EvaluatorException
+    {
+        return new Evaluator27(expression, pythonPath, scriptPath, supportFunctionsOrNull, initialScriptOrNull, blockFileAccess);
+    }
+
+}
\ No newline at end of file
diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/evaluator/Evaluator25Test.java b/common/sourceTest/java/ch/systemsx/cisd/common/evaluator/Evaluator25Test.java
new file mode 100644
index 00000000000..97812ee3362
--- /dev/null
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/evaluator/Evaluator25Test.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2016 ETH Zuerich, CISD
+ *
+ * Licensed 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.
+ */
+
+package ch.systemsx.cisd.common.evaluator;
+
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.common.jython.evaluator.IJythonEvaluatorFactory;
+import ch.systemsx.cisd.common.jython.v25.Jython25EvaluatorFactory;
+
+/**
+ * @author Jakub Straszewski
+ */
+@Test
+public class Evaluator25Test extends EvaluatorTest
+{
+    private IJythonEvaluatorFactory factory;
+
+    @Override
+    public IJythonEvaluatorFactory getFactory()
+    {
+        if (factory == null)
+        {
+            factory = new Jython25EvaluatorFactory();
+        }
+        return factory;
+    }
+
+}
diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/evaluator/Evaluator27Test.java b/common/sourceTest/java/ch/systemsx/cisd/common/evaluator/Evaluator27Test.java
new file mode 100644
index 00000000000..5ff86bab2c9
--- /dev/null
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/evaluator/Evaluator27Test.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 ETH Zuerich, CISD
+ *
+ * Licensed 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.
+ */
+
+package ch.systemsx.cisd.common.evaluator;
+
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.common.jython.evaluator.IJythonEvaluatorFactory;
+import ch.systemsx.cisd.common.jython.v27.Jython27EvaluatorFactory;
+
+/**
+ * @author Jakub Straszewski
+ */
+@Test
+public class Evaluator27Test extends EvaluatorTest
+{
+
+    private IJythonEvaluatorFactory factory;
+
+    @Override
+    public IJythonEvaluatorFactory getFactory()
+    {
+        if (factory == null)
+        {
+            factory = new Jython27EvaluatorFactory();
+        }
+        return factory;
+    }
+
+}
diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/evaluator/EvaluatorTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/evaluator/EvaluatorTest.java
index 0dde2535f5c..be25380d03b 100644
--- a/common/sourceTest/java/ch/systemsx/cisd/common/evaluator/EvaluatorTest.java
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/evaluator/EvaluatorTest.java
@@ -17,36 +17,43 @@
 package ch.systemsx.cisd.common.evaluator;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.commons.io.FileUtils;
 import org.testng.AssertJUnit;
 import org.testng.annotations.BeforeTest;
 import org.testng.annotations.Test;
 
+import ch.systemsx.cisd.common.jython.JythonUtils;
 import ch.systemsx.cisd.common.jython.evaluator.Evaluator;
 import ch.systemsx.cisd.common.jython.evaluator.Evaluator.ReturnType;
 import ch.systemsx.cisd.common.jython.evaluator.EvaluatorException;
+import ch.systemsx.cisd.common.jython.evaluator.IJythonEvaluator;
+import ch.systemsx.cisd.common.jython.evaluator.IJythonEvaluatorFactory;
 
 /**
  * Tests of the {@link Evaluator}.
  * 
  * @author Bernd Rinn
  */
-public class EvaluatorTest extends AssertJUnit
+public abstract class EvaluatorTest extends AssertJUnit
 {
+    public abstract IJythonEvaluatorFactory getFactory();
+
     @BeforeTest
     public void init()
     {
-        Evaluator.initialize();
+        getFactory().initialize();
     }
 
     @Test
     public void testEvalWithNull()
     {
-        final Evaluator eval = new Evaluator("None");
+        final IJythonEvaluator eval = getFactory().create("None");
         assertEquals(null, eval.eval());
         assertEquals(null, eval.evalAsString());
     }
@@ -54,14 +61,14 @@ public class EvaluatorTest extends AssertJUnit
     @Test
     public void testSimpleExpression()
     {
-        final Evaluator eval = new Evaluator("1+1");
+        final IJythonEvaluator eval = getFactory().create("1+1");
         assertEquals(2, eval.evalToInt());
     }
 
     @Test
     public void testExpressionWithVariables()
     {
-        final Evaluator eval = new Evaluator("a*b");
+        final IJythonEvaluator eval = getFactory().create("a*b");
         eval.set("a", 2);
         eval.set("b", 3.1);
         assertEquals(6.2, eval.evalToDouble(), 1e-15);
@@ -70,7 +77,7 @@ public class EvaluatorTest extends AssertJUnit
     @Test
     public void testExpressionWithVariablesMultipleEvaluations()
     {
-        final Evaluator eval = new Evaluator("a*b");
+        final IJythonEvaluator eval = getFactory().create("a*b");
         eval.set("a", 2);
         eval.set("b", 3.1);
         assertEquals(6.2, eval.evalToDouble(), 1e-15);
@@ -82,7 +89,7 @@ public class EvaluatorTest extends AssertJUnit
     @Test
     public void testVariables()
     {
-        final Evaluator eval = new Evaluator("a");
+        final IJythonEvaluator eval = getFactory().create("a");
         eval.set("a", 2);
         assertTrue(eval.has("a"));
         assertFalse(eval.has("b"));
@@ -93,9 +100,9 @@ public class EvaluatorTest extends AssertJUnit
     @Test
     public void testBuiltInFunctionEval()
     {
-        final Evaluator eval = new Evaluator("min(1,2)");
+        final IJythonEvaluator eval = getFactory().create("min(1,2)");
         assertEquals(1, eval.evalToInt());
-        final Evaluator eval2 = new Evaluator("max(1,2)");
+        final IJythonEvaluator eval2 = getFactory().create("max(1,2)");
         assertEquals(2, eval2.evalToInt());
     }
 
@@ -129,28 +136,26 @@ public class EvaluatorTest extends AssertJUnit
     @Test
     public void testFunctionEval()
     {
-        Evaluator eval = new Evaluator("MinInt(1,2)", Functions.class, null);
+        IJythonEvaluator eval = getFactory().create("MinInt(1,2)", Functions.class, null);
         assertEquals(1, eval.evalToInt());
-        eval = new Evaluator("MinDbl([1,2,0.1])", Functions.class, null);
+        eval = getFactory().create("MinDbl([1,2,0.1])", Functions.class, null);
         assertEquals(0.1, eval.evalToDouble(), 1e-15);
-        eval = new Evaluator("MinDbl(v)", Functions.class, null);
-        eval.set("v", new double[]
-        { 1, 2, -99.9, 3 });
+        eval = getFactory().create("MinDbl(v)", Functions.class, null);
+        eval.set("v", new double[] { 1, 2, -99.9, 3 });
         assertEquals(-99.9, eval.evalToDouble(), 1e-15);
     }
 
     @Test
     public void testInitialScript()
     {
-        final Evaluator eval =
-                new Evaluator("hello()", null, "def hello():\n   return 'Hello World'");
+        final IJythonEvaluator eval = getFactory().create("hello()", null, "def hello():\n   return 'Hello World'");
         assertEquals("Hello World", eval.evalAsString());
     }
 
     @Test
     public void testGetTypeChanging()
     {
-        final Evaluator eval = new Evaluator("a");
+        final IJythonEvaluator eval = getFactory().create("a");
         eval.set("a", 2);
         assertEquals(ReturnType.INTEGER, eval.getType());
         eval.set("a", "2");
@@ -160,26 +165,26 @@ public class EvaluatorTest extends AssertJUnit
     @Test(expectedExceptions = EvaluatorException.class)
     public void testInvalidExpression()
     {
-        new Evaluator("pass");
+        getFactory().create("pass");
     }
 
     @Test(expectedExceptions = EvaluatorException.class)
     public void testInvalidExpressionWithLineBreaks()
     {
-        new Evaluator("1\nimport os\nos.remove('/etc/passwd')");
+        getFactory().create("1\nimport os\nos.remove('/etc/passwd')");
     }
 
     @Test(expectedExceptions = EvaluatorException.class)
     public void testMissingVariable()
     {
-        final Evaluator eval = new Evaluator("a");
+        final IJythonEvaluator eval = getFactory().create("a");
         eval.evalAsString();
     }
 
     @Test
     public void testInvalidReturnValue()
     {
-        final Evaluator eval = new Evaluator("a");
+        final IJythonEvaluator eval = getFactory().create("a");
         eval.set("a", true);
         assertEquals(ReturnType.BOOLEAN, eval.getType());
         assertEquals("true", eval.evalAsString());
@@ -199,8 +204,7 @@ public class EvaluatorTest extends AssertJUnit
     {
         final File tagFile = new File("targets/newfile");
         tagFile.delete();
-        final Evaluator eval =
-                new Evaluator("open('targets/newfile', 'w').write('Should not work')");
+        final IJythonEvaluator eval = getFactory().create("open('targets/newfile', 'w').write('Should not work')");
         try
         {
             eval.evalAsString();
@@ -217,25 +221,78 @@ public class EvaluatorTest extends AssertJUnit
     {
         final File tagFile = new File("targets/newfile");
         tagFile.delete();
-        final Evaluator eval =
-                new Evaluator("open('targets/newfile', 'w').write('Should work')", null, null, null,
-                        false);
+        final IJythonEvaluator eval = getFactory().create("open('targets/newfile', 'w').write('Should work')", null, null, null, null,
+                false);
         eval.evalAsString();
         assertTrue(tagFile.exists());
     }
 
+    @Test
+    void testImportExternalPlugin() throws IOException
+    {
+        final File dir = new File("targets/testModule");
+        dir.mkdirs();
+        final File importedScriptFile = new File("targets/test/testmodule.py");
+        FileUtils.writeStringToFile(importedScriptFile, "def test_hello_world(): return \"hello world\"");
+
+        String script =
+                "import os.path\n" +
+                        "import sys\n" +
+                        "print __file__\n" +
+                        "def package_folder(module):\n" +
+                        "    return os.path.dirname(os.path.abspath(module))\n" +
+                        "\n" +
+                        "\n" +
+                        "def inject_local_package(name):\n" +
+                        "    \"\"\"patches sys.path to prefer / find packages provided next to this script\"\"\"\n" +
+                        "    here = package_folder(__file__)\n" +
+                        "    sys.path.insert(0, os.path.join(here, name))\n" +
+                        "\n" +
+                        "\n" +
+                        "def import_and_check_location(package_name):\n" +
+                        "    \"\"\"checks if given package was imported from right place\"\"\"\n" +
+                        "\n" +
+                        "    print \"import %s: \" % package_name,\n" +
+                        "    package = __import__(package_name)\n" +
+                        "    print \"succeeded\" \n" +
+                        "\n" +
+                        "    print \"check location: \",\n" +
+                        "    found_location = package_folder(package.__file__)\n" +
+                        "    here = package_folder(__file__)\n" +
+                        "    if found_location.startswith(here):\n" +
+                        "        print \"ok\"\n" +
+                        "    else:\n" +
+                        "        print \"failed: package is imported from %s\" % found_location\n" +
+                        "\n" +
+                        "\n" +
+                        "inject_local_package(\"testmodule\")\n" +
+                        "import_and_check_location(\"testmodule\")\n" +
+                        "import testmodule\n" +
+                        "def test_from_module():\n" +
+                        "  return testmodule.test_hello_world()\n" +
+                        "";
+
+        File scriptFile = new File("targets/test/file.py");
+        String scriptPath = scriptFile.getAbsolutePath();
+        FileUtils.writeStringToFile(scriptFile, script);
+
+        final IJythonEvaluator eval =
+                getFactory().create("test_from_module()", JythonUtils.getScriptDirectoryPythonPath(scriptPath), scriptPath, null, script, false);
+
+        assertEquals("hello world", eval.evalFunction("test_from_module").toString());
+    }
+
     @Test
     public void testEvalFunctionWithStringArgument()
     {
-        Evaluator evaluator = new Evaluator("", null, "def hello(name):\n  return 'hello ' + name");
-        assertEquals("hello world", evaluator.evalFunction("hello", "world").toString());
+        IJythonEvaluator eval = getFactory().create("", null, "def hello(name):\n  return 'hello ' + name");
+        assertEquals("hello world", eval.evalFunction("hello", "world").toString());
     }
 
     @Test
     public void testEvalFunctionWithTwoArguments()
     {
-        Evaluator evaluator =
-                new Evaluator("", null, "def get(map, key):\n  return map.get(key)\n");
+        IJythonEvaluator evaluator = getFactory().create("", null, "def get(map, key):\n  return map.get(key)\n");
         Map<String, List<String>> map = new HashMap<String, List<String>>();
         map.put("physicists", Arrays.asList("Newton", "Einstein"));
         Object result = evaluator.evalFunction("get", map, "physicists");
@@ -246,8 +303,8 @@ public class EvaluatorTest extends AssertJUnit
     @Test
     public void testEvalFunctionWhichReturnsAList()
     {
-        Evaluator evaluator = new Evaluator("", null, "def get():\n  return ['a','b']");
-        Object result = evaluator.evalFunction("get");
+        IJythonEvaluator eval = getFactory().create("", null, "def get():\n  return ['a','b']");
+        Object result = eval.evalFunction("get");
         assertEquals("Result " + result.getClass(), true, result instanceof List);
         assertEquals("['a', 'b']", result.toString());
     }
@@ -255,10 +312,10 @@ public class EvaluatorTest extends AssertJUnit
     @Test
     public void testEvalFunctionWithScriptError()
     {
-        Evaluator evaluator = new Evaluator("", null, "def hello(name):\n  return unknown\n");
+        IJythonEvaluator eval = getFactory().create("", null, "def hello(name):\n  return unknown\n");
         try
         {
-            evaluator.evalFunction("hello", "world");
+            eval.evalFunction("hello", "world");
             fail("EvaluatorException expected");
         } catch (EvaluatorException ex)
         {
@@ -270,9 +327,8 @@ public class EvaluatorTest extends AssertJUnit
     @Test
     public void testHasFunction()
     {
-        Evaluator evaluator =
-                new Evaluator("", null, "text = 'hi'\n"
-                        + "def hello(name):\n  return 'hello ' + name");
+        IJythonEvaluator evaluator = getFactory().create("", null, "text = 'hi'\n"
+                + "def hello(name):\n  return 'hello ' + name");
 
         assertEquals(true, evaluator.hasFunction("hello"));
         assertEquals(false, evaluator.hasFunction("text"));
@@ -282,7 +338,7 @@ public class EvaluatorTest extends AssertJUnit
     @Test
     public void testEvalUnkownFunction()
     {
-        Evaluator evaluator = new Evaluator("", null, "def hello(name):\n  return 'hello ' + name");
+        IJythonEvaluator evaluator = getFactory().create("", null, "def hello(name):\n  return 'hello ' + name");
         try
         {
             evaluator.evalFunction("func", "world");
@@ -296,12 +352,11 @@ public class EvaluatorTest extends AssertJUnit
     @Test
     public void testEvalFunctionFunctionNameIsVariableName()
     {
-        Evaluator evaluator =
-                new Evaluator("", null, "text = 'universe'\n"
-                        + "def hello(name):\n  return 'hello ' + name");
+        IJythonEvaluator eval = getFactory().create("", null, "text = 'universe'\n"
+                + "def hello(name):\n  return 'hello ' + name");
         try
         {
-            evaluator.evalFunction("text", "world");
+            eval.evalFunction("text", "world");
             fail("EvaluatorException expected");
         } catch (EvaluatorException ex)
         {
@@ -313,7 +368,7 @@ public class EvaluatorTest extends AssertJUnit
     @Test
     public void testEvalFunctionWithNotEnoughArguments()
     {
-        Evaluator evaluator = new Evaluator("", null, "def hello(name):\n  return 'hello ' + name");
+        IJythonEvaluator evaluator = getFactory().create("", null, "def hello(name):\n  return 'hello ' + name");
         try
         {
             evaluator.evalFunction("hello");
@@ -328,7 +383,7 @@ public class EvaluatorTest extends AssertJUnit
     @Test
     public void testEvalFunctionWithToManyArguments()
     {
-        Evaluator evaluator = new Evaluator("", null, "def hello(name):\n  return 'hello ' + name");
+        IJythonEvaluator evaluator = getFactory().create("", null, "def hello(name):\n  return 'hello ' + name");
         try
         {
             evaluator.evalFunction("hello", "world", "universe");
@@ -343,8 +398,7 @@ public class EvaluatorTest extends AssertJUnit
     @Test
     public void testEvalFunctionWithWrongArgument()
     {
-        Evaluator evaluator =
-                new Evaluator("", null, "def get(map, key):\n  return map.get(key)\n");
+        IJythonEvaluator evaluator = getFactory().create("", null, "def get(map, key):\n  return map.get(key)\n");
         try
         {
             evaluator.evalFunction("get", "world", "universe");
-- 
GitLab