PyMemoryEditor 2.2.0__tar.gz → 3.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PKG-INFO +61 -17
  2. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/__init__.py +1 -1
  3. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/linux/functions.py +18 -2
  4. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/macos/functions.py +39 -2
  5. pymemoryeditor-3.0.0/PyMemoryEditor/mcp/__init__.py +68 -0
  6. pymemoryeditor-3.0.0/PyMemoryEditor/mcp/__main__.py +17 -0
  7. pymemoryeditor-3.0.0/PyMemoryEditor/mcp/config.py +301 -0
  8. pymemoryeditor-3.0.0/PyMemoryEditor/mcp/policy.py +311 -0
  9. pymemoryeditor-3.0.0/PyMemoryEditor/mcp/server.py +513 -0
  10. pymemoryeditor-3.0.0/PyMemoryEditor/mcp/session.py +545 -0
  11. pymemoryeditor-3.0.0/PyMemoryEditor/mcp/toolset.py +2231 -0
  12. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/process/abstract.py +24 -6
  13. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/process/scanning.py +17 -0
  14. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/process/util.py +19 -0
  15. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/util/__init__.py +3 -0
  16. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/util/convert.py +154 -10
  17. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/util/scan.py +20 -10
  18. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/win32/functions.py +4 -0
  19. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/README.md +56 -15
  20. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/api/utilities.md +39 -0
  21. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/guide/searching.md +8 -3
  22. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/index.md +2 -0
  23. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/installation.md +44 -0
  24. pymemoryeditor-3.0.0/docs/mcp.md +323 -0
  25. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/pyproject.toml +37 -3
  26. pymemoryeditor-3.0.0/tests/conftest.py +33 -0
  27. pymemoryeditor-3.0.0/tests/mcp_server/__init__.py +1 -0
  28. pymemoryeditor-3.0.0/tests/mcp_server/conftest.py +416 -0
  29. pymemoryeditor-3.0.0/tests/mcp_server/test_argument_fuzz.py +451 -0
  30. pymemoryeditor-3.0.0/tests/mcp_server/test_fake_fidelity.py +739 -0
  31. pymemoryeditor-3.0.0/tests/mcp_server/test_live.py +232 -0
  32. pymemoryeditor-3.0.0/tests/mcp_server/test_parsing.py +739 -0
  33. pymemoryeditor-3.0.0/tests/mcp_server/test_policy.py +228 -0
  34. pymemoryeditor-3.0.0/tests/mcp_server/test_server.py +736 -0
  35. pymemoryeditor-3.0.0/tests/mcp_server/test_session.py +590 -0
  36. pymemoryeditor-3.0.0/tests/mcp_server/test_toolset.py +1720 -0
  37. pymemoryeditor-3.0.0/tests/memory/test_narrow_width_consistency.py +222 -0
  38. pymemoryeditor-3.0.0/tests/memory/test_write_span.py +115 -0
  39. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/platforms/test_macos_transient_reads.py +39 -0
  40. pymemoryeditor-2.2.0/tests/conftest.py +0 -5
  41. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/.flake8 +0 -0
  42. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/.gitignore +0 -0
  43. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/.readthedocs.yaml +0 -0
  44. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/CODE_OF_CONDUCT.md +0 -0
  45. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/CONTRIBUTING.md +0 -0
  46. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/LICENSE +0 -0
  47. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/Makefile +0 -0
  48. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/__main__.py +0 -0
  49. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/app/__init__.py +0 -0
  50. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/app/_auto_refresh_dialog.py +0 -0
  51. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/app/_icon.py +0 -0
  52. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/app/_widgets.py +0 -0
  53. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/app/application.py +0 -0
  54. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/app/assets/icon.svg +0 -0
  55. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/app/cheat_entry.py +0 -0
  56. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/app/cheat_poll_worker.py +0 -0
  57. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/app/cheat_table.py +0 -0
  58. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/app/log_console_dialog.py +0 -0
  59. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/app/main_window.py +0 -0
  60. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/app/memory_map_dialog.py +0 -0
  61. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/app/memory_viewer_dialog.py +0 -0
  62. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/app/modules_dialog.py +0 -0
  63. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/app/open_process_dialog.py +0 -0
  64. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/app/pointer_chain_dialog.py +0 -0
  65. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/app/pointer_scan_dialog.py +0 -0
  66. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/app/results_view.py +0 -0
  67. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/app/scan_types.py +0 -0
  68. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/app/scan_worker.py +0 -0
  69. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/app/scanner_panel.py +0 -0
  70. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/app/threads_dialog.py +0 -0
  71. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/app/value_types.py +0 -0
  72. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/enums.py +0 -0
  73. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/linux/libc.py +0 -0
  74. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/linux/process.py +0 -0
  75. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/linux/types.py +0 -0
  76. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/macos/__init__.py +0 -0
  77. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/macos/libsystem.py +0 -0
  78. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/macos/process.py +0 -0
  79. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/macos/types.py +0 -0
  80. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/process/__init__.py +0 -0
  81. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/process/errors.py +0 -0
  82. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/process/info.py +0 -0
  83. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/process/module_info.py +0 -0
  84. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/process/pointer_scan.py +0 -0
  85. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/process/region.py +0 -0
  86. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/process/remote_pointer.py +0 -0
  87. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/process/thread_info.py +0 -0
  88. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/py.typed +0 -0
  89. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/util/pattern.py +0 -0
  90. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/util/scan_numpy.py +0 -0
  91. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/win32/enums/__init__.py +0 -0
  92. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/win32/enums/memory_allocation_states.py +0 -0
  93. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/win32/enums/memory_protections.py +0 -0
  94. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/win32/enums/memory_types.py +0 -0
  95. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/win32/enums/process_operations.py +0 -0
  96. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/win32/enums/standard_access_rights.py +0 -0
  97. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/win32/process.py +0 -0
  98. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/PyMemoryEditor/win32/types.py +0 -0
  99. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/SECURITY.md +0 -0
  100. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/assets/screenshots/app.png +0 -0
  101. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/assets/social-preview.html +0 -0
  102. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/assets/social-preview.png +0 -0
  103. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/_static/.gitkeep +0 -0
  104. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/_static/custom.css +0 -0
  105. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/_templates/layout.html +0 -0
  106. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/api/enums.md +0 -0
  107. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/api/errors.md +0 -0
  108. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/api/index.md +0 -0
  109. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/api/memory-region.md +0 -0
  110. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/api/module-info.md +0 -0
  111. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/api/openprocess.md +0 -0
  112. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/api/pointer-path.md +0 -0
  113. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/api/remote-pointer.md +0 -0
  114. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/api/thread-info.md +0 -0
  115. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/app.md +0 -0
  116. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/conf.py +0 -0
  117. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/contributing.md +0 -0
  118. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/funding.md +0 -0
  119. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/glossary.md +0 -0
  120. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/guide/allocate-free.md +0 -0
  121. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/guide/index.md +0 -0
  122. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/guide/logging.md +0 -0
  123. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/guide/memory-regions.md +0 -0
  124. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/guide/modules-threads.md +0 -0
  125. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/guide/opening-process.md +0 -0
  126. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/guide/pattern-scan.md +0 -0
  127. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/guide/pointer-scan.md +0 -0
  128. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/guide/pointers.md +0 -0
  129. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/guide/read-write.md +0 -0
  130. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/license.md +0 -0
  131. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/platform-notes.md +0 -0
  132. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/quickstart.md +0 -0
  133. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/requirements.txt +0 -0
  134. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/troubleshooting.md +0 -0
  135. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/docs/why.md +0 -0
  136. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/app/__init__.py +0 -0
  137. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/app/test_app_cheat_entry.py +0 -0
  138. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/app/test_app_pointer_parsing.py +0 -0
  139. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/app/test_app_scan_request.py +0 -0
  140. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/app/test_app_smoke.py +0 -0
  141. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/app/test_app_value_types.py +0 -0
  142. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/app/test_app_widgets.py +0 -0
  143. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/app/test_auto_refresh_dialog.py +0 -0
  144. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/app/test_cheat_poll_worker.py +0 -0
  145. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/app/test_open_process_dialog.py +0 -0
  146. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/app/test_refine_scan_worker.py +0 -0
  147. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/core/__init__.py +0 -0
  148. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/core/test_errors.py +0 -0
  149. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/core/test_logger.py +0 -0
  150. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/memory/__init__.py +0 -0
  151. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/memory/test_allocate_free.py +0 -0
  152. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/memory/test_bufflength_inference.py +0 -0
  153. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/memory/test_editor.py +0 -0
  154. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/memory/test_partial_io.py +0 -0
  155. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/memory/test_read_into.py +0 -0
  156. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/memory/test_str_boundary.py +0 -0
  157. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/memory/test_str_decode_consistency.py +0 -0
  158. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/memory/test_typed_accessors.py +0 -0
  159. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/memory/test_write_safety.py +0 -0
  160. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/memory/test_write_str_bytes_width.py +0 -0
  161. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/platforms/__init__.py +0 -0
  162. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/platforms/test_bitness.py +0 -0
  163. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/platforms/test_bitness_fallback_warns.py +0 -0
  164. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/platforms/test_linux_types.py +0 -0
  165. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/platforms/test_macos_protect.py +0 -0
  166. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/platforms/test_win32_permissions.py +0 -0
  167. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/pointer/__init__.py +0 -0
  168. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/pointer/test_pointer_chain.py +0 -0
  169. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/pointer/test_pointer_scan.py +0 -0
  170. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/pointer/test_remote_pointer.py +0 -0
  171. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/process/__init__.py +0 -0
  172. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/process/test_memory_region.py +0 -0
  173. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/process/test_module_enumeration.py +0 -0
  174. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/process/test_partial_name_match.py +0 -0
  175. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/process/test_process_enumeration.py +0 -0
  176. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/process/test_process_lookup.py +0 -0
  177. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/process/test_thread_enumeration.py +0 -0
  178. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/scan/__init__.py +0 -0
  179. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/scan/test_chunking_integration.py +0 -0
  180. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/scan/test_pattern_compile.py +0 -0
  181. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/scan/test_pattern_scan.py +0 -0
  182. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/scan/test_region_snapshot.py +0 -0
  183. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/scan/test_scan.py +0 -0
  184. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/scan/test_scan_numpy.py +0 -0
  185. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/scan/test_scan_properties.py +0 -0
  186. {pymemoryeditor-2.2.0 → pymemoryeditor-3.0.0}/tests/scan/test_scanning_helper.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: PyMemoryEditor
