Bug 512618 - PY4J debugger
Implemented generic framework for Python debuggers.
Adapted Jython debugger and added Py4J debugger
Change-Id: I757769e7371f49752421833b326c39bae7d8ce0f
Signed-off-by: Martin Kloesch <martin.kloesch@gmail.com>
diff --git a/features/org.eclipse.ease.lang.python.py4j.feature/.project b/features/org.eclipse.ease.lang.python.py4j.feature/.project
index b569265..61708bd 100644
--- a/features/org.eclipse.ease.lang.python.py4j.feature/.project
+++ b/features/org.eclipse.ease.lang.python.py4j.feature/.project
@@ -12,7 +12,6 @@
</buildCommand>
</buildSpec>
<natures>
- <nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.eclipse.pde.FeatureNature</nature>
</natures>
</projectDescription>
diff --git a/plugins/org.eclipse.ease.lang.python.jython.debugger/.classpath b/plugins/org.eclipse.ease.lang.python.jython.debugger/.classpath
index 4e4726e..cb8e90e 100644
--- a/plugins/org.eclipse.ease.lang.python.jython.debugger/.classpath
+++ b/plugins/org.eclipse.ease.lang.python.jython.debugger/.classpath
@@ -7,6 +7,5 @@
</accessrules>
</classpathentry>
<classpathentry kind="src" path="src/"/>
- <classpathentry kind="src" path="python/"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
diff --git a/plugins/org.eclipse.ease.lang.python.jython.debugger/META-INF/MANIFEST.MF b/plugins/org.eclipse.ease.lang.python.jython.debugger/META-INF/MANIFEST.MF
index ebda646..5fcd523 100644
--- a/plugins/org.eclipse.ease.lang.python.jython.debugger/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.ease.lang.python.jython.debugger/META-INF/MANIFEST.MF
@@ -4,17 +4,11 @@
Bundle-SymbolicName: org.eclipse.ease.lang.python.jython.debugger;singleton:=true
Bundle-Version: 0.5.0.qualifier
Bundle-Vendor: Eclipse.org
-Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.7.0,4.0.0)",
- org.eclipse.debug.core;bundle-version="[3.7.1,4.0.0)",
- org.eclipse.ease,
- org.eclipse.debug.ui;bundle-version="[3.7.102,4.0.0)",
- org.eclipse.jface;bundle-version="[3.7.0,4.0.0)",
- org.eclipse.ui.workbench;bundle-version="[3.7.1,4.0.0)",
- org.eclipse.ui.ide;bundle-version="[3.7.0,4.0.0)",
- org.eclipse.ui.editors;bundle-version="[3.7.0,4.0.0)",
+Require-Bundle: org.eclipse.debug.core;bundle-version="[3.7.1,4.0.0)",
org.jython;bundle-version="[2.5.3,3.0.0)",
- org.eclipse.ease.lang.python.jython
+ org.eclipse.ease,
+ org.eclipse.ease.lang.python.jython,
+ org.eclipse.ease.lang.python
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ActivationPolicy: lazy
-Export-Package: org.eclipse.ease.lang.python.jython.debugger,
- org.eclipse.ease.lang.python.jython.debugger.model
+Export-Package: org.eclipse.ease.lang.python.jython.debugger
diff --git a/plugins/org.eclipse.ease.lang.python.jython.debugger/build.properties b/plugins/org.eclipse.ease.lang.python.jython.debugger/build.properties
index 5421b13..4c63aa0 100644
--- a/plugins/org.eclipse.ease.lang.python.jython.debugger/build.properties
+++ b/plugins/org.eclipse.ease.lang.python.jython.debugger/build.properties
@@ -1,9 +1,6 @@
-source.. = src/,\
- python/
+source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.,\
plugin.xml,\
about.html,\
- python/
-src.includes = python/,\
diff --git a/plugins/org.eclipse.ease.lang.python.jython.debugger/plugin.xml b/plugins/org.eclipse.ease.lang.python.jython.debugger/plugin.xml
index 518cffa..d924aa3 100644
--- a/plugins/org.eclipse.ease.lang.python.jython.debugger/plugin.xml
+++ b/plugins/org.eclipse.ease.lang.python.jython.debugger/plugin.xml
@@ -22,44 +22,4 @@
engineID="org.eclipse.ease.python.jythonDebugger">
</launchExtension>
</extension>
- <extension
- point="org.eclipse.debug.ui.debugModelPresentations">
- <debugModelPresentation
- class="org.eclipse.ease.lang.python.jython.debugger.model.JythonDebugModelPresentation"
- detailsViewerConfiguration="org.eclipse.ease.lang.python.jython.debugger.model.JythonDebugModelPresentation"
- id="org.eclipse.ease.debugModelPresentation.jython">
- </debugModelPresentation>
- </extension>
- <extension
- point="org.eclipse.ui.viewActions">
- <viewContribution
- id="variableViewActions"
- targetID="org.eclipse.debug.ui.VariableView">
- <menu
- id="org.eclipse.ease.debug.ui.variableview.menu"
- label="EASE">
- <groupMarker
- name="ease">
- </groupMarker>
- </menu>
- <action
- class="org.eclipse.ease.lang.python.jython.debugger.actions.FunctionFilterAction"
- helpContextId="show_functions_variable_help_context"
- id="org.eclipse.ease.ui.variableview.show.functions"
- label="Show functions"
- menubarPath="org.eclipse.ease.debug.ui.variableview.menu/ease"
- style="toggle"
- tooltip="Tooltip text">
- </action>
- <action
- class="org.eclipse.ease.lang.python.jython.debugger.actions.ModuleFilterAction"
- helpContextId="show_functions_variable_help_context"
- id="org.eclipse.ease.ui.variableview.show.modules"
- label="Show modules"
- menubarPath="org.eclipse.ease.debug.ui.variableview.menu/ease"
- style="toggle"
- tooltip="Tooltip text">
- </action>
- </viewContribution>
- </extension>
</plugin>
diff --git a/plugins/org.eclipse.ease.lang.python.jython.debugger/python/edb.py b/plugins/org.eclipse.ease.lang.python.jython.debugger/python/edb.py
deleted file mode 100644
index abbe347..0000000
--- a/plugins/org.eclipse.ease.lang.python.jython.debugger/python/edb.py
+++ /dev/null
@@ -1,54 +0,0 @@
-'''
-Copyright (c) 2014 Martin Kloesch
-All rights reserved. This program and the accompanying materials
-are made available under the terms of the Eclipse Public License v1.0
-which accompanies this distribution, and is available at
-http://www.eclipse.org/legal/epl-v10.html
-
-Contributors:
- * Martin Kloesch - initial API and implementation
- * Christian Pontesegger - stripped most parts to simply trace and relay to java
-'''
-# Python std library imports
-import os
-import sys
-import __main__
-
-class CodeTracer:
- '''
- Eclipse Debugger class.
- '''
- _debugger = None
-
- def __init__(self):
- '''
- Default Constructor.
- '''
-
- def set_debugger(self, debugger):
- '''
- Setter method for self._debugger.
-
- :param org.eclipse.ease.lang.python.jython.debugger.JythonDebugger debugger:
- JythonDebugger object to handling communication with Eclipse.
- '''
- self._debugger = debugger
- sys.settrace(self.trace_dispatch)
-
- def trace_dispatch(self, frame, event, arg):
- self._debugger.traceDispatch(frame, event)
- return self.trace_dispatch
-
- def run(self, script, filename):
- '''
- Executes the file given using the bdb.Bdb.run method.
- '''
- code = "{}\n".format(script.getCode())
- compiledCode = compile(code, filename, "exec")
-
- globals = __main__.__dict__
- locals = __main__.__dict__
- exec compiledCode in globals, locals
-
-
-eclipse_jython_debugger = CodeTracer()
diff --git a/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/BreakpointInfo.java b/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/BreakpointInfo.java
deleted file mode 100644
index 7da1875..0000000
--- a/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/BreakpointInfo.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2014 Kloesch Martin
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Martin Kloesch - initial implementation
- *******************************************************************************/
-package org.eclipse.ease.lang.python.jython.debugger;
-
-import java.io.File;
-
-import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.debug.core.model.IBreakpoint;
-import org.eclipse.debug.core.model.LineBreakpoint;
-
-/**
- * Helper class to parse IBreakpoint and have easy access to information in Jython.
- *
- * @author kloeschmartin
- */
-public class BreakpointInfo {
- /**
- * All necessary info for breakpoints (from Jython Edb point of view)
- */
- private String mFilename;
- private int mLinenumber = -1;
- private final String mCondition = null;
- private final int mHitcount = 0;
- private final boolean mTemporary = false;
-
- /**
- * Parses breakpoint info from IBreakpoint to members
- *
- * @param breakpoint
- * : breakpoint to be parsed.
- */
- public BreakpointInfo(final IBreakpoint breakpoint) {
- // Calculate absolute filename (necessary for Jython debugger)
- mFilename = breakpoint.getMarker().getResource().getFullPath().toOSString();
- mFilename = new File(ResourcesPlugin.getWorkspace().getRoot().getLocation().toFile(), mFilename).getAbsolutePath();
-
- // If LineBreakpoint given calculate Linenumber
- if (breakpoint instanceof LineBreakpoint) {
- try {
- mLinenumber = ((LineBreakpoint) breakpoint).getLineNumber();
- } catch (CoreException e) {
- e.printStackTrace();
- }
- }
-
- // Get condition from PyBreakpoint
- // FIXME temporary disabled to get rid of pydev dependency
- // if (breakpoint instanceof PyBreakpoint) {
- // try {
- // mCondition = ((PyBreakpoint) breakpoint).getCondition();
- // } catch (DebugException e) {
- // }
- // }
- }
-
- // ************************************************************
- // Getter methods for necessary information
- // ************************************************************
- public String getFilename() {
- return mFilename;
- }
-
- public int getLinenumber() {
- return mLinenumber;
- }
-
- public String getCondition() {
- return mCondition;
- }
-
- public int getHitcount() {
- return mHitcount;
- }
-
- public boolean getTemporary() {
- return mTemporary;
- }
-}
diff --git a/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/JythonCodeTracer.java b/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/JythonCodeTracer.java
new file mode 100644
index 0000000..ea97116
--- /dev/null
+++ b/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/JythonCodeTracer.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Kloesch and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Kloesch - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.lang.python.jython.debugger;
+
+import org.eclipse.ease.Script;
+import org.eclipse.ease.lang.python.debugger.ICodeTracer;
+import org.python.core.Py;
+import org.python.core.PyObject;
+
+/**
+ * Wrapper class for calling {@link ICodeTracer} functionality on {@link PyObject}.
+ */
+public class JythonCodeTracer implements ICodeTracer {
+ /**
+ * {@link ICodeTracer} in Python form.
+ * <p>
+ * All calls simply wrap to this.
+ */
+ private final PyObject fPyTracer;
+
+ /**
+ * Constructor only stores parameters to member.
+ *
+ * @param tracer
+ * {@link ICodeTracer} in Python form.
+ */
+ public JythonCodeTracer(PyObject tracer) {
+ fPyTracer = tracer;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ease.lang.python.debugger.ICodeTracer#run(org.eclipse.ease.Script, java.lang.String)
+ */
+ @Override
+ public void run(Script script, String filename) {
+ fPyTracer.invoke("run", Py.java2py(script), Py.java2py(filename));
+ }
+
+}
diff --git a/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/JythonDebugger.java b/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/JythonDebugger.java
index dd39d15..d627477 100644
--- a/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/JythonDebugger.java
+++ b/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/JythonDebugger.java
@@ -10,170 +10,36 @@
*******************************************************************************/
package org.eclipse.ease.lang.python.jython.debugger;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-import java.util.Set;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.debug.core.DebugEvent;
-import org.eclipse.ease.ExitException;
-import org.eclipse.ease.IExecutionListener;
-import org.eclipse.ease.Script;
-import org.eclipse.ease.debugging.AbstractScriptDebugger;
-import org.eclipse.ease.debugging.IEventProcessor;
-import org.eclipse.ease.debugging.IScriptDebugFrame;
-import org.eclipse.ease.debugging.ScriptDebugFrame;
-import org.eclipse.ease.debugging.events.IDebugEvent;
-import org.eclipse.ease.debugging.events.TerminateRequest;
-import org.python.core.Py;
-import org.python.core.PyFrame;
+import org.eclipse.ease.IScriptEngine;
+import org.eclipse.ease.lang.python.debugger.IPyFrame;
+import org.eclipse.ease.lang.python.debugger.PythonDebugger;
import org.python.core.PyObject;
/**
- * Debugger class handling communication between JythonDebugTarget and edb.py.
+ * Extension of {@link PythonDebugger} for overloading methods to have {@link PyObject} parameter wrappers.
*/
-public class JythonDebugger extends AbstractScriptDebugger implements IEventProcessor, IExecutionListener {
-
- public class JythonDebugFrame extends ScriptDebugFrame implements IScriptDebugFrame {
-
- public JythonDebugFrame(final PyFrame frame) {
- super(fScriptRegistry.get(frame.f_code.co_filename), frame.f_lineno, TYPE_FILE);
- }
-
- @Override
- public String getName() {
- Script script = getScript();
- if (script.isDynamic()) {
- // dynamic script
- final String title = getScript().getTitle();
- return (title != null) ? "Dynamic: " + title : "(Dynamic)";
-
- } else {
- final Object command = getScript().getCommand();
- if (command != null) {
- if (command instanceof IFile)
- return ((IFile) command).getName();
-
- else if (command instanceof File)
- return ((File) command).getName();
-
- return command.toString();
- }
- }
-
- return "(unknown source)";
- }
-
- @Override
- public Map<String, Object> getVariables() {
- return getEngine().getVariables();
- }
- }
-
- /** Declarations for variables and function names in Jython. */
- private static final String PY_CMD_SET_DEBUGGER = "set_debugger";
- private static final String PY_CMD_RUN = "run";
-
- private PyObject fPythonStub;
-
- public JythonDebugger(final JythonDebuggerEngine engine, final boolean showDynamicCode) {
+public class JythonDebugger extends PythonDebugger {
+ /**
+ * @see PythonDebugger#PythonDebugger(IScriptEngine, boolean)
+ */
+ public JythonDebugger(IScriptEngine engine, boolean showDynamicCode) {
super(engine, showDynamicCode);
}
/**
- * Link Jython stub with this debugger instance.
+ * Overload of {@link #setCodeTracer(org.eclipse.ease.lang.python.debugger.ICodeTracer)} wrapping {@link PyObject} to {@link JythonCodeTracer}.
*
- * @param pythonStub
- * jython debugger stub instance
+ * @param tracer
+ * {@link PyObject} representation of code tracer.
*/
- public void setupJythonObjects(final PyObject pythonStub) {
- fPythonStub = pythonStub;
- fPythonStub.invoke(PY_CMD_SET_DEBUGGER, Py.java2py(this));
+ public void setCodeTracer(PyObject tracer) {
+ setCodeTracer(new JythonCodeTracer(tracer));
}
/**
- * Function called to handle incoming event.
- *
- * Depending on type corresponding handler will be called
+ * Overload of {@link #traceDispatch(org.eclipse.ease.lang.python.debugger.IPyFrame, String)} wrapping {@link PyObject} to {@link IPyFrame}.
*/
- @Override
- public void handleEvent(final IDebugEvent event) {
- if (event instanceof TerminateRequest) {
- resume(DebugEvent.STEP_END);
-
- } else
- super.handleEvent(event);
- }
-
- private static boolean isUserCode(final PyFrame frame) {
- return frame.f_code.co_filename.startsWith("__ref_");
- }
-
- private List<IScriptDebugFrame> getStacktrace(final PyFrame origin) {
- List<IScriptDebugFrame> trace = new ArrayList<IScriptDebugFrame>();
-
- PyFrame frame = origin;
- while (frame != null) {
- if (isUserCode(frame)) {
- if (isTrackedScript(fScriptRegistry.get(frame.f_code.co_filename)))
- trace.add(new JythonDebugFrame(frame));
- }
-
- frame = frame.f_back;
- }
-
- return trace;
- }
-
- public void traceDispatch(final PyFrame frame, final String type) {
- if (getResumeType() == DebugEvent.STEP_END)
- throw new ExitException("Debug aborted by user");
-
- if (isUserCode(frame)) {
- Script script = fScriptRegistry.get(frame.f_code.co_filename);
-
- if (isTrackedScript(script)) {
-
- // update stacktrace
- setStacktrace(getStacktrace(frame));
-
- // do not process script load event (line == 0)
- if (frame.f_lineno != 0)
- processLine(script, frame.f_lineno);
- }
- }
- }
-
- public Object execute(final Script script) {
- fPythonStub.invoke(PY_CMD_RUN, Py.javas2pys(script, registerScript(script)));
-
- // FIXME return execution result
- return null;
- }
-
- private final Map<String, Script> fScriptRegistry = new HashMap<String, Script>();
-
- private String registerScript(final Script script) {
- final String reference = getHash(script, fScriptRegistry.keySet());
- fScriptRegistry.put(reference, script);
- return reference;
- }
-
- private static String getHash(final Script script, final Set<String> existingKeys) {
- StringBuilder buffer = new StringBuilder("__ref_");
- buffer.append(script.isDynamic() ? "dyn" : script.getCommand().toString());
- buffer.append("_");
-
- for (int index = 0; index < 10; index++)
- buffer.append((char) ('a' + new Random().nextInt(26)));
-
- if (existingKeys.contains(buffer.toString()))
- return getHash(script, existingKeys);
-
- return buffer.toString();
+ public void traceDispatch(PyObject frame, String type) {
+ traceDispatch(new JythonFrame(frame), type);
}
}
\ No newline at end of file
diff --git a/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/JythonDebuggerEngine.java b/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/JythonDebuggerEngine.java
index a0a8be9..53ca03c 100644
--- a/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/JythonDebuggerEngine.java
+++ b/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/JythonDebuggerEngine.java
@@ -13,23 +13,26 @@
import java.io.InputStream;
import org.eclipse.debug.core.ILaunch;
-import org.eclipse.ease.IDebugEngine;
import org.eclipse.ease.Script;
import org.eclipse.ease.ScriptEngineException;
import org.eclipse.ease.debugging.EventDispatchJob;
+import org.eclipse.ease.lang.python.debugger.IPythonDebugEngine;
+import org.eclipse.ease.lang.python.debugger.PythonDebugger;
+import org.eclipse.ease.lang.python.debugger.ResourceHelper;
+import org.eclipse.ease.lang.python.debugger.model.PythonDebugTarget;
import org.eclipse.ease.lang.python.jython.JythonScriptEngine;
-import org.eclipse.ease.lang.python.jython.debugger.model.JythonDebugTarget;
-import org.python.core.PyObject;
+import org.python.core.Py;
/**
* A script engine to execute/debug Python code on a Jython interpreter.
*
* Uses most of JythonScriptEngine's functionality and only extends it when file is to be debugged.
*/
-public class JythonDebuggerEngine extends JythonScriptEngine implements IDebugEngine {
- private JythonDebugger fDebugger = null;
+public class JythonDebuggerEngine extends JythonScriptEngine implements IPythonDebugEngine {
+ private PythonDebugger fDebugger = null;
- public void setDebugger(final JythonDebugger debugger) {
+ @Override
+ public void setDebugger(final PythonDebugger debugger) {
fDebugger = debugger;
}
@@ -40,19 +43,13 @@
// in case we were called using "Run as"
if (fDebugger != null) {
// load python part of debugger
- final InputStream stream = ResourceHelper.getResourceStream("org.eclipse.ease.lang.python.jython.debugger", "python/edb.py");
+ final InputStream stream = ResourceHelper.getResourceStream("org.eclipse.ease.lang.python", "pysrc/edb.py");
try {
- // load debugger class as normal python code
- // this.internalExecute will already wrap code using the debugger
- super.internalExecute(new Script("Load Python debugger", stream), null, null);
+ internalSetVariable(PythonDebugger.PYTHON_DEBUGGER_VARIABLE, Py.java2py(fDebugger));
+ super.internalExecute(new Script("Load Python debugger", stream), null, "Load Python Debugger");
- final Object pyDebugger = internalGetVariable("eclipse_jython_debugger");
- if (pyDebugger instanceof PyObject) {
- fDebugger.setupJythonObjects((PyObject) pyDebugger);
- }
-
- } catch (final Exception e) {
+ } catch (final Throwable e) {
throw new ScriptEngineException("Failed to load Python Debugger", e);
}
}
@@ -60,18 +57,18 @@
@Override
protected Object internalExecute(final Script script, final Object reference, final String fileName) throws Exception {
- if (fDebugger != null)
+ if (fDebugger != null) {
return fDebugger.execute(script);
-
+ }
return super.internalExecute(script, reference, fileName);
}
@Override
public void setupDebugger(final ILaunch launch, final boolean suspendOnStartup, final boolean suspendOnScriptLoad, final boolean showDynamicCode) {
- final JythonDebugTarget target = new JythonDebugTarget(launch, suspendOnStartup, suspendOnScriptLoad, showDynamicCode);
+ final PythonDebugTarget target = new PythonDebugTarget(launch, suspendOnStartup, suspendOnScriptLoad, showDynamicCode);
launch.addDebugTarget(target);
- final JythonDebugger debugger = new JythonDebugger(this, showDynamicCode);
+ final PythonDebugger debugger = new JythonDebugger(this, showDynamicCode);
setDebugger(debugger);
diff --git a/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/JythonFrame.java b/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/JythonFrame.java
new file mode 100644
index 0000000..add4e3b
--- /dev/null
+++ b/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/JythonFrame.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Kloesch and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Kloesch - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.lang.python.jython.debugger;
+
+import org.eclipse.ease.lang.python.debugger.IPyFrame;
+import org.python.core.Py;
+import org.python.core.PyObject;
+
+/**
+ * Wrapper class for calling {@link IPyFrame} functionality on {@link PyObject}.
+ */
+public class JythonFrame implements IPyFrame {
+ /**
+ * {@link IPyFrame} in Python form.
+ * <p>
+ * All calls simply wrap to this.
+ */
+ private final PyObject fJythonFrame;
+
+ /**
+ * Constructor only stores parameters to member.
+ *
+ * @param frame
+ * {@link IPyFrame} in Python form.
+ */
+ public JythonFrame(PyObject frame) {
+ fJythonFrame = frame;
+ }
+
+ /**
+ * Utility method to check if a {@link PyObject} is a null object (either in Java or in Python).
+ *
+ * @param object
+ * {@link PyObject} to check if it is null.
+ * @return <code>true</code> if object has null value.
+ */
+ private static boolean isNull(PyObject object) {
+ return (object != null) && !Py.None.equals(object);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ease.lang.python.debugger.IPyFrame#getFilename()
+ */
+ @Override
+ public String getFilename() {
+ if (isNull(fJythonFrame)) {
+ final PyObject filename = fJythonFrame.invoke("getFilename");
+ return filename.asString();
+ }
+ return "<No Filename>";
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ease.lang.python.debugger.IPyFrame#getLineNumber()
+ */
+ @Override
+ public int getLineNumber() {
+ if (isNull(fJythonFrame)) {
+ final PyObject lineNumber = fJythonFrame.invoke("getLineNumber");
+ return Py.py2int(lineNumber);
+ }
+ return -1;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ease.lang.python.debugger.IPyFrame#getParent()
+ */
+ @Override
+ public IPyFrame getParent() {
+ if (isNull(fJythonFrame)) {
+ return new JythonFrame(fJythonFrame.invoke("getParent"));
+ }
+ return null;
+ }
+
+}
diff --git a/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/actions/FunctionFilterAction.java b/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/actions/FunctionFilterAction.java
deleted file mode 100644
index 2db27f1..0000000
--- a/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/actions/FunctionFilterAction.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2013 Christian Pontesegger and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Christian Pontesegger - initial API and implementation
- *******************************************************************************/
-package org.eclipse.ease.lang.python.jython.debugger.actions;
-
-import org.eclipse.ease.debugging.ScriptDebugVariable;
-import org.eclipse.jface.viewers.Viewer;
-
-public class FunctionFilterAction extends ViewFilterAction {
-
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.wst.jsdt.debug.internal.ui.actions.ViewFilterAction#getPreferenceKey()
- */
- @Override
- protected String getPreferenceKey() {
- return "org.eclipse.ease.ui.show_functions";
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.jface.viewers.ViewerFilter#select(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
- */
- @Override
- public boolean select(final Viewer viewer, final Object parentElement, final Object element) {
- if (element instanceof ScriptDebugVariable) {
- return getValue();
- }
-
- return true;
- }
-
-}
diff --git a/plugins/org.eclipse.ease.lang.python.py4j/plugin.xml b/plugins/org.eclipse.ease.lang.python.py4j/plugin.xml
index e83891b..c57fb53 100644
--- a/plugins/org.eclipse.ease.lang.python.py4j/plugin.xml
+++ b/plugins/org.eclipse.ease.lang.python.py4j/plugin.xml
@@ -16,6 +16,19 @@
class="org.eclipse.ease.lang.python.py4j.internal.Py4JBootstrap"
engineID="org.eclipse.ease.lang.python.py4j.engine">
</launchExtension>
+ <engine
+ class="org.eclipse.ease.lang.python.py4j.internal.Py4jDebuggerEngine"
+ id="org.eclipse.ease.lang.python.py4j.debugger.engine"
+ name="Python (Py4J Debugger)"
+ priority="1">
+ <binding
+ scriptType="Python">
+ </binding>
+ </engine>
+ <launchExtension
+ class="org.eclipse.ease.lang.python.py4j.internal.Py4JBootstrap"
+ engineID="org.eclipse.ease.lang.python.py4j.debugger.engine">
+ </launchExtension>
</extension>
<extension
diff --git a/plugins/org.eclipse.ease.lang.python.py4j/src/org/eclipse/ease/lang/python/py4j/internal/Py4jDebuggerEngine.java b/plugins/org.eclipse.ease.lang.python.py4j/src/org/eclipse/ease/lang/python/py4j/internal/Py4jDebuggerEngine.java
new file mode 100644
index 0000000..4187885
--- /dev/null
+++ b/plugins/org.eclipse.ease.lang.python.py4j/src/org/eclipse/ease/lang/python/py4j/internal/Py4jDebuggerEngine.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2014 Martin Kloesch and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Martin Kloesch - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ease.lang.python.py4j.internal;
+
+import java.io.InputStream;
+
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.ease.Script;
+import org.eclipse.ease.ScriptEngineException;
+import org.eclipse.ease.debugging.EventDispatchJob;
+import org.eclipse.ease.lang.python.debugger.IPythonDebugEngine;
+import org.eclipse.ease.lang.python.debugger.PythonDebugger;
+import org.eclipse.ease.lang.python.debugger.ResourceHelper;
+import org.eclipse.ease.lang.python.debugger.model.PythonDebugTarget;
+
+/***
+ * A script engine to debug Python code on a PY4J engine.
+ *
+ * Uses most of {@link Py4jDebuggerEngine}'s functionality and only extends it when file is to be debugged.
+ */
+
+public class Py4jDebuggerEngine extends Py4jScriptEngine implements IPythonDebugEngine {
+ private PythonDebugger fDebugger = null;
+
+ @Override
+ public void setDebugger(final PythonDebugger debugger) {
+ fDebugger = debugger;
+ }
+
+ @Override
+ protected void setupEngine() throws ScriptEngineException {
+ super.setupEngine();
+
+ // in case we were called using "Run as"
+ if (fDebugger != null) {
+ // load python part of debugger
+ final InputStream stream = ResourceHelper.getResourceStream("org.eclipse.ease.lang.python", "pysrc/edb.py");
+
+ try {
+ internalSetVariable(PythonDebugger.PYTHON_DEBUGGER_VARIABLE, fDebugger);
+ super.internalExecute(new Script("Load Python debugger", stream), null);
+
+ } catch (final Throwable e) {
+ throw new ScriptEngineException("Failed to load Python Debugger", e);
+ }
+ }
+ }
+
+ @Override
+ protected Object internalExecute(final Script script, final String fileName) throws Throwable {
+ if (fDebugger != null) {
+ return fDebugger.execute(script);
+ }
+ return super.internalExecute(script, fileName);
+ }
+
+ @Override
+ public void setupDebugger(final ILaunch launch, final boolean suspendOnStartup, final boolean suspendOnScriptLoad, final boolean showDynamicCode) {
+ final PythonDebugTarget target = new PythonDebugTarget(launch, suspendOnStartup, suspendOnScriptLoad, showDynamicCode);
+ launch.addDebugTarget(target);
+
+ final PythonDebugger debugger = new PythonDebugger(this, showDynamicCode);
+
+ setDebugger(debugger);
+
+ final EventDispatchJob dispatcher = new EventDispatchJob(target, debugger);
+ target.setDispatcher(dispatcher);
+ debugger.setDispatcher(dispatcher);
+ dispatcher.schedule();
+ }
+}
diff --git a/plugins/org.eclipse.ease.lang.python.py4j/src/org/eclipse/ease/lang/python/py4j/internal/Py4jScriptEngine.java b/plugins/org.eclipse.ease.lang.python.py4j/src/org/eclipse/ease/lang/python/py4j/internal/Py4jScriptEngine.java
index d69bd72..9d68791 100644
--- a/plugins/org.eclipse.ease.lang.python.py4j/src/org/eclipse/ease/lang/python/py4j/internal/Py4jScriptEngine.java
+++ b/plugins/org.eclipse.ease.lang.python.py4j/src/org/eclipse/ease/lang/python/py4j/internal/Py4jScriptEngine.java
@@ -212,7 +212,7 @@
}
}
- private Object internalExecute(Script script, String fileName) throws Throwable, Exception {
+ protected Object internalExecute(Script script, String fileName) throws Throwable, Exception {
IInteractiveReturn interactiveReturn;
if (script.isShellMode()) {
interactiveReturn = fPythonSideEngine.executeInteractive(script.getCode());
diff --git a/plugins/org.eclipse.ease.lang.python/.classpath b/plugins/org.eclipse.ease.lang.python/.classpath
index cf36b56..43b9862 100644
--- a/plugins/org.eclipse.ease.lang.python/.classpath
+++ b/plugins/org.eclipse.ease.lang.python/.classpath
@@ -2,6 +2,6 @@
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
- <classpathentry kind="src" path="src/"/>
+ <classpathentry kind="src" path="src"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
diff --git a/plugins/org.eclipse.ease.lang.python/.project b/plugins/org.eclipse.ease.lang.python/.project
index d87e740..809a760 100644
--- a/plugins/org.eclipse.ease.lang.python/.project
+++ b/plugins/org.eclipse.ease.lang.python/.project
@@ -6,6 +6,11 @@
</projects>
<buildSpec>
<buildCommand>
+ <name>org.python.pydev.PyDevBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
@@ -24,5 +29,6 @@
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.python.pydev.pythonNature</nature>
</natures>
</projectDescription>
diff --git a/plugins/org.eclipse.ease.lang.python/.pydevproject b/plugins/org.eclipse.ease.lang.python/.pydevproject
new file mode 100644
index 0000000..40e9f40
--- /dev/null
+++ b/plugins/org.eclipse.ease.lang.python/.pydevproject
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?eclipse-pydev version="1.0"?><pydev_project>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
+</pydev_project>
diff --git a/plugins/org.eclipse.ease.lang.python/META-INF/MANIFEST.MF b/plugins/org.eclipse.ease.lang.python/META-INF/MANIFEST.MF
index d8ab2a0..2faee21 100644
--- a/plugins/org.eclipse.ease.lang.python/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.ease.lang.python/META-INF/MANIFEST.MF
@@ -8,11 +8,18 @@
Require-Bundle: org.eclipse.ease,
org.eclipse.ease.ui,
org.eclipse.ui;bundle-version="[3.7.0,4.0.0)",
- org.eclipse.text;bundle-version="[3.5.300,4.0.0)"
+ org.eclipse.text;bundle-version="[3.5.300,4.0.0)",
+ org.eclipse.debug.core;bundle-version="[3.7.1,4.0.0)",
+ org.eclipse.debug.ui;bundle-version="[3.7.102,4.0.0)",
+ org.eclipse.ui.editors;bundle-version="[3.7.0,4.0.0)",
+ org.eclipse.ui.ide;bundle-version="[3.7.0,4.0.0)"
Bundle-Activator: org.eclipse.ease.lang.python.Activator
Bundle-ActivationPolicy: lazy
Eclipse-BuddyPolicy: global
Export-Package: org.eclipse.ease.lang.python,
org.eclipse.ease.lang.python.debug,
+ org.eclipse.ease.lang.python.debugger,
+ org.eclipse.ease.lang.python.debugger.actions,
+ org.eclipse.ease.lang.python.debugger.model,
org.eclipse.ease.lang.python.preferences
Bundle-ClassPath: .
diff --git a/plugins/org.eclipse.ease.lang.python/build.properties b/plugins/org.eclipse.ease.lang.python/build.properties
index 0794394..1bf0b01 100644
--- a/plugins/org.eclipse.ease.lang.python/build.properties
+++ b/plugins/org.eclipse.ease.lang.python/build.properties
@@ -3,5 +3,5 @@
bin.includes = META-INF/,\
.,\
plugin.xml,\
- .options,\
- about.html
+ about.html,\
+ pysrc/
diff --git a/plugins/org.eclipse.ease.lang.python/plugin.xml b/plugins/org.eclipse.ease.lang.python/plugin.xml
index 46490e8..4d72cad 100644
--- a/plugins/org.eclipse.ease.lang.python/plugin.xml
+++ b/plugins/org.eclipse.ease.lang.python/plugin.xml
@@ -28,5 +28,34 @@
</binding>
</scriptType>
</extension>
+ <extension
+ point="org.eclipse.debug.ui.debugModelPresentations">
+ <debugModelPresentation
+ class="org.eclipse.ease.lang.python.debugger.model.PythonDebugModelPresentation"
+ id="org.eclipse.ease.debugModelPresentation.python">
+ </debugModelPresentation>
+ </extension>
+ <extension
+ point="org.eclipse.ui.viewActions">
+ <viewContribution
+ id="variableViewActions"
+ targetID="org.eclipse.debug.ui.VariableView">
+ <menu
+ id="org.eclipse.ease.debug.ui.variableview.menu"
+ label="EASE">
+ <groupMarker
+ name="ease">
+ </groupMarker>
+ </menu>
+ <action
+ class="org.eclipse.ease.lang.python.debugger.actions.FrameworkFilterAction"
+ id="org.eclipse.ease.ui.variableview.show.framework"
+ label="Hide Python Framework Variables"
+ menubarPath="org.eclipse.ease.debug.ui.variableview.menu/ease"
+ state="true"
+ style="toggle">
+ </action>
+ </viewContribution>
+ </extension>
</plugin>
diff --git a/plugins/org.eclipse.ease.lang.python.jython.debugger/python/.gitignore b/plugins/org.eclipse.ease.lang.python/pysrc/.gitignore
similarity index 100%
rename from plugins/org.eclipse.ease.lang.python.jython.debugger/python/.gitignore
rename to plugins/org.eclipse.ease.lang.python/pysrc/.gitignore
diff --git a/plugins/org.eclipse.ease.lang.python/pysrc/edb.py b/plugins/org.eclipse.ease.lang.python/pysrc/edb.py
new file mode 100644
index 0000000..8ec4b8e
--- /dev/null
+++ b/plugins/org.eclipse.ease.lang.python/pysrc/edb.py
@@ -0,0 +1,165 @@
+'''
+Copyright (c) 2014 Martin Kloesch
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/epl-v10.html
+
+Contributors:
+ * Martin Kloesch - initial API and implementation
+ * Christian Pontesegger - stripped most parts to simply trace and relay to java
+'''
+# Python std library imports
+import sys
+import __main__
+import re
+
+# : Regular expression if we are dealing with internal module.
+_pyease_INTERNAL_CHECKER = re.compile(r"^<.+>$")
+
+def _pyease_ignore_frame(frame, first=True):
+ '''
+ Utility method to check if a frame should be ignored.
+
+ Current reasons to ignore a frame:
+ * It is the top entry of the stack and it is a standard module.
+ e.g. <string>
+ * It is part of the py4j library or has py4j in its call chain.
+
+ Recursively checks trace until at bottom of stack.
+
+ :param frame: Frame to check if it should be ignored.
+ :param first: Flag to signalize if it is the first call.
+ :returns: `True` if the frame should be ignored.
+ '''
+ # End of frame
+ if not frame:
+ return False
+
+ # Check if we are in the standard modules
+ if _pyease_INTERNAL_CHECKER.match(frame.f_code.co_filename):
+ # Only ignore standard module if its the top of the stack
+ if first:
+ return True
+ else:
+ return False
+
+ # TODO: Think of better way to identify py4j library
+ if 'py4j' in frame.f_code.co_filename.lower():
+ return True
+
+ # Check parent in stack
+ return _pyease_ignore_frame(frame.f_back, False)
+
+
+class _pyease_PyFrame:
+ '''
+ Python implementation of IPyFrame used for exchanging frame data
+ with eclipse.
+
+ Simply wraps standard python frame to more easily usable format.
+ '''
+ def __init__(self, frame):
+ '''
+ Constructor only stores frame to member.
+
+ :param frame: Python frame to be converted.
+ '''
+ self._frame = frame
+
+ def getFilename(self):
+ '''
+ Returns the filename of the frame.
+
+ If no frame was set, a dummy value will be returned.
+
+ :returns: Filename of frame or dummy value.
+ '''
+ if self._frame:
+ return self._frame.f_code.co_filename
+ else:
+ return "__no_frame__"
+
+ def getLineNumber(self):
+ '''
+ Returns the linenumber of the frame.
+
+ If no frame was set, -1 is returned.
+
+ :returns: Line number of frame or -1.
+ '''
+ if self._frame:
+ return self._frame.f_lineno
+ else:
+ return -1
+
+ def getParent(self):
+ '''
+ Returns the parent of the frame.
+
+ If no frame was set or the frame does not have a parent
+ `None` is returned.
+
+ :returns: Parent frame in stack or `None`
+ '''
+ if self._frame:
+ return _pyease_PyFrame(self._frame.f_back)
+ else:
+ return None
+
+ class Java:
+ implements = ['org.eclipse.ease.lang.python.debugger.IPyFrame']
+
+
+class _pyease_CodeTracer:
+ '''
+ Eclipse Debugger class.
+ '''
+ _debugger = None
+ _framework_variables = {}
+
+ def set_debugger(self, debugger):
+ '''
+ Setter method for self._debugger.
+
+ :param org.eclipse.ease.lang.python.debugger.PythonDebugger debugger:
+ PythonDebugger object to handling communication with Eclipse.
+ '''
+ self._debugger = debugger
+ sys.settrace(self.trace_dispatch)
+
+ def trace_dispatch(self, frame, event, arg):
+ '''
+ Method called each time a new frame is reached in execution.
+ <p>
+ Performs prefiltering and dispatches the data to Eclipse.
+
+ :param frame: New execution frame.
+ :param event: ignored.
+ :param arg: ignored.
+ :see: sys.settrace
+ '''
+ if not _pyease_ignore_frame(frame):
+ if self._debugger:
+ self._debugger.traceDispatch(_pyease_PyFrame(frame), event)
+ return self.trace_dispatch
+
+ def run(self, script, filename):
+ '''
+ Executes the file given using the bdb.Bdb.run method.
+ '''
+ code = "{}\n".format(script.getCode())
+ compiledCode = compile(code, filename, "exec")
+
+ g = globals()
+
+ exec(compiledCode, g)
+
+ class Java:
+ implements = ['org.eclipse.ease.lang.python.debugger.ICodeTracer']
+
+
+# Set up connection between eclipse and python
+_pyease_eclipse_python_debugger = _pyease_CodeTracer()
+_pyease_eclipse_python_debugger.set_debugger(_pyease_debugger)
+_pyease_debugger.setCodeTracer(_pyease_eclipse_python_debugger)
\ No newline at end of file
diff --git a/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/ICodeTracer.java b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/ICodeTracer.java
new file mode 100644
index 0000000..9209a5b
--- /dev/null
+++ b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/ICodeTracer.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Kloesch and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Kloesch - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.lang.python.debugger;
+
+import org.eclipse.ease.Script;
+
+/**
+ * Interface for execution tracing in Python.
+ *
+ * This object is the link between Eclipse and the Python implementation.
+ *
+ */
+public interface ICodeTracer {
+ /**
+ * Runs the given script via the code tracer in Python.
+ *
+ * @param script
+ * Script to be run via code tracer.
+ * @param filename
+ * Filename for script.
+ */
+ void run(Script script, String filename);
+}
diff --git a/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/IPyFrame.java b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/IPyFrame.java
new file mode 100644
index 0000000..f68ea42
--- /dev/null
+++ b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/IPyFrame.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Kloesch and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Kloesch - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.lang.python.debugger;
+
+/**
+ * Abstraction interface for frame information in Python.
+ */
+public interface IPyFrame {
+ /**
+ * Returns the filename of the current frame.
+ * <p>
+ * Must <b>NOT</b> return <code>null</code>.
+ *
+ * @return filename for the current frame.
+ */
+ public String getFilename();
+
+ /**
+ * Returns the linenumber of the current frame.
+ *
+ * @return line number of the current frame.
+ */
+ public int getLineNumber();
+
+ /**
+ * Returns the parent frame in the call stack.
+ * <p>
+ * If the current frame is the root, <code>null</code> should be returned.
+ *
+ * @return Parent in the call stack or <code>null</code>
+ */
+ public IPyFrame getParent();
+}
diff --git a/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/IPythonDebugEngine.java b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/IPythonDebugEngine.java
new file mode 100644
index 0000000..cb6c812
--- /dev/null
+++ b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/IPythonDebugEngine.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Kloesch and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Kloesch - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.lang.python.debugger;
+
+import org.eclipse.ease.IDebugEngine;
+
+/**
+ * Extension of {@link IDebugEngine} for Python script engines.
+ */
+public interface IPythonDebugEngine extends IDebugEngine {
+ /**
+ * Sets the PythonDebugger for the debug engine.
+ *
+ * @param debugger
+ * {@link PythonDebugger} to be used.
+ */
+ public void setDebugger(PythonDebugger debugger);
+}
diff --git a/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/PythonDebugger.java b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/PythonDebugger.java
new file mode 100644
index 0000000..35d36d7
--- /dev/null
+++ b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/PythonDebugger.java
@@ -0,0 +1,255 @@
+/*******************************************************************************
+ * Copyright (c) 2014 Kloesch and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Kloesch - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ease.lang.python.debugger;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.debug.core.DebugEvent;
+import org.eclipse.ease.ExitException;
+import org.eclipse.ease.IExecutionListener;
+import org.eclipse.ease.IScriptEngine;
+import org.eclipse.ease.Script;
+import org.eclipse.ease.debugging.AbstractScriptDebugger;
+import org.eclipse.ease.debugging.IEventProcessor;
+import org.eclipse.ease.debugging.IScriptDebugFrame;
+import org.eclipse.ease.debugging.ScriptDebugFrame;
+import org.eclipse.ease.debugging.events.IDebugEvent;
+import org.eclipse.ease.debugging.events.TerminateRequest;
+
+/**
+ * Debugger class handling communication between Python and Eclipse.
+ */
+public class PythonDebugger extends AbstractScriptDebugger implements IEventProcessor, IExecutionListener {
+ /**
+ * Variable name for {@link PythonDebugger} in Python engine.
+ * <p>
+ * During setup phase set this variable <b>BEFORE</b> calling edb.py
+ */
+ public static final String PYTHON_DEBUGGER_VARIABLE = "_pyease_debugger";
+
+ /**
+ * Custom {@link ScriptDebugFrame} parsing the data from {@link IPyFrame} to more usable format.
+ */
+ public class PythonDebugFrame extends ScriptDebugFrame implements IScriptDebugFrame {
+ /**
+ * Constructor parses information from {@link IPyFrame} to correct parameters for {@link ScriptDebugFrame#ScriptDebugFrame(Script, int, int)}.
+ *
+ * @param frame
+ * {@link IPyFrame} with information about the current execution frame.
+ */
+ public PythonDebugFrame(final IPyFrame frame) {
+ super(fScriptRegistry.get(frame.getFilename()), frame.getLineNumber(), TYPE_FILE);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ease.debugging.ScriptDebugFrame#getName()
+ */
+ @Override
+ public String getName() {
+ final Script script = getScript();
+ if (script.isDynamic()) {
+ // dynamic script
+ final String title = getScript().getTitle();
+ return (title != null) ? "Dynamic: " + title : "(Dynamic)";
+
+ } else {
+ final Object command = getScript().getCommand();
+ if (command != null) {
+ if (command instanceof IFile)
+ return ((IFile) command).getName();
+
+ else if (command instanceof File)
+ return ((File) command).getName();
+
+ return command.toString();
+ }
+ }
+
+ return "(unknown source)";
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ease.debugging.ScriptDebugFrame#getVariables()
+ */
+ @Override
+ public Map<String, Object> getVariables() {
+ // Check to avoid NPE if shut down
+ if (getEngine() != null) {
+ return getEngine().getVariables();
+ }
+ return null;
+ }
+ }
+
+ /**
+ * {@link ICodeTracer} for communicating with Python implementation.
+ */
+ private ICodeTracer fCodeTracer;
+
+ /**
+ * @see AbstractScriptDebugger#AbstractScriptDebugger(IScriptEngine, boolean)
+ */
+ public PythonDebugger(final IScriptEngine engine, final boolean showDynamicCode) {
+ super(engine, showDynamicCode);
+ }
+
+ /**
+ * Sets the {@link ICodeTracer} from the Python implementation.
+ * <p>
+ * This method will be called by edb.py on {@value #PYTHON_DEBUGGER_VARIABLE}.
+ *
+ * @param tracer
+ * {@link ICodeTracer} for the connection between Eclipse and Python.
+ */
+ public void setCodeTracer(final ICodeTracer tracer) {
+ fCodeTracer = tracer;
+ }
+
+ /**
+ * Function called to handle incoming event.
+ *
+ * Depending on type corresponding handler will be called
+ */
+ @Override
+ public void handleEvent(final IDebugEvent event) {
+ if (event instanceof TerminateRequest) {
+ resume(DebugEvent.STEP_END);
+
+ } else
+ super.handleEvent(event);
+ }
+
+ /**
+ * Utility to check if a frame is part of user code or external library.
+ *
+ * @param frame
+ * {@link IPyFrame} to check if we are currently in user code.
+ * @return <code>true</code> if we are in user code.
+ */
+ private static boolean isUserCode(final IPyFrame frame) {
+ return frame.getFilename().startsWith("__ref_");
+ }
+
+ /**
+ * Parses given frame for its call stack.
+ *
+ * @param origin
+ * Top frame of stack.
+ * @return Stack based on given {@link IPyFrame}
+ */
+ private List<IScriptDebugFrame> getStacktrace(final IPyFrame origin) {
+ final List<IScriptDebugFrame> trace = new ArrayList<>();
+
+ IPyFrame frame = origin;
+ while (frame != null) {
+ if (isUserCode(frame)) {
+ if (isTrackedScript(fScriptRegistry.get(frame.getFilename())))
+ trace.add(new PythonDebugFrame(frame));
+ }
+
+ frame = frame.getParent();
+ }
+
+ return trace;
+ }
+
+ /**
+ * Function called from {@link ICodeTracer} whenever a new frame in Python is hit.
+ * <p>
+ * Effectively checks if debugger should supsend or continue.
+ *
+ * @param frame
+ * {@link IPyFrame} for current execution point.
+ * @param type
+ * Type of trace step that occured (ignored).
+ */
+ public void traceDispatch(final IPyFrame frame, final String type) {
+ if (getResumeType() == DebugEvent.STEP_END)
+ throw new ExitException("Debug aborted by user");
+
+ if (isUserCode(frame)) {
+ final Script script = fScriptRegistry.get(frame.getFilename());
+
+ if (isTrackedScript(script)) {
+
+ // update stacktrace
+ setStacktrace(getStacktrace(frame));
+
+ // do not process script load event (line == 0)
+ if (frame.getLineNumber() != 0)
+ processLine(script, frame.getLineNumber());
+ }
+ }
+ }
+
+ /**
+ * Runs the given {@link Script} using the {@link ICodeTracer}.
+ * <p>
+ * Return values are ignored in debug mode.
+ *
+ * @param script
+ * Script to be executed.
+ * @return Always <code>null</code>
+ */
+ public Object execute(final Script script) {
+ fCodeTracer.run(script, registerScript(script));
+ return null;
+ }
+
+ /**
+ * Map from custom filename to actual {@link Script} for easily identifying different scripts.
+ * <p>
+ * For each new file a unique filename is created using {@link #getHash(Script, Set)}.
+ */
+ private final Map<String, Script> fScriptRegistry = new HashMap<>();
+
+ private String registerScript(final Script script) {
+ final String reference = getHash(script, fScriptRegistry.keySet());
+ fScriptRegistry.put(reference, script);
+ return reference;
+ }
+
+ /**
+ * Creates a unique filename for the given {@link Script}.
+ *
+ * @param script
+ * {@link Script} to get unique filename for.
+ * @param existingKeys
+ * Existing keys to avoid duplicates.
+ * @return Unique filename for given {@link Script}.
+ */
+ private static String getHash(final Script script, final Set<String> existingKeys) {
+ final StringBuilder buffer = new StringBuilder("__ref_");
+ buffer.append(script.isDynamic() ? "dyn" : script.getCommand().toString());
+ buffer.append("_");
+
+ for (int index = 0; index < 10; index++)
+ buffer.append((char) ('a' + new Random().nextInt(26)));
+
+ if (existingKeys.contains(buffer.toString()))
+ return getHash(script, existingKeys);
+
+ return buffer.toString();
+ }
+
+}
diff --git a/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/ResourceHelper.java b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/ResourceHelper.java
similarity index 83%
rename from plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/ResourceHelper.java
rename to plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/ResourceHelper.java
index debabae..b0d249d 100644
--- a/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/ResourceHelper.java
+++ b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/ResourceHelper.java
@@ -1,63 +1,69 @@
-/*******************************************************************************
- * Copyright (c) 2014 Christian Pontesegger and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Christian Pontesegger - initial API and implementation
- *******************************************************************************/
-package org.eclipse.ease.lang.python.jython.debugger;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.jar.JarFile;
-
-import org.eclipse.core.runtime.FileLocator;
-import org.eclipse.core.runtime.Platform;
-
-public class ResourceHelper {
-
- /**
- * Returns an {@link InputStream} for a given resource within a bundle.
- *
- * @param bundle
- * qualified name of the bundle to resolve
- * @param path
- * full path of the file to load
- * @return input stream to resource
- */
- public static InputStream getResourceStream(final String bundle, final String path) {
- String location = Platform.getBundle(bundle).getLocation();
- try {
- if (location.toLowerCase().endsWith(".jar")) {
- // we need to open a jar file
- final int pos = location.indexOf("file:");
- if (pos != -1) {
- location = location.substring(pos + 5);
- if (!location.startsWith("/")) {
- // relative location, add full path to executable
- location = (Platform.getInstallLocation().getURL().toString() + location).substring(6);
- }
-
- final JarFile file = new JarFile(location);
- if (path.startsWith("/"))
- return file.getInputStream(file.getEntry(path.substring(1)));
- else
- return file.getInputStream(file.getEntry(path));
- }
-
- } else {
- final URL url = Platform.getBundle(bundle).getResource(path);
- return FileLocator.resolve(url).openStream();
- }
- } catch (final IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
- return null;
- }
-}
+/*******************************************************************************
+ * Copyright (c) 2014 Christian Pontesegger and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian Pontesegger - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ease.lang.python.debugger;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.jar.JarFile;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Platform;
+
+public class ResourceHelper {
+
+ /**
+ * Returns an {@link InputStream} for a given resource within a bundle.
+ *
+ * @param bundle
+ * qualified name of the bundle to resolve
+ * @param path
+ * full path of the file to load
+ * @return input stream to resource
+ */
+ public static InputStream getResourceStream(final String bundle, final String path) {
+ String location = Platform.getBundle(bundle).getLocation();
+ try {
+ if (location.toLowerCase().endsWith(".jar")) {
+ // we need to open a jar file
+ final int pos = location.indexOf("file:");
+ if (pos != -1) {
+ location = location.substring(pos + 5);
+ if (!location.startsWith("/")) {
+ // relative location, add full path to executable
+ location = (Platform.getInstallLocation().getURL().toString() + location).substring(6);
+ }
+ JarFile file = null;
+ try {
+ file = new JarFile(location);
+ if (path.startsWith("/"))
+ return file.getInputStream(file.getEntry(path.substring(1)));
+ else
+ return file.getInputStream(file.getEntry(path));
+ } finally {
+ if (file != null) {
+ file.close();
+ }
+ }
+ }
+
+ } else {
+ final URL url = Platform.getBundle(bundle).getResource(path);
+ return FileLocator.resolve(url).openStream();
+ }
+ } catch (final IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+}
diff --git a/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/actions/ModuleFilterAction.java b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/actions/FrameworkFilterAction.java
similarity index 68%
rename from plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/actions/ModuleFilterAction.java
rename to plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/actions/FrameworkFilterAction.java
index b8f644f..cebfc53 100644
--- a/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/actions/ModuleFilterAction.java
+++ b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/actions/FrameworkFilterAction.java
@@ -1,20 +1,22 @@
/*******************************************************************************
- * Copyright (c) 2013 Christian Pontesegger and others.
+ * Copyright (c) 2017 Martin Kloesch and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * Christian Pontesegger - initial API and implementation
+ * Martin Kloesch - initial API and implementation
*******************************************************************************/
-package org.eclipse.ease.lang.python.jython.debugger.actions;
+package org.eclipse.ease.lang.python.debugger.actions;
import org.eclipse.ease.debugging.ScriptDebugVariable;
-import org.eclipse.ease.modules.AbstractScriptModule;
import org.eclipse.jface.viewers.Viewer;
-public class ModuleFilterAction extends ViewFilterAction {
+/**
+ * {@link ViewFilterAction} for hiding debug framewok specific variables.
+ */
+public class FrameworkFilterAction extends ViewFilterAction {
/*
* (non-Javadoc)
@@ -23,7 +25,7 @@
*/
@Override
protected String getPreferenceKey() {
- return "org.eclipse.ease.ui.show_modules";
+ return "org.eclipse.ease.ui.show_frameworkvariables";
}
/*
@@ -34,9 +36,8 @@
@Override
public boolean select(final Viewer viewer, final Object parentElement, final Object element) {
if (element instanceof ScriptDebugVariable) {
- Object value = ((ScriptDebugVariable) element).getValue().getValue();
- if (value instanceof AbstractScriptModule)
- return getValue();
+ final ScriptDebugVariable variable = (ScriptDebugVariable) element;
+ return !variable.getName().startsWith("_pyease_");
}
return true;
diff --git a/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/actions/ViewFilterAction.java b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/actions/ViewFilterAction.java
similarity index 98%
rename from plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/actions/ViewFilterAction.java
rename to plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/actions/ViewFilterAction.java
index 3019926..896c90e 100644
--- a/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/actions/ViewFilterAction.java
+++ b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/actions/ViewFilterAction.java
@@ -8,7 +8,7 @@
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
-package org.eclipse.ease.lang.python.jython.debugger.actions;
+package org.eclipse.ease.lang.python.debugger.actions;
import org.eclipse.debug.ui.IDebugView;
import org.eclipse.ease.Activator;
diff --git a/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/model/JythonDebugModelPresentation.java b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/model/PythonDebugModelPresentation.java
similarity index 90%
rename from plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/model/JythonDebugModelPresentation.java
rename to plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/model/PythonDebugModelPresentation.java
index cc92770..2adf29b 100644
--- a/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/model/JythonDebugModelPresentation.java
+++ b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/model/PythonDebugModelPresentation.java
@@ -8,7 +8,7 @@
* Contributors:
* Christian Pontesegger - initial API and implementation
*******************************************************************************/
-package org.eclipse.ease.lang.python.jython.debugger.model;
+package org.eclipse.ease.lang.python.debugger.model;
import org.eclipse.core.resources.IFile;
import org.eclipse.debug.core.model.IValue;
@@ -26,8 +26,8 @@
import org.eclipse.ui.editors.text.EditorsUI;
import org.eclipse.ui.part.FileEditorInput;
-public class JythonDebugModelPresentation implements IDebugModelPresentation {
- public static String ID = "org.python.pydev.debug";// "org.eclipse.ease.lang.python.jython.debugger.model.JythonDebugModelPresentation";
+public class PythonDebugModelPresentation implements IDebugModelPresentation {
+ public static String ID = "org.python.pydev.debug";
@Override
public void setAttribute(final String attribute, final Object value) {
@@ -46,7 +46,7 @@
@Override
public void computeDetail(final IValue value, final IValueDetailListener listener) {
- Object adapter = value.getAdapter(String.class);
+ final Object adapter = value.getAdapter(String.class);
if (adapter instanceof String)
listener.detailComputed(value, (String) adapter);
}
@@ -60,7 +60,7 @@
@Override
public void dispose() {
// TODO Auto-generated method stub
- System.out.println("Dispose of JythonDebugModelPresentation.");
+ System.out.println("Dispose of PythonDebugModelPresentation.");
}
@Override
diff --git a/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/model/JythonDebugTarget.java b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/model/PythonDebugTarget.java
similarity index 79%
rename from plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/model/JythonDebugTarget.java
rename to plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/model/PythonDebugTarget.java
index 45e1885..5b04631 100644
--- a/plugins/org.eclipse.ease.lang.python.jython.debugger/src/org/eclipse/ease/lang/python/jython/debugger/model/JythonDebugTarget.java
+++ b/plugins/org.eclipse.ease.lang.python/src/org/eclipse/ease/lang/python/debugger/model/PythonDebugTarget.java
@@ -9,7 +9,7 @@
* Christian Pontesegger - initial API
* Martin Kloesch - implementation
*******************************************************************************/
-package org.eclipse.ease.lang.python.jython.debugger.model;
+package org.eclipse.ease.lang.python.debugger.model;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
@@ -19,12 +19,10 @@
import org.eclipse.ease.debugging.ScriptDebugTarget;
/**
- * ScriptDebugTarget for communication between Eclipse framework and Jython debugger.
- *
- * @author kloeschmartin
+ * ScriptDebugTarget for communication between Eclipse framework and Python debugger.
*/
-public class JythonDebugTarget extends ScriptDebugTarget {
- private static final String pyBreakpointType = JythonDebugModelPresentation.ID;
+public class PythonDebugTarget extends ScriptDebugTarget {
+ private static final String pyBreakpointType = PythonDebugModelPresentation.ID;
/**
* Constructor for now only calls super constructor.
@@ -34,13 +32,13 @@
* @param suspendOnScriptLoad
* @param showDynamicCode
*/
- public JythonDebugTarget(final ILaunch launch, final boolean suspendOnStartup, final boolean suspendOnScriptLoad, boolean showDynamicCode) {
+ public PythonDebugTarget(final ILaunch launch, final boolean suspendOnStartup, final boolean suspendOnScriptLoad, boolean showDynamicCode) {
super(launch, suspendOnStartup, suspendOnScriptLoad, showDynamicCode);
}
@Override
public String getName() throws DebugException {
- return "EASE Jython Debugger";
+ return "EASE Python Debugger";
}
// ************************************************************
@@ -50,7 +48,7 @@
/**
* Getter methods for all matching breakpoints in given script.
*
- * Currently EASE Jython Debugger uses PyDev breakpoints, this could change though.
+ * Currently EASE Python Debugger uses PyDev breakpoints, this could change though.
*/
@Override
protected IBreakpoint[] getBreakpoints(final Script script) {
@@ -61,4 +59,9 @@
public boolean supportsBreakpoint(final IBreakpoint breakpoint) {
return true;
}
+
+ @Override
+ public String getModelIdentifier() {
+ return "org.eclipse.ease.debugModelPresentation.python";
+ }
}