GP-5171: Generating pypredef files for PyDev. Fixing PyDev

errors/warnings in PyGhidra.
This commit is contained in:
Ryan Kurtz 2024-11-27 09:38:51 -05:00
parent e66bbc5231
commit 56d6af4531
16 changed files with 108 additions and 92 deletions

View file

@ -1 +1,2 @@
/.pytest_cache/
!.pydevproject

View file

@ -0,0 +1,12 @@
<?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 interpreter</pydev_property>
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
<path>/${PROJECT_DIR_NAME}/ghidra_scripts</path>
<path>/${PROJECT_DIR_NAME}/src/main/py/src/pyghidra</path>
</pydev_pathproperty>
</pydev_project>

View file

@ -54,10 +54,10 @@ debug_callback = _debug_callback
# Expose API
from .core import run_script, start, started, open_program
from .launcher import DeferredPyGhidraLauncher, GuiPyGhidraLauncher, HeadlessPyGhidraLauncher
from .script import get_current_interpreter
from .version import ApplicationInfo, ExtensionDetails
from pyghidra.core import run_script, start, started, open_program
from pyghidra.launcher import DeferredPyGhidraLauncher, GuiPyGhidraLauncher, HeadlessPyGhidraLauncher
from pyghidra.script import get_current_interpreter
from pyghidra.version import ApplicationInfo, ExtensionDetails
__all__ = [

View file

@ -20,7 +20,6 @@ import logging
import sys
from pathlib import Path
import pyghidra
import pyghidra.core
import pyghidra.gui

View file

@ -14,7 +14,6 @@
# limitations under the License.
##
import contextlib
from pathlib import Path
from typing import Union, TYPE_CHECKING, Tuple, ContextManager, List, Optional
from pyghidra.converters import * # pylint: disable=wildcard-import, unused-wildcard-import
@ -51,29 +50,29 @@ def started() -> bool:
return PyGhidraLauncher.has_launched()
def _get_language(id: str) -> "Language":
def _get_language(lang_id: str) -> "Language":
from ghidra.program.util import DefaultLanguageService
from ghidra.program.model.lang import LanguageID, LanguageNotFoundException
try:
service: "LanguageService" = DefaultLanguageService.getLanguageService()
return service.getLanguage(LanguageID(id))
return service.getLanguage(LanguageID(lang_id))
except LanguageNotFoundException:
# suppress the java exception
pass
raise ValueError("Invalid Language ID: "+id)
raise ValueError("Invalid Language ID: " + lang_id)
def _get_compiler_spec(lang: "Language", id: str = None) -> "CompilerSpec":
if id is None:
def _get_compiler_spec(lang: "Language", compiler: str = None) -> "CompilerSpec":
if compiler is None:
return lang.getDefaultCompilerSpec()
from ghidra.program.model.lang import CompilerSpecID, CompilerSpecNotFoundException
try:
return lang.getCompilerSpecByID(CompilerSpecID(id))
return lang.getCompilerSpecByID(CompilerSpecID(compiler))
except CompilerSpecNotFoundException:
# suppress the java exception
pass
lang_id = lang.getLanguageID()
raise ValueError(f"Invalid CompilerSpecID: {id} for Language: {lang_id.toString()}")
raise ValueError(f"Invalid CompilerSpecID: {compiler} for Language: {lang_id.toString()}")
def _setup_project(
@ -85,8 +84,8 @@ def _setup_project(
loader: Union[str, JClass] = None
) -> Tuple["GhidraProject", "Program"]:
from ghidra.base.project import GhidraProject
from java.lang import ClassLoader
from java.io import IOException
from java.lang import ClassLoader # type:ignore @UnresolvedImport
from java.io import IOException # type:ignore @UnresolvedImport
if binary_path is not None:
binary_path = Path(binary_path)
if project_location:
@ -99,7 +98,7 @@ def _setup_project(
project_location.mkdir(exist_ok=True, parents=True)
if isinstance(loader, str):
from java.lang import ClassNotFoundException
from java.lang import ClassNotFoundException # type:ignore @UnresolvedImport
try:
gcl = ClassLoader.getSystemClassLoader()
loader = JClass(loader, gcl)
@ -108,7 +107,8 @@ def _setup_project(
if isinstance(loader, JClass):
from ghidra.app.util.opinion import Loader
if not Loader.class_.isAssignableFrom(loader):
loader_cls = Loader.class_
if not loader_cls.isAssignableFrom(loader):
raise TypeError(f"{loader} does not implement ghidra.app.util.opinion.Loader")
# Open/Create project
@ -157,8 +157,8 @@ def _setup_script(project: "GhidraProject", program: "Program"):
from ghidra.program.util import ProgramLocation
from ghidra.util.task import TaskMonitor
from java.io import PrintWriter
from java.lang import System
from java.io import PrintWriter # type:ignore @UnresolvedImport
from java.lang import System # type:ignore @UnresolvedImport
if project is not None:
project = project.getProject()
@ -185,7 +185,7 @@ def _analyze_program(flat_api, program):
if hasattr(GhidraProgramUtilities, "markProgramAnalyzed"):
GhidraProgramUtilities.markProgramAnalyzed(program)
else:
GhidraProgramUtilities.setAnalyzedFlag(program, True)
GhidraProgramUtilities.setAnalyzedFlag(program, True) # @UndefinedVariable
finally:
GhidraScriptUtil.releaseBundleHostReference()

View file

@ -19,7 +19,7 @@ from pathlib import Path
import sys
import threading
from .launcher import PyGhidraLauncher, _run_mac_app
from pyghidra.launcher import PyGhidraLauncher, _run_mac_app
class GhidraLauncher(PyGhidraLauncher):
@ -31,12 +31,12 @@ class GhidraLauncher(PyGhidraLauncher):
def _launch(self):
from ghidra import Ghidra
from java.lang import Runtime, Thread
from java.lang import Runtime, Thread # type:ignore @UnresolvedImport
if self._gui:
if sys.platform == "win32":
appid = ctypes.c_wchar_p(self.app_info.name)
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(appid)
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(appid) # @UndefinedVariable
Thread(lambda: Ghidra.main([self._class_name, *self.args])).start()
is_exiting = threading.Event()
Runtime.getRuntime().addShutdownHook(Thread(is_exiting.set))

View file

@ -21,8 +21,8 @@ import json
from pathlib import Path
import zipfile
from java.lang import Class
from java.io import PrintWriter
from java.lang import Class # type:ignore @UnresolvedImport
from java.io import PrintWriter # type:ignore @UnresolvedImport
from jpype import JMethod, JObject, JClass
from ghidra.framework import Application
@ -85,7 +85,7 @@ class _Helper:
with zipfile.ZipFile(javadoc_zip, "r") as docs:
with docs.open(json_path) as f:
jsondoc = json.load(f)
except (IOError, KeyError) as e:
except (IOError, KeyError):
pass
return jsondoc

View file

@ -112,12 +112,12 @@ def _gui():
# where tkinter can't be imported. Since there may not be an attached
# terminal, the problem still needs to be reported somehow.
try:
import tkinter.messagebox as _
import tkinter.messagebox as _ # @UnusedImport
except ImportError as e:
if platform.system() == "Windows":
# there is no console/terminal to report the error
import ctypes
MessageBox = ctypes.windll.user32.MessageBoxW
MessageBox = ctypes.windll.user32.MessageBoxW # @UndefinedVariable
MessageBox(None, str(e), "Import Error", 0)
sys.exit(1)
# report this before detaching from the console or no

View file

@ -22,7 +22,7 @@ from types import CodeType, FunctionType, MappingProxyType, MethodType, ModuleTy
from docking.widgets.label import GLabel
from generic.theme import GColor
from ghidra.app.plugin.core.console import CodeCompletion
from java.util import Arrays, Collections
from java.util import Arrays, Collections # type:ignore @UnresolvedImport
from jpype import JPackage
from jpype.types import JDouble, JFloat, JInt, JLong, JShort
@ -80,9 +80,10 @@ class PythonCodeCompleter(Completer):
if attr is PythonCodeCompleter._BUILTIN_ATTRIBUTE:
if iskeyword(match.rstrip()):
return label
attr = builtins.__dict__.get(match, PythonCodeCompleter._BUILTIN_ATTRIBUTE)
builtins_dict = builtins.__dict__
attr = builtins_dict.get(match, PythonCodeCompleter._BUILTIN_ATTRIBUTE)
if attr is not PythonCodeCompleter._BUILTIN_ATTRIBUTE and not match.startswith("__"):
attr = builtins.__dict__[match]
attr = builtins_dict[match]
else:
return label
color = _TYPE_COLORS.get(type(attr), PythonCodeCompleter._BUILTIN_ATTRIBUTE)

View file

@ -26,11 +26,11 @@ from code import InteractiveConsole
from ghidra.framework import Application
from ghidra.pyghidra import PyGhidraScriptProvider, PyGhidraPlugin
from ghidra.pyghidra.interpreter import PyGhidraConsole
from java.io import BufferedReader, InputStreamReader
from java.lang import String
from java.lang import Thread as JThread
from java.util import Collections
from java.util.function import Consumer
from java.io import BufferedReader, InputStreamReader # type:ignore @UnresolvedImport
from java.lang import String # type:ignore @UnresolvedImport
from java.lang import Thread as JThread # type:ignore @UnresolvedImport
from java.util import Collections # type:ignore @UnresolvedImport
from java.util.function import Consumer # type:ignore @UnresolvedImport
from jpype import JClass, JImplements, JOverride
from pyghidra.internal.plugin.completions import PythonCodeCompleter

View file

@ -29,8 +29,8 @@ COMPILER_OPTIONS = ["-target", "21", "-source", "21"]
def _to_jar_(jar_path: Path, root: Path):
from java.io import ByteArrayOutputStream
from java.util.jar import JarEntry, JarOutputStream
from java.io import ByteArrayOutputStream # type:ignore @UnresolvedImport
from java.util.jar import JarEntry, JarOutputStream # type:ignore @UnresolvedImport
out = ByteArrayOutputStream()
with JarOutputStream(out) as jar:
@ -46,12 +46,12 @@ def _to_jar_(jar_path: Path, root: Path):
class _CompilerDiagnosticListener:
def __init__(self):
from javax.tools import Diagnostic
from javax.tools import Diagnostic # type:ignore @UnresolvedImport
self.errors: List[Diagnostic] = []
@JOverride
def report(self, diagnostic):
from javax.tools import Diagnostic
from javax.tools import Diagnostic # type:ignore @UnresolvedImport
diagnostic: Diagnostic = diagnostic
kind = diagnostic.getKind()
@ -71,10 +71,10 @@ def java_compile(src_path: Path, jar_path: Path):
:raises ValueError: If an error occurs when compiling the Java source
"""
from java.lang import System
from java.io import Writer
from java.nio.file import Path as JPath
from javax.tools import StandardLocation, ToolProvider
from java.lang import System # type:ignore @UnresolvedImport
from java.io import Writer # type:ignore @UnresolvedImport
from java.nio.file import Path as JPath # type:ignore @UnresolvedImport
from javax.tools import StandardLocation, ToolProvider # type:ignore @UnresolvedImport
with tempfile.TemporaryDirectory() as out:
outdir = Path(out).resolve()

View file

@ -14,7 +14,6 @@
# limitations under the License.
##
import contextlib
import ctypes
import ctypes.util
import html
import importlib.metadata
@ -36,17 +35,17 @@ import jpype
from jpype import imports, _jpype
from packaging.version import Version
from .javac import java_compile
from .script import PyGhidraScript
from .version import ApplicationInfo, ExtensionDetails, MINIMUM_GHIDRA_VERSION
from pyghidra.javac import java_compile
from pyghidra.script import PyGhidraScript
from pyghidra.version import ApplicationInfo, ExtensionDetails, MINIMUM_GHIDRA_VERSION
logger = logging.getLogger(__name__)
@contextlib.contextmanager
def _silence_java_output(stdout=True, stderr=True):
from java.io import OutputStream, PrintStream
from java.lang import System
from java.io import OutputStream, PrintStream # type:ignore @UnresolvedImport
from java.lang import System # type:ignore @UnresolvedImport
out = System.out
err = System.err
null = PrintStream(OutputStream.nullOutputStream())
@ -116,7 +115,7 @@ def _plugin_lock():
"""
File lock for processing plugins
"""
from java.io import RandomAccessFile
from java.io import RandomAccessFile # type:ignore @UnresolvedImport
path = Path(tempfile.gettempdir()) / "pyghidra_plugin_lock"
try:
# Python doesn't have a file lock except for unix systems
@ -431,7 +430,7 @@ class PyGhidraLauncher:
# Add extra class paths
# Do this before installing plugins incase dependencies are needed
if self.class_files:
from java.lang import ClassLoader
from java.lang import ClassLoader # type:ignore @UnresolvedImport
gcl = ClassLoader.getSystemClassLoader()
for path in self.class_files:
gcl.addPath(path)
@ -451,7 +450,7 @@ class PyGhidraLauncher:
self._layout = GhidraLauncher.initializeGhidraEnvironment()
# import properties to register the property customizer
from . import properties as _
from pyghidra import properties as _ # @UnusedImport
_load_entry_points("pyghidra.pre_launch")
@ -654,7 +653,7 @@ class GuiPyGhidraLauncher(PyGhidraLauncher):
@staticmethod
def _get_thread(name: str):
from java.lang import Thread
from java.lang import Thread # type:ignore @UnresolvedImport
for t in Thread.getAllStackTraces().keySet():
if t.getName() == name:
return t
@ -662,11 +661,11 @@ class GuiPyGhidraLauncher(PyGhidraLauncher):
def _launch(self):
from ghidra import Ghidra
from java.lang import Runtime, Thread
from java.lang import Runtime, Thread # type:ignore @UnresolvedImport
if sys.platform == "win32":
appid = ctypes.c_wchar_p(self.app_info.name)
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(appid)
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(appid) # @UndefinedVariable
stdout = _PyGhidraStdOut(sys.stdout)
stderr = _PyGhidraStdOut(sys.stderr)

View file

@ -14,7 +14,6 @@
# limitations under the License.
##
import functools
import importlib
import importlib.util
import inspect
import logging
@ -157,7 +156,7 @@ class PyGhidraScript(dict):
global _headless_interpreter
from ghidra.util import SystemUtilities
from .ghidradoc import _Helper
from pyghidra.ghidradoc import _Helper
if SystemUtilities.isInHeadlessMode() and _headless_interpreter is None:
_headless_interpreter = jobj

View file

@ -56,6 +56,16 @@ class GhidraBuiltinsBuilder {
catch (IOException e) {
e.printStackTrace();
}
File pypredefDir = new File(doclet.getDestDir().getParentFile(), "pypredef");
File pypredefFile = new File(pypredefDir, "ghidra.ghidra_builtins.pypredef");
pypredefDir.mkdirs();
try (PrintWriter printer = new PrintWriter(new FileWriter(pypredefFile))) {
process(printer);
}
catch (IOException e) {
e.printStackTrace();
}
}
/**

View file

@ -15,20 +15,10 @@
*/
package ghidra.doclets.typestubs;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.io.*;
import java.util.*;
import javax.lang.model.element.Element;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.*;
/**
* {@link PythonTypeStubElement} for a package<p/>
@ -105,6 +95,16 @@ final class PythonTypeStubPackage extends PythonTypeStubElement<PackageElement>
catch (IOException e) {
e.printStackTrace();
}
File pypredefDir = new File(doclet.getDestDir().getParentFile(), "pypredef");
File pypredefFile = new File(pypredefDir, packageName + ".pypredef");
pypredefDir.mkdirs();
try (PrintWriter printer = new PrintWriter(new FileWriter(pypredefFile))) {
process(printer, "");
}
catch (IOException e) {
e.printStackTrace();
}
}
/**

View file

@ -16,27 +16,12 @@
package ghidra.doclets.typestubs;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.element.*;
import javax.lang.model.type.*;
import com.sun.source.doctree.DocTree;
@ -278,12 +263,11 @@ class PythonTypeStubType extends PythonTypeStubElement<TypeElement> {
for (PythonTypeStubNestedType nested : getNestedTypes()) {
nested.process(printer, indent);
}
printClassLiteralField(printer, indent);
for (VariableElement field : getFields()) {
printField(field, printer, indent, isStatic(field));
}
if (!getFields().isEmpty()) {
printer.println();
}
ListIterator<PythonTypeStubMethod> methodIterator = getMethods().listIterator();
while (methodIterator.hasNext()) {
PythonTypeStubMethod method = methodIterator.next();
@ -342,6 +326,17 @@ class PythonTypeStubType extends PythonTypeStubElement<TypeElement> {
}
}
/**
* Prints the class literal field to the provided printer
*
* @param printer the printer
* @param indent the indentation
*/
void printClassLiteralField(PrintWriter printer, String indent) {
printer.print(indent);
printer.println("class_: " + applyClassVar(Class.class.getName()));
}
/**
* Wraps the provided type in typing.ClassVar
*