3
- Version: 2.2.0
3
+ Version: 3.0.0
4
4
  Summary: Read, write and scan process memory in a few lines of Python — Cheat Engine-style scans, pointer chains and AOB search on Windows, Linux and macOS.
5
5
  Project-URL: Homepage, https://github.com/JeanExtreme002/PyMemoryEditor
6
6
  Project-URL: Documentation, https://pymemoryeditor.readthedocs.io
@@ -12,7 +12,7 @@ Author-email: Jean Loui Bernard Silva de Jesus <contact@jeanloui.dev>
12
12
  Maintainer-email: Jean Loui Bernard Silva de Jesus <contact@jeanloui.dev>
13
13
  License-Expression: MIT
14
14
  License-File: LICENSE
15
- Keywords: aob-scan,cheat-engine,ctypes,debugging,game-hacking,introspection,memory-editor,memory-scanner,pattern-scan,pointer-scan,process-memory,reverse-engineering
15
+ Keywords: ai-agent,aob-scan,cheat-engine,ctypes,debugging,game-hacking,introspection,llm-tools,mcp,memory-editor,memory-scanner,model-context-protocol,pattern-scan,pointer-scan,process-memory,reverse-engineering
16
16
  Classifier: Development Status :: 5 - Production/Stable
17
17
  Classifier: Intended Audience :: Developers
