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)
```
## Legacy API
## Legacy API (deprecated)
### 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
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()
__NOTE:__ This function has been deprecated.
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
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
__3.0.0:__
* Introduced many new functions to the PyGhidra API. PyGhidra 3.0.0 requires Ghidra 12.0 or later
to run.
* Revised the the PyGhidra API. See the [API section](#api) for more details.
* PyGhidra 3.0.0 requires Ghidra 12.0 or later to run.
__2.2.1:__
* 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
if TYPE_CHECKING:
from pyghidra.launcher import PyGhidraLauncher
from ghidra.program.model.listing import Program
from ghidra.program.util import GhidraProgramUtilities
from ghidra.framework.model import Project, DomainFile
@ -32,6 +33,28 @@ if TYPE_CHECKING:
from generic.jar import ResourceFile
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(
path: Union[str, Path],
name: str,

View file

@ -14,42 +14,18 @@
# limitations under the License.
##
import contextlib
import warnings
from typing import Union, TYPE_CHECKING, Tuple, ContextManager, List, Optional
from pyghidra.converters import * # pylint: disable=wildcard-import, unused-wildcard-import
if TYPE_CHECKING:
from pyghidra.launcher import PyGhidraLauncher
from ghidra.base.project import GhidraProject
from ghidra.program.flatapi import FlatProgramAPI
from ghidra.program.model.lang import CompilerSpec, Language, LanguageService
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":
from ghidra.program.util import DefaultLanguageService
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 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
@ -386,6 +367,12 @@ def run_script(
: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`.
"""
warnings.warn(
"run_script() is deprecated, use open_project() and ghidra_script() instead.",
DeprecationWarning,
stacklevel=3
)
script_path = str(script_path)
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:

View file

@ -205,6 +205,13 @@ class PyGhidraScript(dict):
def get_static_view(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):
"""
Run this GhidraScript