diff --git a/PyMemoryEditor/app/open_process_dialog.py b/PyMemoryEditor/app/open_process_dialog.py index efa668f..9825917 100644 --- a/PyMemoryEditor/app/open_process_dialog.py +++ b/PyMemoryEditor/app/open_process_dialog.py @@ -255,7 +255,7 @@ def _build_ui(self) -> None: self._case_checkbox = QCheckBox("Case-sensitive name lookup") self._case_checkbox.setChecked(False) self._case_checkbox.setToolTip( - "When unchecked, OpenProcess(process_name=…) is called with " + "When unchecked, OpenProcess(name=…) is called with " "case_sensitive=False — useful on Windows where process names " "are case-insensitive." ) @@ -375,7 +375,7 @@ def _try_open(self) -> None: self.process = OpenProcess(pid=pid, **kwargs) else: self.process = OpenProcess( - process_name=entry, + name=entry, case_sensitive=self._case_checkbox.isChecked(), **kwargs, ) diff --git a/PyMemoryEditor/linux/process.py b/PyMemoryEditor/linux/process.py index 44f7aa9..4da0216 100644 --- a/PyMemoryEditor/linux/process.py +++ b/PyMemoryEditor/linux/process.py @@ -39,7 +39,7 @@ class LinuxProcess(AbstractProcess): def __init__( self, *, - process_name: Optional[str] = None, + name: Optional[str] = None, pid: Optional[int] = None, permission=None, case_sensitive: bool = True, @@ -47,22 +47,22 @@ def __init__( strict_bitness: bool = False, ): """ - :param process_name: name of the target process. + :param name: name of the target process. :param pid: process ID. :param permission: accepted for cross-platform API parity; ignored on Linux (access is governed by ptrace_scope and process ownership). Passing a non-None value emits a ``UserWarning`` so a Windows-shaped mask doesn't disappear silently here — pass ``None`` (or omit) on non-Windows platforms. - :param case_sensitive: when False, process_name matching ignores case. - :param exact_match: when False, ``process_name`` is matched as a + :param case_sensitive: when False, name matching ignores case. + :param exact_match: when False, ``name`` is matched as a substring (e.g. ``"chrome"`` finds ``"chromium-browser"``). :param strict_bitness: raise ``BitnessDetectionError`` instead of guessing the host word size when the target's ELF class can't be read. See :class:`~PyMemoryEditor.AbstractProcess`. """ super().__init__( - process_name=process_name, + name=name, pid=pid, case_sensitive=case_sensitive, exact_match=exact_match, diff --git a/PyMemoryEditor/macos/process.py b/PyMemoryEditor/macos/process.py index 9e92879..910d5d4 100644 --- a/PyMemoryEditor/macos/process.py +++ b/PyMemoryEditor/macos/process.py @@ -50,7 +50,7 @@ class MacProcess(AbstractProcess): def __init__( self, *, - process_name: Optional[str] = None, + name: Optional[str] = None, pid: Optional[int] = None, permission=None, case_sensitive: bool = True, @@ -58,22 +58,22 @@ def __init__( strict_bitness: bool = False, ): """ - :param process_name: name of the target process. + :param name: name of the target process. :param pid: process ID. :param permission: accepted for cross-platform API parity; ignored on macOS (access is governed by entitlements / mach_task_self_). Passing a non-None value emits a ``UserWarning`` so a Windows-shaped mask doesn't disappear silently here — pass ``None`` (or omit) on non-Windows platforms. - :param case_sensitive: when False, process_name matching ignores case. - :param exact_match: when False, ``process_name`` is matched as a + :param case_sensitive: when False, name matching ignores case. + :param exact_match: when False, ``name`` is matched as a substring (e.g. ``"chrome"`` finds ``"Google Chrome"``). :param strict_bitness: raise ``BitnessDetectionError`` instead of defaulting to 64-bit when no Mach-O header can be read. See :class:`~PyMemoryEditor.AbstractProcess`. """ super().__init__( - process_name=process_name, + name=name, pid=pid, case_sensitive=case_sensitive, exact_match=exact_match, diff --git a/PyMemoryEditor/process/abstract.py b/PyMemoryEditor/process/abstract.py index c3f6a5c..56f658d 100644 --- a/PyMemoryEditor/process/abstract.py +++ b/PyMemoryEditor/process/abstract.py @@ -45,18 +45,18 @@ class AbstractProcess(ABC): def __init__( self, *, - process_name: Optional[str] = None, + name: Optional[str] = None, pid: Optional[int] = None, case_sensitive: bool = True, exact_match: bool = True, strict_bitness: bool = False, ): """ - :param process_name: name of the target process. + :param name: name of the target process. :param pid: process ID. - :param case_sensitive: when False, process_name matching ignores case + :param case_sensitive: when False, name matching ignores case (recommended on Windows where process names are case-insensitive). - :param exact_match: when False, ``process_name`` is matched as a + :param exact_match: when False, ``name`` is matched as a substring — ``"chrome"`` matches ``"chrome.exe"`` / ``"Google Chrome"``. If more than one process matches, ``AmbiguousProcessNameError`` is raised so you can pick a PID from the list. @@ -72,16 +72,16 @@ def __init__( if pid is not None: self._process_info.pid = pid - elif process_name: - self._process_info.set_process_name( - process_name, + elif name: + self._process_info.set_name( + name, case_sensitive=case_sensitive, exact_match=exact_match, ) else: raise TypeError( - "You must pass an argument to one of these parameters (process_name, pid)." + "You must pass an argument to one of these parameters (name, pid)." ) # Cache for the target's bitness — resolved lazily on first access of diff --git a/PyMemoryEditor/process/info.py b/PyMemoryEditor/process/info.py index b70cdc9..c9c72ae 100644 --- a/PyMemoryEditor/process/info.py +++ b/PyMemoryEditor/process/info.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from .errors import ProcessIDNotExistsError, ProcessNotFoundError -from .util import get_process_id_by_process_name, pid_exists +from .util import get_process_id_by_name, pid_exists class ProcessInfo(object): @@ -11,7 +11,7 @@ class ProcessInfo(object): def __init__(self) -> None: self.__pid: int = -1 - self.__process_name: str = "" + self.__name: str = "" @property def pid(self) -> int: @@ -31,27 +31,27 @@ def pid(self, pid: int) -> None: self.__pid = pid @property - def process_name(self) -> str: - return self.__process_name + def name(self) -> str: + return self.__name - @process_name.setter - def process_name(self, process_name: str) -> None: - self.set_process_name(process_name) + @name.setter + def name(self, name: str) -> None: + self.set_name(name) - def set_process_name( + def set_name( self, - process_name: str, + name: str, *, case_sensitive: bool = True, exact_match: bool = True, ) -> None: - pid = get_process_id_by_process_name( - process_name, + pid = get_process_id_by_name( + name, case_sensitive=case_sensitive, exact_match=exact_match, ) if pid is None: - raise ProcessNotFoundError(process_name) + raise ProcessNotFoundError(name) self.__pid = pid - self.__process_name = process_name + self.__name = name diff --git a/PyMemoryEditor/process/util.py b/PyMemoryEditor/process/util.py index 4f82c5a..fbb6c1e 100644 --- a/PyMemoryEditor/process/util.py +++ b/PyMemoryEditor/process/util.py @@ -32,8 +32,8 @@ def _backend_process_exists(pid: int) -> bool: return False -def get_process_ids_by_process_name( - process_name: str, +def get_process_ids_by_name( + name: str, *, case_sensitive: bool = True, exact_match: bool = True, @@ -41,17 +41,17 @@ def get_process_ids_by_process_name( """ Return a list of all process IDs matching the provided name. - :param process_name: process name to search. + :param name: process name to search. :param case_sensitive: when False, comparison ignores case (useful on Windows). :param exact_match: when False, returns every process whose name *contains* - ``process_name`` as a substring — handy when you don't know the exact + ``name`` as a substring — handy when you don't know the exact executable name (``"chrome"`` matches ``"chrome.exe"``, ``"Google Chrome"``, ``"Chromium"``, ...). Often combined with ``case_sensitive=False``. """ if not case_sensitive: - process_name_cmp = process_name.casefold() + process_name_cmp = name.casefold() else: - process_name_cmp = process_name + process_name_cmp = name matches: List[int] = [] @@ -70,8 +70,8 @@ def get_process_ids_by_process_name( return matches -def get_process_id_by_process_name( - process_name: str, +def get_process_id_by_name( + name: str, *, case_sensitive: bool = True, exact_match: bool = True, @@ -82,14 +82,14 @@ def get_process_id_by_process_name( Raises AmbiguousProcessNameError when more than one process matches. Returns None when no process matches (callers should handle this). """ - matches = get_process_ids_by_process_name( - process_name, + matches = get_process_ids_by_name( + name, case_sensitive=case_sensitive, exact_match=exact_match, ) if len(matches) > 1: - raise AmbiguousProcessNameError(process_name, matches) + raise AmbiguousProcessNameError(name, matches) return matches[0] if matches else None diff --git a/PyMemoryEditor/win32/process.py b/PyMemoryEditor/win32/process.py index 748fb19..f86292a 100644 --- a/PyMemoryEditor/win32/process.py +++ b/PyMemoryEditor/win32/process.py @@ -88,7 +88,7 @@ class WindowsProcess(AbstractProcess): def __init__( self, *, - process_name: Optional[str] = None, + name: Optional[str] = None, pid: Optional[int] = None, permission: Union[ProcessOperationsEnum, int] = DEFAULT_PERMISSION, case_sensitive: bool = False, @@ -96,7 +96,7 @@ def __init__( strict_bitness: bool = False, ): """ - :param process_name: name of the target process. + :param name: name of the target process. :param pid: process ID. :param permission: access mode to the process. Defaults to the read-and-write set: PROCESS_VM_READ | PROCESS_VM_WRITE | @@ -104,13 +104,13 @@ def __init__( (PROCESS_QUERY_INFORMATION is required by VirtualQueryEx, used internally for region enumeration). Narrow the mask if you want a read-only handle, or pass PROCESS_ALL_ACCESS for full control. - :param case_sensitive: when False (default on Windows), process_name + :param case_sensitive: when False (default on Windows), name matching ignores case to align with the OS convention. - :param exact_match: when False, ``process_name`` is matched as a + :param exact_match: when False, ``name`` is matched as a substring (e.g. ``"chrome"`` finds ``"chrome.exe"``). """ super().__init__( - process_name=process_name, + name=name, pid=pid, case_sensitive=case_sensitive, exact_match=exact_match, diff --git a/README.md b/README.md index eb5f620..ebd0853 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ pip install "PyMemoryEditor[speed]" ```python from PyMemoryEditor import OpenProcess -with OpenProcess(process_name="game.exe") as process: +with OpenProcess(name="game.exe") as process: # Scan the whole process for every address holding the value 100. for address in process.search_by_value(int, value=100): diff --git a/docs/api/enums.md b/docs/api/enums.md index 0eb5a87..333aece 100644 --- a/docs/api/enums.md +++ b/docs/api/enums.md @@ -30,7 +30,7 @@ from PyMemoryEditor import ScanTypesEnum ```python from PyMemoryEditor import OpenProcess, ScanTypesEnum -with OpenProcess(process_name="game.exe") as process: +with OpenProcess(name="game.exe") as process: for address in process.search_by_value(int, value=1000, scan_type=ScanTypesEnum.BIGGER_THAN): print(hex(address)) ``` diff --git a/docs/api/errors.md b/docs/api/errors.md index 8f4a486..6084023 100644 --- a/docs/api/errors.md +++ b/docs/api/errors.md @@ -7,7 +7,7 @@ inherit from `PyMemoryEditorError`, so you can catch the whole library: from PyMemoryEditor import PyMemoryEditorError try: - with OpenProcess(process_name="game.exe") as process: + with OpenProcess(name="game.exe") as process: ... except PyMemoryEditorError as exc: print("Library error:", exc) @@ -70,7 +70,7 @@ Raised when the given `pid=` doesn't correspond to a running process. ### `ProcessNotFoundError` -Raised when no running process matches the given `process_name=`. +Raised when no running process matches the given `name=`. ```{eval-rst} .. py:exception:: ProcessNotFoundError @@ -84,7 +84,7 @@ Raised when no running process matches the given `process_name=`. ### `AmbiguousProcessNameError` Raised when **more than one** running process matches the given -`process_name=` (typical when using `exact_match=False`). +`name=` (typical when using `exact_match=False`). ```{eval-rst} .. py:exception:: AmbiguousProcessNameError @@ -106,7 +106,7 @@ Example: from PyMemoryEditor import OpenProcess, AmbiguousProcessNameError try: - OpenProcess(process_name="chrome", exact_match=False) + OpenProcess(name="chrome", exact_match=False) except AmbiguousProcessNameError as exc: print("Multiple matches:", exc.pids) process = OpenProcess(pid=exc.pids[0]) @@ -116,7 +116,7 @@ except AmbiguousProcessNameError as exc: - + @@ -138,7 +138,7 @@ from PyMemoryEditor import ( ) try: - with OpenProcess(process_name="game.exe") as process: + with OpenProcess(name="game.exe") as process: for address in process.search_by_value(int, value=100): try: value = process.read_process_memory(address, int) diff --git a/docs/api/memory-region.md b/docs/api/memory-region.md index eb4f170..88857df 100644 --- a/docs/api/memory-region.md +++ b/docs/api/memory-region.md @@ -90,7 +90,7 @@ of memory with its address, size, permissions and backing path. ### Iterating regions ```python -with OpenProcess(process_name="game.exe") as process: +with OpenProcess(name="game.exe") as process: for region in process.get_memory_regions(): print(f"0x{region.address:016X} {region.size:>12,}") ``` diff --git a/docs/api/module-info.md b/docs/api/module-info.md index a1b682b..6adeb65 100644 --- a/docs/api/module-info.md +++ b/docs/api/module-info.md @@ -64,7 +64,7 @@ Linux, `.dylib` on macOS). ### Listing every module ```python -with OpenProcess(process_name="game.exe") as process: +with OpenProcess(name="game.exe") as process: for module in process.get_modules(): print(f"{module.name:32} 0x{module.base_address:016X} {module.size:>12}") ``` diff --git a/docs/api/openprocess.md b/docs/api/openprocess.md index 5f44739..32a2169 100644 --- a/docs/api/openprocess.md +++ b/docs/api/openprocess.md @@ -23,7 +23,7 @@ All three subclass `AbstractProcess` and share the API documented below. ## Construction ```{eval-rst} -.. py:class:: OpenProcess(*, process_name=None, pid=None, permission=, case_sensitive=, exact_match=True) +.. py:class:: OpenProcess(*, name=None, pid=None, permission=, case_sensitive=, exact_match=True) Open a target process. ``OpenProcess`` resolves to the concrete backend for the host OS, so the ``permission`` and ``case_sensitive`` defaults are @@ -32,23 +32,23 @@ All three subclass `AbstractProcess` and share the API documented below. ``permission`` defaults to ``None`` (ignored) and ``case_sensitive`` to ``True``. - :param str process_name: name of the target process. - :param int pid: process ID. Takes precedence over ``process_name``. + :param str name: name of the target process. + :param int pid: process ID. Takes precedence over ``name``. :param permission: **Windows only.** A :py:class:`ProcessOperationsEnum` value (or integer). Defaults to read+write (``PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION``). On Linux and macOS this argument is accepted for API parity but **ignored**; passing a non-``None`` value emits ``UserWarning``. - :param bool case_sensitive: when ``False``, ``process_name`` matching + :param bool case_sensitive: when ``False``, ``name`` matching ignores case. Default is ``False`` on Windows, ``True`` elsewhere. - :param bool exact_match: when ``False``, ``process_name`` matches as a + :param bool exact_match: when ``False``, ``name`` matches as a substring (``"chrome"`` matches ``"chrome.exe"``). - :raises ProcessNotFoundError: no process matches ``process_name``. + :raises ProcessNotFoundError: no process matches ``name``. :raises ProcessIDNotExistsError: ``pid`` doesn't exist. :raises AmbiguousProcessNameError: more than one process matches. - :raises TypeError: neither ``process_name`` nor ``pid`` was provided. + :raises TypeError: neither ``name`` nor ``pid`` was provided. :raises PermissionError: the OS denied access. ``` @@ -56,7 +56,7 @@ All three subclass `AbstractProcess` and share the API documented below. ```python # By name -with OpenProcess(process_name="game.exe") as process: +with OpenProcess(name="game.exe") as process: ... # By PID @@ -64,14 +64,14 @@ with OpenProcess(pid=1234) as process: ... # Partial, case-insensitive name match (Windows-friendly) -with OpenProcess(process_name="chrome", case_sensitive=False, exact_match=False) as process: +with OpenProcess(name="chrome", case_sensitive=False, exact_match=False) as process: ... # Read-only handle (Windows only) from PyMemoryEditor import ProcessOperationsEnum with OpenProcess( - process_name="game.exe", + name="game.exe", permission=ProcessOperationsEnum.PROCESS_VM_READ | ProcessOperationsEnum.PROCESS_QUERY_INFORMATION, ) as process: ... diff --git a/docs/api/thread-info.md b/docs/api/thread-info.md index 5c438ac..e373e2d 100644 --- a/docs/api/thread-info.md +++ b/docs/api/thread-info.md @@ -73,7 +73,7 @@ Linux. ### Listing threads ```python -with OpenProcess(process_name="game.exe") as process: +with OpenProcess(name="game.exe") as process: for thread in process.get_threads(): print(thread.tid, thread.state, thread.priority) ``` diff --git a/docs/guide/allocate-free.md b/docs/guide/allocate-free.md index 52f1fa2..0adf503 100644 --- a/docs/guide/allocate-free.md +++ b/docs/guide/allocate-free.md @@ -11,7 +11,7 @@ and returns its base address. The OS may round the size up to the page size: ```python -with OpenProcess(process_name="game.exe") as process: +with OpenProcess(name="game.exe") as process: address = process.allocate_memory(64) process.write_int(address, 1337) ``` @@ -119,7 +119,7 @@ Pass a `MemoryProtectionsEnum` (or the underlying integer): from PyMemoryEditor import OpenProcess from PyMemoryEditor.win32.enums.memory_protections import MemoryProtectionsEnum -with OpenProcess(process_name="game.exe") as process: +with OpenProcess(name="game.exe") as process: # Allocate a read-only buffer. address = process.allocate_memory(64, permission=MemoryProtectionsEnum.PAGE_READONLY) ``` @@ -161,7 +161,7 @@ execute injected code. ```python from PyMemoryEditor import OpenProcess -with OpenProcess(process_name="game.exe") as process: +with OpenProcess(name="game.exe") as process: address = process.allocate_memory(128) try: # Write something to it diff --git a/docs/guide/memory-regions.md b/docs/guide/memory-regions.md index e4da275..cc782e9 100644 --- a/docs/guide/memory-regions.md +++ b/docs/guide/memory-regions.md @@ -11,7 +11,7 @@ ultimately touches a region. [`MemoryRegion`](../api/memory-region.md) per region: ```python -with OpenProcess(process_name="game.exe") as process: +with OpenProcess(name="game.exe") as process: for region in process.get_memory_regions(): print( hex(region.address), @@ -110,7 +110,7 @@ Memory Map dialog): ```python from PyMemoryEditor import OpenProcess -with OpenProcess(process_name="game.exe") as process: +with OpenProcess(name="game.exe") as process: print(f"{'ADDRESS':<18}{'SIZE':>14} RWX Source") for region in process.get_memory_regions(): diff --git a/docs/guide/modules-threads.md b/docs/guide/modules-threads.md index 3d5ecf2..b1ab444 100644 --- a/docs/guide/modules-threads.md +++ b/docs/guide/modules-threads.md @@ -15,7 +15,7 @@ shared library it loaded (`.exe`/`.dll` on Windows, the binary and `.so` files on Linux, the Mach-O image and `.dylib` files on macOS). ```python -with OpenProcess(process_name="game.exe") as process: +with OpenProcess(name="game.exe") as process: for module in process.get_modules(): print( module.name, @@ -94,7 +94,7 @@ target. It's useful for introspection ("how many workers does it spawn?", "is the main thread still alive?"). ```python -with OpenProcess(process_name="game.exe") as process: +with OpenProcess(name="game.exe") as process: for thread in process.get_threads(): print(thread.tid, thread.state, thread.priority) diff --git a/docs/guide/opening-process.md b/docs/guide/opening-process.md index cbb5115..aa069d9 100644 --- a/docs/guide/opening-process.md +++ b/docs/guide/opening-process.md @@ -10,7 +10,7 @@ the API is identical. ```python from PyMemoryEditor import OpenProcess -with OpenProcess(process_name="notepad.exe") as process: +with OpenProcess(name="notepad.exe") as process: print("PID:", process.pid) ``` @@ -27,7 +27,7 @@ You can identify the target in two ways: - + @@ -40,7 +40,7 @@ If you pass **both**, `pid` wins. If you pass **neither**, `TypeError` is raised ## Name matching: case and partial matches -By default, `process_name` matching is: +By default, `name` matching is: - **Case-sensitive** on Linux and macOS. - **Case-insensitive** on Windows (matches the OS convention). @@ -50,7 +50,7 @@ You can override both with keyword arguments: ```python # Match "chrome.exe", "ChroMe.EXE", "chrome" — anywhere case-insensitively. -OpenProcess(process_name="chrome", case_sensitive=False, exact_match=False) +OpenProcess(name="chrome", case_sensitive=False, exact_match=False) ``` | Argument | Type | Default | Effect | @@ -71,7 +71,7 @@ of `OpenProcess`. The default opens a **read + write** handle: ```python # Default — same as: OpenProcess( - process_name="notepad.exe", + name="notepad.exe", permission=( ProcessOperationsEnum.PROCESS_VM_READ | ProcessOperationsEnum.PROCESS_VM_WRITE @@ -87,7 +87,7 @@ For a read-only handle (less powerful but useful for static analysis): from PyMemoryEditor import OpenProcess, ProcessOperationsEnum OpenProcess( - process_name="notepad.exe", + name="notepad.exe", permission=ProcessOperationsEnum.PROCESS_VM_READ | ProcessOperationsEnum.PROCESS_QUERY_INFORMATION, ) @@ -97,7 +97,7 @@ For full control: ```python OpenProcess( - process_name="notepad.exe", + name="notepad.exe", permission=ProcessOperationsEnum.PROCESS_ALL_ACCESS, ) ``` @@ -134,7 +134,7 @@ Once closed, any further call raises `ClosedProcess`. | Exception | Meaning | | --- | --- | -| `ProcessNotFoundError` | No process matches the given `process_name`. | +| `ProcessNotFoundError` | No process matches the given `name`. | | `ProcessIDNotExistsError` | The given `pid` doesn't exist on the system. | | `AmbiguousProcessNameError` | More than one process matches a partial name — pick a PID from `.pids`. | | `PermissionError` | The OS denied access — usually fixable; see [Troubleshooting](../troubleshooting.md). | @@ -147,7 +147,7 @@ collectively: from PyMemoryEditor import OpenProcess, PyMemoryEditorError try: - with OpenProcess(process_name="game.exe") as process: + with OpenProcess(name="game.exe") as process: ... except PyMemoryEditorError as e: print("Failed to open process:", e) diff --git a/docs/guide/read-write.md b/docs/guide/read-write.md index f7ebe6c..f3ca335 100644 --- a/docs/guide/read-write.md +++ b/docs/guide/read-write.md @@ -36,7 +36,7 @@ method name. ```python from PyMemoryEditor import OpenProcess -with OpenProcess(process_name="notepad.exe") as process: +with OpenProcess(name="notepad.exe") as process: address = 0x0005000C # Integers — 4 bytes by default @@ -79,7 +79,7 @@ If you need the bytes verbatim, pass `pytype=bytes`. ## Writing a value ```python -with OpenProcess(process_name="notepad.exe") as process: +with OpenProcess(name="notepad.exe") as process: address = 0x0005000C # Write an int — bufflength is optional, so pass value by keyword. @@ -133,7 +133,7 @@ special handling? Use the **typed shortcuts**. Each one is a `read_*` / `write_*` pair with the size and signedness baked into the name: ```python -with OpenProcess(process_name="game.exe") as process: +with OpenProcess(name="game.exe") as process: hp = process.read_int(0x7FF40010) # signed, 4 bytes gold = process.read_uint(0x7FF40014) # unsigned, 4 bytes speed = process.read_float(0x7FF40018) # 32-bit float @@ -170,7 +170,7 @@ Linux and macOS. counting, no manual decoding: ```python -with OpenProcess(process_name="game.exe") as process: +with OpenProcess(name="game.exe") as process: # Write your text — UTF-8 encoding (accents, emoji…) is handled for you. process.write_string(0x7FF40020, "Pedro") diff --git a/docs/guide/searching.md b/docs/guide/searching.md index 9d8dd34..81a64c0 100644 --- a/docs/guide/searching.md +++ b/docs/guide/searching.md @@ -20,7 +20,7 @@ For locating **code or byte patterns** (AOB / signatures), see the dedicated ```python from PyMemoryEditor import OpenProcess -with OpenProcess(process_name="game.exe") as process: +with OpenProcess(name="game.exe") as process: for address in process.search_by_value(int, 4, 100): print(f"Found at 0x{address:X}") ``` @@ -83,7 +83,7 @@ target. Every mode is a member of `ScanTypesEnum`: ```python from PyMemoryEditor import OpenProcess, ScanTypesEnum -with OpenProcess(process_name="game.exe") as process: +with OpenProcess(name="game.exe") as process: # Every address that holds a value bigger than 1_000_000. for address in process.search_by_value( int, 4, 1_000_000, diff --git a/docs/index.md b/docs/index.md index 3a4f55e..2bdfbb7 100644 --- a/docs/index.md +++ b/docs/index.md @@ -37,7 +37,7 @@ Cheat Engine-style interface for free. ```python from PyMemoryEditor import OpenProcess -with OpenProcess(process_name="game.exe") as process: +with OpenProcess(name="game.exe") as process: # Scan the whole process for every address holding the value 100. for address in process.search_by_value(int, value=100): diff --git a/docs/platform-notes.md b/docs/platform-notes.md index 520f13c..8b19d2a 100644 --- a/docs/platform-notes.md +++ b/docs/platform-notes.md @@ -45,7 +45,7 @@ For a **read-only** handle, narrow the mask: from PyMemoryEditor import OpenProcess, ProcessOperationsEnum with OpenProcess( - process_name="notepad.exe", + name="notepad.exe", permission=ProcessOperationsEnum.PROCESS_VM_READ | ProcessOperationsEnum.PROCESS_QUERY_INFORMATION, ) as process: @@ -55,7 +55,7 @@ with OpenProcess( For full control: ```python -OpenProcess(process_name="game.exe", permission=ProcessOperationsEnum.PROCESS_ALL_ACCESS) +OpenProcess(name="game.exe", permission=ProcessOperationsEnum.PROCESS_ALL_ACCESS) ``` ### Running as Administrator diff --git a/docs/quickstart.md b/docs/quickstart.md index 632256f..933e27e 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -19,7 +19,7 @@ process by **name** or **PID**: from PyMemoryEditor import OpenProcess # By process name -process = OpenProcess(process_name="notepad.exe") +process = OpenProcess(name="notepad.exe") # Or by PID process = OpenProcess(pid=1234) @@ -28,7 +28,7 @@ process = OpenProcess(pid=1234) The recommended pattern is a `with` block — it closes the handle automatically: ```python -with OpenProcess(process_name="notepad.exe") as process: +with OpenProcess(name="notepad.exe") as process: ... ``` @@ -43,7 +43,7 @@ name, so there's nothing to remember: ```python from PyMemoryEditor import OpenProcess -with OpenProcess(process_name="notepad.exe") as process: +with OpenProcess(name="notepad.exe") as process: address = 0x0005000C value = process.read_int(address) # read a 4-byte int @@ -69,7 +69,7 @@ You rarely know the address of a value up front — you **find it by scanning**. `search_by_value` yields every address holding a given value: ```python -with OpenProcess(process_name="game.exe") as process: +with OpenProcess(name="game.exe") as process: for address in process.search_by_value(int, value=100): print(f"Found at 0x{address:X}") ``` @@ -90,7 +90,7 @@ The classic loop is: 4. **Read, write or freeze** it. ```python -with OpenProcess(process_name="game.exe") as process: +with OpenProcess(name="game.exe") as process: # 1. First scan — every address currently holding 100. candidates = list(process.search_by_value(int, value=100)) @@ -122,7 +122,7 @@ scan** (Cheat Engine's "Pointer scan"): give it the value's address *right now*, and it discovers the static paths that resolve to it. ```python -with OpenProcess(process_name="game.exe") as process: +with OpenProcess(name="game.exe") as process: # The value lives here this run (e.g. from search_by_value above). for path in process.scan_pointer_paths(0x1FA3C140, max_depth=4): print(path) @@ -134,12 +134,12 @@ Each result is a `PointerPath` carrying the module + offsets — the part that survives a restart. Save the reliable ones and reuse them later: ```python -with OpenProcess(process_name="game.exe") as process: +with OpenProcess(name="game.exe") as process: paths = list(process.scan_pointer_paths(0x1FA3C140, max_depth=4)) process.save_pointer_paths(paths, "health.json") # ...next launch, the absolute address has changed but the path still works: -with OpenProcess(process_name="game.exe") as process: +with OpenProcess(name="game.exe") as process: survivors = process.rescan_pointer_paths("health.json", 0x2B7C0140) pointer = survivors[0].rebase(process).to_pointer(process) pointer.write(9999) diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 9fdce38..0cd51e8 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -28,7 +28,7 @@ from PyMemoryEditor import OpenProcess, ProcessOperationsEnum # Need PROCESS_VM_OPERATION for allocate_memory. with OpenProcess( - process_name="game.exe", + name="game.exe", permission=ProcessOperationsEnum.PROCESS_VM_READ | ProcessOperationsEnum.PROCESS_VM_WRITE | ProcessOperationsEnum.PROCESS_VM_OPERATION @@ -45,7 +45,7 @@ No running process matches the given name. Names are **case-sensitive** by default on Linux/macOS and **case-insensitive** on Windows. Try: ```python -OpenProcess(process_name="chrome", exact_match=False, case_sensitive=False) +OpenProcess(name="chrome", exact_match=False, case_sensitive=False) ``` Or pass `pid=` directly if you can find it via `ps`, Task Manager or @@ -60,7 +60,7 @@ pass it explicitly: from PyMemoryEditor import OpenProcess, AmbiguousProcessNameError try: - process = OpenProcess(process_name="chrome", exact_match=False) + process = OpenProcess(name="chrome", exact_match=False) except AmbiguousProcessNameError as exc: print("Multiple matches:", exc.pids) process = OpenProcess(pid=exc.pids[0]) diff --git a/docs/why.md b/docs/why.md index c9accf3..f73aef9 100644 --- a/docs/why.md +++ b/docs/why.md @@ -94,7 +94,7 @@ PyMemoryEditor wraps all of that behind a handful of methods — `OpenProcess`, ```python from PyMemoryEditor import OpenProcess -with OpenProcess(process_name="game.exe") as process: +with OpenProcess(name="game.exe") as process: # Scan the whole process for every address holding the value 100. for address in process.search_by_value(int, value=100): diff --git a/tests/test_partial_name_match.py b/tests/test_partial_name_match.py index 5c70445..04e3868 100644 --- a/tests/test_partial_name_match.py +++ b/tests/test_partial_name_match.py @@ -21,8 +21,8 @@ from PyMemoryEditor.process.util import ( _iter_processes, - get_process_id_by_process_name, - get_process_ids_by_process_name, + get_process_id_by_name, + get_process_ids_by_name, ) @@ -46,7 +46,7 @@ def own_name(): def test_exact_match_finds_self(own_name): - pids = get_process_ids_by_process_name(own_name, exact_match=True) + pids = get_process_ids_by_name(own_name, exact_match=True) assert os.getpid() in pids @@ -57,7 +57,7 @@ def test_exact_match_does_not_find_substring(own_name): substring = own_name[: len(own_name) // 2] if substring == own_name: pytest.skip("substring equals full name") - pids = get_process_ids_by_process_name(substring, exact_match=True) + pids = get_process_ids_by_name(substring, exact_match=True) assert os.getpid() not in pids @@ -66,7 +66,7 @@ def test_partial_match_finds_self_by_substring(own_name): if len(own_name) <= 2: pytest.skip("process name too short to test substring matching") substring = own_name[: max(2, len(own_name) // 2)] - pids = get_process_ids_by_process_name(substring, exact_match=False) + pids = get_process_ids_by_name(substring, exact_match=False) assert os.getpid() in pids @@ -75,7 +75,7 @@ def test_partial_match_case_insensitive(own_name): swapped = own_name.swapcase() if swapped == own_name: pytest.skip("process name has no alphabetic characters") - pids = get_process_ids_by_process_name( + pids = get_process_ids_by_name( swapped, exact_match=False, case_sensitive=False ) assert os.getpid() in pids @@ -84,7 +84,7 @@ def test_partial_match_case_insensitive(own_name): def test_partial_match_no_results_for_garbage(): """An impossible substring returns an empty list, not a false positive.""" garbage = "definitely_not_a_real_process_name_zzzzzzz_42" - pids = get_process_ids_by_process_name(garbage, exact_match=False) + pids = get_process_ids_by_name(garbage, exact_match=False) assert pids == [] @@ -92,7 +92,7 @@ def test_get_single_returns_none_for_garbage(): """The single-result helper returns None when no process matches.""" garbage = "definitely_not_a_real_process_name_zzzzzzz_42" assert ( - get_process_id_by_process_name(garbage, exact_match=False) is None + get_process_id_by_name(garbage, exact_match=False) is None ) @@ -107,14 +107,14 @@ def test_openprocess_accepts_exact_match_kwarg(own_name): # Don't lean on a known unique name — only that the kwarg is accepted # without raising TypeError and the resulting PID is ours when the name # is unique enough to match exactly one process. - pids = get_process_ids_by_process_name(own_name, exact_match=True) + pids = get_process_ids_by_name(own_name, exact_match=True) if len(pids) != 1: pytest.skip( "more than one process shares this name; OpenProcess would raise " "AmbiguousProcessNameError — not what this test is checking" ) - process = OpenProcess(process_name=own_name, exact_match=True) + process = OpenProcess(name=own_name, exact_match=True) try: assert process.pid == os.getpid() finally: diff --git a/tests/test_process_enumeration.py b/tests/test_process_enumeration.py index 98d3430..ab1f2cd 100644 --- a/tests/test_process_enumeration.py +++ b/tests/test_process_enumeration.py @@ -2,7 +2,7 @@ """ Cross-platform tests for the native process enumeration that backs -``OpenProcess(process_name=...)`` — the per-platform ``(pid, name)`` source +``OpenProcess(name=...)`` — the per-platform ``(pid, name)`` source (``CreateToolhelp32Snapshot`` on Windows, ``/proc`` on Linux, libproc on macOS) exposed through ``PyMemoryEditor.process.util`` — plus the native ``pid_exists`` probe. These exercise the real OS code paths (no mocking; the @@ -20,7 +20,7 @@ from PyMemoryEditor.process.util import ( # noqa: E402 _iter_processes, - get_process_ids_by_process_name, + get_process_ids_by_name, pid_exists, ) @@ -85,7 +85,7 @@ def test_resolve_own_name_includes_self(): if not name: pytest.skip("could not read this process's name on this platform") - pids = get_process_ids_by_process_name(name, exact_match=True) + pids = get_process_ids_by_name(name, exact_match=True) assert os.getpid() in pids @@ -99,7 +99,7 @@ def test_case_insensitive_match_finds_self_native(): pytest.skip("process name has no alphabetic characters to swap") # A list (≥1) — other processes may share the name; we only require ours. - pids = get_process_ids_by_process_name( + pids = get_process_ids_by_name( swapped, exact_match=True, case_sensitive=False ) assert os.getpid() in pids @@ -112,5 +112,5 @@ def test_substring_match_finds_self_native(): pytest.skip("process name too short for a substring test") substring = name[: max(2, len(name) // 2)] - pids = get_process_ids_by_process_name(substring, exact_match=False) + pids = get_process_ids_by_name(substring, exact_match=False) assert os.getpid() in pids diff --git a/tests/test_process_lookup.py b/tests/test_process_lookup.py index 51b151e..25d1109 100644 --- a/tests/test_process_lookup.py +++ b/tests/test_process_lookup.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ -Cross-platform tests for process_name lookup logic, exercising +Cross-platform tests for process name lookup logic, exercising AmbiguousProcessNameError and the case_sensitive flag without depending on real processes existing under known names. """ @@ -30,12 +30,12 @@ def install(processes): def test_returns_none_when_no_match(fake_process_iter): fake_process_iter([("chrome", 1), ("firefox", 2)]) - assert lookup.get_process_id_by_process_name("missing.exe") is None + assert lookup.get_process_id_by_name("missing.exe") is None def test_returns_pid_on_single_match(fake_process_iter): fake_process_iter([("chrome", 1), ("firefox", 2)]) - assert lookup.get_process_id_by_process_name("chrome") == 1 + assert lookup.get_process_id_by_name("chrome") == 1 def test_raises_ambiguous_on_multiple_matches(fake_process_iter): @@ -47,7 +47,7 @@ def test_raises_ambiguous_on_multiple_matches(fake_process_iter): ] ) with pytest.raises(AmbiguousProcessNameError) as exc: - lookup.get_process_id_by_process_name("python") + lookup.get_process_id_by_name("python") assert exc.value.pids == [100, 200] assert exc.value.process_name == "python" @@ -55,17 +55,17 @@ def test_raises_ambiguous_on_multiple_matches(fake_process_iter): def test_case_sensitive_default_distinguishes(fake_process_iter): fake_process_iter([("Notepad.exe", 42)]) - assert lookup.get_process_id_by_process_name("notepad.exe") is None - assert lookup.get_process_id_by_process_name("Notepad.exe") == 42 + assert lookup.get_process_id_by_name("notepad.exe") is None + assert lookup.get_process_id_by_name("Notepad.exe") == 42 def test_case_insensitive_matches(fake_process_iter): fake_process_iter([("Notepad.exe", 42)]) assert ( - lookup.get_process_id_by_process_name("notepad.exe", case_sensitive=False) == 42 + lookup.get_process_id_by_name("notepad.exe", case_sensitive=False) == 42 ) assert ( - lookup.get_process_id_by_process_name("NOTEPAD.EXE", case_sensitive=False) == 42 + lookup.get_process_id_by_name("NOTEPAD.EXE", case_sensitive=False) == 42 ) @@ -76,7 +76,7 @@ def test_get_process_ids_returns_full_list(fake_process_iter): ("python", 200), ] ) - pids = lookup.get_process_ids_by_process_name("python") + pids = lookup.get_process_ids_by_name("python") assert pids == [100, 200] @@ -84,8 +84,8 @@ def test_empty_name_rows_are_tolerated(fake_process_iter): """A process with an empty name (macOS can yield this) must not crash the lookup, and must not spuriously match a non-empty query.""" fake_process_iter([("", 1), ("chrome", 2)]) - assert lookup.get_process_id_by_process_name("chrome") == 2 - assert lookup.get_process_id_by_process_name("") == 1 + assert lookup.get_process_id_by_name("chrome") == 2 + assert lookup.get_process_id_by_name("") == 1 def test_ambiguous_error_has_args_and_str():
ExceptionWhen it's raised
TypeErrorNeither process_name nor pid provided to OpenProcess; or a scan pattern that is not str, bytes or a compiled re.Pattern.
TypeErrorNeither name nor pid provided to OpenProcess; or a scan pattern that is not str, bytes or a compiled re.Pattern.
ValueErrorInvalid pytype, missing bufflength for str/bytes, invalid ptr_size, malformed pattern, byte_length omitted for a regex pattern, etc.
PermissionErrorOS denied access to the target process or a specific region.
OSErrorLow-level read/write failure (e.g. page was freed between scan and read).
What it does
process_name="notepad.exe"name="notepad.exe" Looks up the PID by name. Most natural way for desktop apps and games.