18
18
  Classifier: Intended Audience :: Information Technology
@@ -41,6 +41,7 @@ Provides-Extra: dev
41
41
  Requires-Dist: build; extra == 'dev'
42
42
  Requires-Dist: flake8; extra == 'dev'
43
43
  Requires-Dist: hypothesis; extra == 'dev'
44
+ Requires-Dist: mcp<3,>=2; extra == 'dev'
44
45
  Requires-Dist: mypy; extra == 'dev'
45
46
  Requires-Dist: psutil<7,>=5.9; extra == 'dev'
46
47
  Requires-Dist: pyside6>=6.5; extra == 'dev'
@@ -49,6 +50,8 @@ Requires-Dist: pytest-cov; extra == 'dev'
49
50
  Requires-Dist: pytest-qt; extra == 'dev'
50
51
  Requires-Dist: pytest-xdist; extra == 'dev'
51
52
  Requires-Dist: twine; extra == 'dev'
53
+ Provides-Extra: mcp
54
+ Requires-Dist: mcp<3,>=2; extra == 'mcp'
52
55
  Provides-Extra: speed
53
56
  Requires-Dist: numpy>=1.24; extra == 'speed'
54
57
  Provides-Extra: tests
@@ -71,18 +74,19 @@ A pure-Python library (built on [ctypes](https://docs.python.org/3/library/ctype
71
74
  <i>One unified API. Three operating systems. No C compiler. No native build step.</i>
72
75
  </p>
73
76
 
74
- <p align="center">
75
- Runs on <b>🪟 Windows</b> · <b>🐧 Linux</b> · <b>🍎 macOS</b> — 32-bit and 64-bit.
76
- </p>
77
-
78
77
  <p align="center">
79
78
  <a href="https://github.com/JeanExtreme002/PyMemoryEditor/actions/workflows/python-package.yml"><img src="https://github.com/JeanExtreme002/PyMemoryEditor/actions/workflows/python-package.yml/badge.svg" alt="Python Package" /></a>
79
+ <a href="https://codecov.io/gh/JeanExtreme002/PyMemoryEditor"><img src="https://codecov.io/gh/JeanExtreme002/PyMemoryEditor/branch/main/graph/badge.svg" alt="Coverage" /></a>
80
80
  <a href="https://pypi.org/project/PyMemoryEditor/"><img src="https://img.shields.io/pypi/v/PyMemoryEditor" alt="Pypi" /></a>
81
81
  <a href="https://github.com/JeanExtreme002/PyMemoryEditor"><img src="https://img.shields.io/pypi/l/PyMemoryEditor" alt="License" /></a>
82
82
  <a href="https://github.com/JeanExtreme002/PyMemoryEditor"><img src="https://img.shields.io/badge/python-3.10+-8A2BE2" alt="Python Version" /></a>
83
83
  <a href="https://pypi.org/project/PyMemoryEditor/"><img src="https://static.pepy.tech/personalized-badge/pymemoryeditor?period=total&units=international_system&left_color=grey&right_color=orange&left_text=Downloads" alt="Downloads" /></a>
84
84
  </p>
85
85
 
86
+ <p align="center">
87
+ Runs on <b>Windows</b> · <b>Linux</b> · <b>macOS</b> — 32-bit and 64-bit.
88
+ </p>
89
+
86
90
  <p align="center">
87
91
  <img src="https://raw.githubusercontent.com/JeanExtreme002/PyMemoryEditor/main/assets/screenshots/app.png" alt="PyMemoryEditor app attached to a running process" width="820" />
88
92
  </p>
@@ -114,6 +118,13 @@ selective scans:
114
118
  ```bash
115
119
  pip install "PyMemoryEditor[speed]"
116
120
  ```
121
+
122
+ To let an AI assistant drive the library over the Model Context Protocol, use
123
+ the `mcp` extra (see [below](#let-an-ai-assistant-do-it-mcp)):
124
+
125
+ ```bash
126
+ pip install "PyMemoryEditor[mcp]"
127
+ ```
117
128
  📖 Full guide at **[Read the Docs](https://pymemoryeditor.readthedocs.io)**.
118
129
 
119
130
  ---
@@ -138,6 +149,38 @@ That's it — read, write or scan another process in three lines, the same way o
138
149
 
139
150
  ---
140
151
 
152
+ ## Let an AI assistant do it (MCP)
153
+
154
+ PyMemoryEditor ships a **Model Context Protocol server**, so an AI assistant can run the whole loop itself:
155
+
156
+ > *"Find the health value in my game. It's 100 right now."*
157
+ >
158
+ > It scans, asks you to take damage, refines the matches, and hands you the address.
159
+
160
+ ```bash
161
+ pip install "PyMemoryEditor[mcp]"
162
+ claude mcp add pymemoryeditor -- pymemoryeditor-mcp
163
+ ```
164
+
165
+ Or in any client that reads `mcpServers` JSON (Claude Desktop, editors, …):
166
+
167
+ ```json
168
+ {
169
+ "mcpServers": {
170
+ "pymemoryeditor": {
171
+ "command": "pymemoryeditor-mcp",
172
+ "args": []
173
+ }
174
+ }
175
+ }
176
+ ```
177
+
178
+ Fourteen tools cover the full workflow, with scan results kept server-side behind a handle, so a 40 000-hit first scan costs a few tokens instead of your whole context.
179
+
180
+ Read the [MCP guide](https://pymemoryeditor.readthedocs.io/en/latest/mcp.html) to learn more.
181
+
182
+ ---
183
+
141
184
  ## 📖 Documentation
142
185
 
143
186
  Full documentation lives at **[pymemoryeditor.readthedocs.io](https://pymemoryeditor.readthedocs.io)** — installation, the Cheat Engine workflow, every method and parameter, the GUI app guide, platform notes and troubleshooting.
@@ -145,15 +188,16 @@ Full documentation lives at **[pymemoryeditor.readthedocs.io](https://pymemoryed
145
188
  A quick map of where to go:
146
189
 
147
190
  <table>
148
- <tr><td><a href="docs/quickstart.md"><b>Quick Start</b></a></td><td>Open a process, read, write and run your first scan.</td></tr>
149
- <tr><td><a href="docs/guide/searching.md"><b>Searching memory</b></a></td><td>Value scans, ranges, refining results, the Cheat Engine loop.</td></tr>
150
- <tr><td><a href="docs/guide/pattern-scan.md"><b>Pattern scan</b></a></td><td>Find code/data with byte signatures (AOB) and regex.</td></tr>
151
- <tr><td><a href="docs/guide/pointers.md"><b>Pointers</b></a></td><td>Multi-level pointer chains and the live <code>RemotePointer</code>.</td></tr>
152
- <tr><td><a href="docs/guide/pointer-scan.md"><b>Pointer scan</b></a></td><td>Find static pointers that survive ASLR.</td></tr>
153
- <tr><td><a href="docs/app.md"><b>The GUI app</b></a></td><td>The bundled Cheat Engine-style scanner.</td></tr>
154
- <tr><td><a href="docs/api/openprocess.md"><b>API reference</b></a></td><td>Every public class, method and parameter.</td></tr>
155
- <tr><td><a href="docs/platform-notes.md"><b>Platform notes</b></a></td><td>Permissions and quirks on Windows, Linux and macOS.</td></tr>
156
- <tr><td><a href="docs/troubleshooting.md"><b>Troubleshooting</b></a></td><td>Common errors and how to fix them.</td></tr>
191
+ <tr><td><a href="https://pymemoryeditor.readthedocs.io/en/latest/quickstart.html"><b>Quick Start</b></a></td><td>Open a process, read, write and run your first scan.</td></tr>
192
+ <tr><td><a href="https://pymemoryeditor.readthedocs.io/en/latest/guide/searching.html"><b>Searching memory</b></a></td><td>Value scans, ranges, refining results, the Cheat Engine loop.</td></tr>
193
+ <tr><td><a href="https://pymemoryeditor.readthedocs.io/en/latest/guide/pattern-scan.html"><b>Pattern scan</b></a></td><td>Find code/data with byte signatures (AOB) and regex.</td></tr>
194
+ <tr><td><a href="https://pymemoryeditor.readthedocs.io/en/latest/guide/pointers.html"><b>Pointers</b></a></td><td>Multi-level pointer chains and the live <code>RemotePointer</code>.</td></tr>
195
+ <tr><td><a href="https://pymemoryeditor.readthedocs.io/en/latest/guide/pointer-scan.html"><b>Pointer scan</b></a></td><td>Find static pointers that survive ASLR.</td></tr>
196
+ <tr><td><a href="https://pymemoryeditor.readthedocs.io/en/latest/app.html"><b>The GUI app</b></a></td><td>The bundled Cheat Engine-style scanner.</td></tr>
197
+ <tr><td><a href="https://pymemoryeditor.readthedocs.io/en/latest/mcp.html"><b>The MCP server</b></a></td><td>Let an AI assistant drive the scan/refine loop.</td></tr>
198
+ <tr><td><a href="https://pymemoryeditor.readthedocs.io/en/latest/api/openprocess.html"><b>API reference</b></a></td><td>Every public class, method and parameter.</td></tr>
199
+ <tr><td><a href="https://pymemoryeditor.readthedocs.io/en/latest/platform-notes.html"><b>Platform notes</b></a></td><td>Permissions and quirks on Windows, Linux and macOS.</td></tr>
200
+ <tr><td><a href="https://pymemoryeditor.readthedocs.io/en/latest/troubleshooting.html"><b>Troubleshooting</b></a></td><td>Common errors and how to fix them.</td></tr>
157
201
  </table>
158
202
 
159
203
  ---
@@ -175,7 +219,7 @@ A quick map of where to go:
175
219
  ## 🤝 Contributing
176
220
 
177
221
  Pull requests, bug reports and feature ideas are very welcome. Read
178
- [`CONTRIBUTING.md`](CONTRIBUTING.md) for the development setup, test layout and
222
+ [`CONTRIBUTING.md`](https://github.com/JeanExtreme002/PyMemoryEditor/blob/main/CONTRIBUTING.md) for the development setup, test layout and
179
223
  the small set of platform-specific quirks to be aware of.
180
224
 
181
225
  If PyMemoryEditor helped your project, please ⭐ the repo — it's the easiest way to
@@ -185,4 +229,4 @@ support the work and to help others discover the library.
185
229
 
186
230
  ## License
187
231
 
188
- Released under the [MIT License](LICENSE) — free for personal and commercial use.
232
+ Released under the [MIT License](https://github.com/JeanExtreme002/PyMemoryEditor/blob/main/LICENSE) — free for personal and commercial use.
@@ -8,7 +8,7 @@ Supported platforms: Windows, Linux and macOS (32-bit and 64-bit).
8
8
  """
9
9
 
10
10
  __author__ = "Jean Loui Bernard Silva de Jesus"
11
- __version__ = "2.2.0"
11
+ __version__ = "3.0.0"
12
12
 
13
13
  import logging
14
14
  import sys
@@ -32,6 +32,7 @@ from ..util import (
32
32
  _validate_pytype,
33
33
  as_writable_c_buffer,
34
34
  get_c_type_of,
35
+ sign_extend_narrow_int,
35
36
  values_to_bytes,
36
37
  )
37
38
  from ..util.pattern import PatternLike, compile_pattern
@@ -369,13 +370,23 @@ def read_process_memory(pid: int, address: int, pytype: Type[T], bufflength: int
369
370
  _validate_pytype(pytype)
370
371
 
371
372
  data = get_c_type_of(pytype, bufflength)
372
- _process_vm_readv(pid, addressof(data), address, sizeof(data))
373
+ # `bufflength`, not `sizeof(data)`. The two differ whenever the width
374
+ # rounds up to a wider C type — `int` at 3 bytes gets a `c_int32` — and
375
+ # passing the buffer size made this backend read 4 bytes where Windows and
376
+ # macOS read 3, so the same call returned a different value per platform
377
+ # (0x11223344 here against 0x223344 there). `get_c_type_of` guarantees
378
+ # `sizeof(data) >= bufflength`, so reading into the front of a larger,
379
+ # zero-initialised buffer is safe and matches the other two backends.
380
+ _process_vm_readv(pid, addressof(data), address, bufflength)
373
381
 
374
382
  if pytype is str:
375
383
  return bytes(data).decode("utf-8", errors="replace")
376
384
  elif pytype is bytes:
377
385
  return bytes(data)
378
386
  else:
387
+ # Narrow widths pad with zeroes, which reads a signed value as
388
+ # unsigned -- and a scan for the same bytes is signed.
389
+ sign_extend_narrow_int(data, pytype, bufflength)
379
390
  return data.value
380
391
 
381
392
 
@@ -525,7 +536,12 @@ def write_process_memory(
525
536
  data = get_c_type_of(pytype, bufflength)
526
537
  data.value = value.encode() if isinstance(value, str) else value
527
538
 
528
- _process_vm_writev(pid, addressof(data), address, sizeof(data))
539
+ # `bufflength`, not `sizeof(data)` — this one corrupted memory rather than
540
+ # merely disagreeing. A write of 3 bytes sized a 4-byte `c_int32` and then
541
+ # wrote all four, destroying a byte the caller never asked to touch, while
542
+ # Windows and macOS wrote exactly three. Verified on Linux: `w=3` touched 4
543
+ # bytes and `w=5` touched 8.
544
+ _process_vm_writev(pid, addressof(data), address, bufflength)
529
545
  return value
530
546
 
531
547
 
@@ -30,6 +30,7 @@ from ..util import (
30
30
  _validate_pytype,
31
31
  as_writable_c_buffer,
32
32
  get_c_type_of,
33
+ sign_extend_narrow_int,
33
34
  values_to_bytes,
34
35
  )
35
36
  from ..util.pattern import PatternLike, compile_pattern
@@ -311,6 +312,31 @@ _PAGE_GONE_KRS = (
311
312
  KERN_MEMORY_ERROR,
312
313
  )
313
314
 
315
+ # KERN_PROTECTION_FAILURE is tolerated by a full-address-space *sweep* only,
316
+ # never by a read of caller-supplied addresses — hence a second tuple rather
317
+ # than another entry above.
318
+ #
319
+ # The sweeps walk every region the filter accepted and have no opinion about
320
+ # any single one: a range the kernel declines to hand over is a range with no
321
+ # matches in it, and aborting the whole scan over it loses every region that
322
+ # came after. `search_values_by_addresses` is the opposite case — the caller
323
+ # named those addresses, and its documented `raise_error=True` must still be
324
+ # able to report that one of them could not be read. Anything in the tuple
325
+ # above is swallowed even when `raise_error` is set (see
326
+ # process.scanning.iter_values_for_addresses), so putting kr=2 there would
327
+ # silently turn "permission denied" into the same `(address, None)` the caller
328
+ # gets for an address in a gap.
329
+ #
330
+ # Honest limits of what is known here. This was added because a plain
331
+ # search_by_value over the current process died with kr=2 on GitHub's
332
+ # virtualized macOS runners, on a 22 MB region that reported VM_PROT_READ and
333
+ # Shared=False. The mechanism was not established. It does *not* reproduce
334
+ # locally: probing all 135 scannable regions of a live process yields only kr=1
335
+ # and kr=10, and a page deliberately re-protected to PROT_NONE (or never
336
+ # mapped) answers KERN_INVALID_ADDRESS, not kr=2 — so the usual
337
+ # "protection changed under us" story does not explain it.
338
+ _SWEEP_SKIPPABLE_KRS = _PAGE_GONE_KRS + (KERN_PROTECTION_FAILURE,)
339
+
314
340
 
315
341
  class MachReadError(OSError):
316
342
  """OSError subclass that carries the underlying kern_return_t."""
@@ -494,6 +520,14 @@ def _is_transient(exc: BaseException) -> bool:
494
520
  return isinstance(exc, MachReadError) and exc.kr in _PAGE_GONE_KRS
495
521
 
496
522
 
523
+ def _is_skippable_by_sweep(exc: BaseException) -> bool:
524
+ """
525
+ Same as :func:`_is_transient`, plus the codes only a full-address-space
526
+ sweep may skip. See :data:`_SWEEP_SKIPPABLE_KRS`.
527
+ """
528
+ return isinstance(exc, MachReadError) and exc.kr in _SWEEP_SKIPPABLE_KRS
529
+
530
+
497
531
  def _query_region(task: int, address: int):
498
532
  """Return the region containing `address`, or None when the query fails."""
499
533
  addr = mach_vm_address_t(address)
@@ -554,6 +588,9 @@ def read_process_memory(
554
588
  elif pytype is bytes:
555
589
  return bytes(data)
556
590
  else:
591
+ # Narrow widths pad with zeroes, which reads a signed value as
592
+ # unsigned -- and a scan for the same bytes is signed.
593
+ sign_extend_narrow_int(data, pytype, bufflength)
557
594
  return data.value
558
595
 
559
596
 
@@ -683,7 +720,7 @@ def search_addresses_by_value(
683
720
  scan_type,
684
721
  _make_read_chunk(task),
685
722
  progress_information=progress_information,
686
- transient_error_check=_is_transient,
723
+ transient_error_check=_is_skippable_by_sweep,
687
724
  )
688
725
 
689
726
 
@@ -1044,7 +1081,7 @@ def search_addresses_by_pattern(
1044
1081
  length,
1045
1082
  _make_read_chunk(task),
1046
1083
  progress_information=progress_information,
1047
- transient_error_check=_is_transient,
1084
+ transient_error_check=_is_skippable_by_sweep,
1048
1085
  )
1049
1086
 
1050
1087
 
@@ -0,0 +1,68 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """
4
+ A Model Context Protocol server for PyMemoryEditor.
5
+
6
+ Exposes the library's process-memory tools over MCP so an AI assistant can run
7
+ the Cheat Engine loop itself — enumerate processes, attach, scan for a value,
8
+ narrow the matches as the value changes, then read (and optionally write) the
9
+ address it converged on.
10
+
11
+ Install and run::
12
+
13
+ pip install "PyMemoryEditor[mcp]"
14
+ pymemoryeditor-mcp # asks before attaching; writes allowed
15
+ pymemoryeditor-mcp --read-only # never modifies a target
16
+
17
+ Or register it with a client — Claude Code::
18
+
19
+ claude mcp add pymemoryeditor -- pymemoryeditor-mcp
20
+
21
+ ...and any client that reads ``mcpServers`` JSON::
22
+
23
+ {
24
+ "mcpServers": {
25
+ "pymemoryeditor": {
26
+ "command": "pymemoryeditor-mcp",
27
+ "args": []
28
+ }
29
+ }
30
+ }
31
+
32
+ No flags are needed, because consent is asked for where it can actually be
33
+ given: attaching to a process the operator did not pre-approve **asks the
34
+ user**, and every ``write_value`` call is confirmed by their client.
35
+ ``--read-only`` drops the write tool entirely, ``--allow-process NAME``
36
+ pre-approves a target so it stops prompting, and ``--allow-any-process`` turns
37
+ prompting off for scripted runs. Read :doc:`the MCP guide </mcp>` before
38
+ pointing it at anything you care about — it runs with your privileges and it is
39
+ **not a sandbox**.
40
+
41
+ Layout: :mod:`~PyMemoryEditor.mcp.toolset` holds the tools (and imports no MCP
42
+ SDK, so it is testable on its own), :mod:`~PyMemoryEditor.mcp.session` the
43
+ process/scan handles, :mod:`~PyMemoryEditor.mcp.policy` the access rules, and
44
+ :mod:`~PyMemoryEditor.mcp.server` the protocol wiring.
45
+ """
46
+
47
+ from .config import ServerConfig, build_parser, parse_args
48
+ from .policy import AccessDecision, ProcessPolicy
49
+ from .server import INSTRUCTIONS, build_server, main
50
+ from .session import ScanResult, Session, SessionError, SessionStore
51
+ from .toolset import MemoryToolset, ToolError
52
+
53
+ __all__ = (
54
+ "INSTRUCTIONS",
55
+ "AccessDecision",
56
+ "MemoryToolset",
57
+ "ProcessPolicy",
58
+ "ScanResult",
59
+ "ServerConfig",
60
+ "Session",
61
+ "SessionError",
62
+ "SessionStore",
63
+ "ToolError",
64
+ "build_parser",
65
+ "build_server",
66
+ "main",
67
+ "parse_args",
68
+ )
@@ -0,0 +1,17 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """``python -m PyMemoryEditor.mcp`` — the same entry point as the console script.
4
+
5
+ Useful when the console script is not on PATH, which is the usual situation
6
+ when an MCP client launches the server from a virtualenv it did not activate::
7
+
8
+ {"command": "/path/to/venv/bin/python",
9
+ "args": ["-m", "PyMemoryEditor.mcp", "--allow-process", "game.exe"]}
10
+ """
11
+
12
+ import sys
13
+
14
+ from .server import main
15
+
16
+ if __name__ == "__main__":
17
+ sys.exit(main())