GP-5961: Deprecating pyghidra.open_program() and pyghidra.run_script()

Also fixed a recent regression with calling pyghidra.run_script()
This commit is contained in:
Ryan Kurtz 2025-08-29 13:45:36 -04:00
parent ec28004339
commit e0a060660b
4 changed files with 50 additions and 29 deletions

View file

@ -311,9 +311,11 @@ with pyghidra.open_project(os.environ["GHIDRA_PROJECT_DIR"], "ExampleProject", c
pyghidra.ghidra_script(f"{os.environ['GHIDRA_SCRIPTS_DIR']}/HelloWorldScript.java", project) pyghidra.ghidra_script(f"{os.environ['GHIDRA_SCRIPTS_DIR']}/HelloWorldScript.java", project)
``` ```
## Legacy API ## Legacy API (deprecated)
### pyghidra.open_program() ### pyghidra.open_program()
__NOTE:__ This function has been deprecated.
To have PyGhidra setup a binary file for you, use the `open_program()` function. This will setup a To have PyGhidra setup a binary file for you, use the `open_program()` function. This will setup a
Ghidra project and import the given binary file as a program for you. Ghidra project and import the given binary file as a program for you.
@ -401,6 +403,8 @@ with pyghidra.open_program("binary_file.exe", project_name="MyProject", project_
``` ```
### pyghidra.run_script() ### pyghidra.run_script()
__NOTE:__ This function has been deprecated.
PyGhidra can also be used to run an existing Ghidra Python script directly in your native CPython PyGhidra can also be used to run an existing Ghidra Python script directly in your native CPython
interpreter using the `run_script()` function. However, while you can technically run an existing interpreter using the `run_script()` function. However, while you can technically run an existing
Ghidra script unmodified, you may run into issues due to differences between Jython 2 and Ghidra script unmodified, you may run into issues due to differences between Jython 2 and
@ -547,8 +551,8 @@ import pdb_ # imports Ghidra's pdb
``` ```
## Change History ## Change History
__3.0.0:__ __3.0.0:__
* Introduced many new functions to the PyGhidra API. PyGhidra 3.0.0 requires Ghidra 12.0 or later * Revised the the PyGhidra API. See the [API section](#api) for more details.
to run. * PyGhidra 3.0.0 requires Ghidra 12.0 or later to run.
__2.2.1:__ __2.2.1:__
* PyGhidra now launches with the current working directory removed from `sys.path` to prevent * PyGhidra now launches with the current working directory removed from `sys.path` to prevent

View file

@ -20,6 +20,7 @@ from typing import Union, TYPE_CHECKING, Tuple, List, Callable, Any
from pyghidra.converters import * # pylint: disable=wildcard-import, unused-wildcard-import from pyghidra.converters import * # pylint: disable=wildcard-import, unused-wildcard-import
if TYPE_CHECKING: if TYPE_CHECKING:
from pyghidra.launcher import PyGhidraLauncher
from ghidra.program.model.listing import Program from ghidra.program.model.listing import Program
from ghidra.program.util import GhidraProgramUtilities from ghidra.program.util import GhidraProgramUtilities
from ghidra.framework.model import Project, DomainFile from ghidra.framework.model import Project, DomainFile
@ -32,6 +33,28 @@ if TYPE_CHECKING:
from generic.jar import ResourceFile from generic.jar import ResourceFile
from java.lang import Object # type:ignore @UnresolvedImport from java.lang import Object # type:ignore @UnresolvedImport
def start(verbose=False, *, install_dir: Path = None) -> "PyGhidraLauncher":
"""
Starts the JVM and fully initializes Ghidra in Headless mode.
:param verbose: Enable verbose output during JVM startup (Defaults to False)
:param install_dir: The path to the Ghidra installation directory.
(Defaults to the GHIDRA_INSTALL_DIR environment variable or "lastrun" file)
:return: The PyGhidraLauncher used to start the JVM
"""
from pyghidra.launcher import HeadlessPyGhidraLauncher
launcher = HeadlessPyGhidraLauncher(verbose=verbose, install_dir=install_dir)
launcher.start()
return launcher
def started() -> bool:
"""
Whether the PyGhidraLauncher has already started.
"""
from pyghidra.launcher import PyGhidraLauncher
return PyGhidraLauncher.has_launched()
def open_project( def open_project(
path: Union[str, Path], path: Union[str, Path],
name: str, name: str,

View file

@ -14,42 +14,18 @@
# limitations under the License. # limitations under the License.
## ##
import contextlib import contextlib
import warnings
from typing import Union, TYPE_CHECKING, Tuple, ContextManager, List, Optional from typing import Union, TYPE_CHECKING, Tuple, ContextManager, List, Optional
from pyghidra.converters import * # pylint: disable=wildcard-import, unused-wildcard-import from pyghidra.converters import * # pylint: disable=wildcard-import, unused-wildcard-import
if TYPE_CHECKING: if TYPE_CHECKING:
from pyghidra.launcher import PyGhidraLauncher
from ghidra.base.project import GhidraProject from ghidra.base.project import GhidraProject
from ghidra.program.flatapi import FlatProgramAPI from ghidra.program.flatapi import FlatProgramAPI
from ghidra.program.model.lang import CompilerSpec, Language, LanguageService from ghidra.program.model.lang import CompilerSpec, Language, LanguageService
from ghidra.program.model.listing import Program from ghidra.program.model.listing import Program
def start(verbose=False, *, install_dir: Path = None) -> "PyGhidraLauncher":
"""
Starts the JVM and fully initializes Ghidra in Headless mode.
:param verbose: Enable verbose output during JVM startup (Defaults to False)
:param install_dir: The path to the Ghidra installation directory.
(Defaults to the GHIDRA_INSTALL_DIR environment variable or "lastrun" file)
:return: The PyGhidraLauncher used to start the JVM
"""
from pyghidra.launcher import HeadlessPyGhidraLauncher
launcher = HeadlessPyGhidraLauncher(verbose=verbose, install_dir=install_dir)
launcher.start()
return launcher
def started() -> bool:
"""
Whether the PyGhidraLauncher has already started.
"""
from pyghidra.launcher import PyGhidraLauncher
return PyGhidraLauncher.has_launched()
def _get_language(lang_id: str) -> "Language": def _get_language(lang_id: str) -> "Language":
from ghidra.program.util import DefaultLanguageService from ghidra.program.util import DefaultLanguageService
from ghidra.program.model.lang import LanguageID, LanguageNotFoundException from ghidra.program.model.lang import LanguageID, LanguageNotFoundException
@ -230,6 +206,11 @@ def open_program(
:raises ValueError: If the provided language, compiler or loader is invalid. :raises ValueError: If the provided language, compiler or loader is invalid.
:raises TypeError: If the provided loader does not implement `ghidra.app.util.opinion.Loader`. :raises TypeError: If the provided loader does not implement `ghidra.app.util.opinion.Loader`.
""" """
warnings.warn(
"open_program() is deprecated, use open_project() and program_context() or program_loader() instead.",
DeprecationWarning,
stacklevel=3
)
from pyghidra.launcher import PyGhidraLauncher, HeadlessPyGhidraLauncher from pyghidra.launcher import PyGhidraLauncher, HeadlessPyGhidraLauncher
@ -386,6 +367,12 @@ def run_script(
:raises ValueError: If the provided language, compiler or loader is invalid. :raises ValueError: If the provided language, compiler or loader is invalid.
:raises TypeError: If the provided loader does not implement `ghidra.app.util.opinion.Loader`. :raises TypeError: If the provided loader does not implement `ghidra.app.util.opinion.Loader`.
""" """
warnings.warn(
"run_script() is deprecated, use open_project() and ghidra_script() instead.",
DeprecationWarning,
stacklevel=3
)
script_path = str(script_path) script_path = str(script_path)
args = binary_path, project_location, project_name, verbose, analyze, lang, compiler, loader, program_name, nested_project_location args = binary_path, project_location, project_name, verbose, analyze, lang, compiler, loader, program_name, nested_project_location
with _flat_api(*args, install_dir=install_dir) as script: with _flat_api(*args, install_dir=install_dir) as script:

View file

@ -205,6 +205,13 @@ class PyGhidraScript(dict):
def get_static_view(self): def get_static_view(self):
return _StaticMap(self) return _StaticMap(self)
def set(self, state, monitor, writer, error_writer):
"""
see GhidraScript.set
"""
from ghidra.app.script import ScriptControls
self._script.set(state, ScriptControls(writer, error_writer, monitor))
def run(self, script_path: str = None, script_args: List[str] = None): def run(self, script_path: str = None, script_args: List[str] = None):
""" """
Run this GhidraScript Run this GhidraScript