PyMemoryEditor 2.2.0__tar.gz → 2.2.1__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 (165) hide show
  1. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PKG-INFO +6 -5
  2. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/__init__.py +1 -1
  3. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/macos/functions.py +35 -2
  4. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/README.md +5 -4
  5. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/index.md +1 -0
  6. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/platforms/test_macos_transient_reads.py +39 -0
  7. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/.flake8 +0 -0
  8. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/.gitignore +0 -0
  9. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/.readthedocs.yaml +0 -0
  10. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/CODE_OF_CONDUCT.md +0 -0
  11. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/CONTRIBUTING.md +0 -0
  12. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/LICENSE +0 -0
  13. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/Makefile +0 -0
  14. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/__main__.py +0 -0
  15. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/app/__init__.py +0 -0
  16. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/app/_auto_refresh_dialog.py +0 -0
  17. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/app/_icon.py +0 -0
  18. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/app/_widgets.py +0 -0
  19. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/app/application.py +0 -0
  20. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/app/assets/icon.svg +0 -0
  21. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/app/cheat_entry.py +0 -0
  22. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/app/cheat_poll_worker.py +0 -0
  23. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/app/cheat_table.py +0 -0
  24. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/app/log_console_dialog.py +0 -0
  25. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/app/main_window.py +0 -0
  26. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/app/memory_map_dialog.py +0 -0
  27. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/app/memory_viewer_dialog.py +0 -0
  28. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/app/modules_dialog.py +0 -0
  29. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/app/open_process_dialog.py +0 -0
  30. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/app/pointer_chain_dialog.py +0 -0
  31. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/app/pointer_scan_dialog.py +0 -0
  32. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/app/results_view.py +0 -0
  33. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/app/scan_types.py +0 -0
  34. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/app/scan_worker.py +0 -0
  35. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/app/scanner_panel.py +0 -0
  36. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/app/threads_dialog.py +0 -0
  37. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/app/value_types.py +0 -0
  38. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/enums.py +0 -0
  39. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/linux/functions.py +0 -0
  40. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/linux/libc.py +0 -0
  41. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/linux/process.py +0 -0
  42. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/linux/types.py +0 -0
  43. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/macos/__init__.py +0 -0
  44. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/macos/libsystem.py +0 -0
  45. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/macos/process.py +0 -0
  46. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/macos/types.py +0 -0
  47. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/process/__init__.py +0 -0
  48. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/process/abstract.py +0 -0
  49. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/process/errors.py +0 -0
  50. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/process/info.py +0 -0
  51. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/process/module_info.py +0 -0
  52. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/process/pointer_scan.py +0 -0
  53. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/process/region.py +0 -0
  54. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/process/remote_pointer.py +0 -0
  55. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/process/scanning.py +0 -0
  56. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/process/thread_info.py +0 -0
  57. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/process/util.py +0 -0
  58. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/py.typed +0 -0
  59. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/util/__init__.py +0 -0
  60. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/util/convert.py +0 -0
  61. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/util/pattern.py +0 -0
  62. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/util/scan.py +0 -0
  63. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/util/scan_numpy.py +0 -0
  64. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/win32/enums/__init__.py +0 -0
  65. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/win32/enums/memory_allocation_states.py +0 -0
  66. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/win32/enums/memory_protections.py +0 -0
  67. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/win32/enums/memory_types.py +0 -0
  68. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/win32/enums/process_operations.py +0 -0
  69. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/win32/enums/standard_access_rights.py +0 -0
  70. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/win32/functions.py +0 -0
  71. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/win32/process.py +0 -0
  72. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/PyMemoryEditor/win32/types.py +0 -0
  73. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/SECURITY.md +0 -0
  74. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/assets/screenshots/app.png +0 -0
  75. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/assets/social-preview.html +0 -0
  76. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/assets/social-preview.png +0 -0
  77. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/_static/.gitkeep +0 -0
  78. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/_static/custom.css +0 -0
  79. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/_templates/layout.html +0 -0
  80. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/api/enums.md +0 -0
  81. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/api/errors.md +0 -0
  82. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/api/index.md +0 -0
  83. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/api/memory-region.md +0 -0
  84. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/api/module-info.md +0 -0
  85. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/api/openprocess.md +0 -0
  86. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/api/pointer-path.md +0 -0
  87. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/api/remote-pointer.md +0 -0
  88. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/api/thread-info.md +0 -0
  89. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/api/utilities.md +0 -0
  90. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/app.md +0 -0
  91. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/conf.py +0 -0
  92. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/contributing.md +0 -0
  93. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/funding.md +0 -0
  94. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/glossary.md +0 -0
  95. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/guide/allocate-free.md +0 -0
  96. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/guide/index.md +0 -0
  97. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/guide/logging.md +0 -0
  98. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/guide/memory-regions.md +0 -0
  99. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/guide/modules-threads.md +0 -0
  100. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/guide/opening-process.md +0 -0
  101. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/guide/pattern-scan.md +0 -0
  102. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/guide/pointer-scan.md +0 -0
  103. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/guide/pointers.md +0 -0
  104. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/guide/read-write.md +0 -0
  105. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/guide/searching.md +0 -0
  106. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/installation.md +0 -0
  107. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/license.md +0 -0
  108. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/platform-notes.md +0 -0
  109. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/quickstart.md +0 -0
  110. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/requirements.txt +0 -0
  111. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/troubleshooting.md +0 -0
  112. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/docs/why.md +0 -0
  113. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/pyproject.toml +0 -0
  114. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/app/__init__.py +0 -0
  115. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/app/test_app_cheat_entry.py +0 -0
  116. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/app/test_app_pointer_parsing.py +0 -0
  117. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/app/test_app_scan_request.py +0 -0
  118. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/app/test_app_smoke.py +0 -0
  119. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/app/test_app_value_types.py +0 -0
  120. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/app/test_app_widgets.py +0 -0
  121. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/app/test_auto_refresh_dialog.py +0 -0
  122. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/app/test_cheat_poll_worker.py +0 -0
  123. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/app/test_open_process_dialog.py +0 -0
  124. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/app/test_refine_scan_worker.py +0 -0
  125. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/conftest.py +0 -0
  126. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/core/__init__.py +0 -0
  127. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/core/test_errors.py +0 -0
  128. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/core/test_logger.py +0 -0
  129. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/memory/__init__.py +0 -0
  130. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/memory/test_allocate_free.py +0 -0
  131. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/memory/test_bufflength_inference.py +0 -0
  132. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/memory/test_editor.py +0 -0
  133. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/memory/test_partial_io.py +0 -0
  134. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/memory/test_read_into.py +0 -0
  135. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/memory/test_str_boundary.py +0 -0
  136. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/memory/test_str_decode_consistency.py +0 -0
  137. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/memory/test_typed_accessors.py +0 -0
  138. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/memory/test_write_safety.py +0 -0
  139. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/memory/test_write_str_bytes_width.py +0 -0
  140. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/platforms/__init__.py +0 -0
  141. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/platforms/test_bitness.py +0 -0
  142. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/platforms/test_bitness_fallback_warns.py +0 -0
  143. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/platforms/test_linux_types.py +0 -0
  144. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/platforms/test_macos_protect.py +0 -0
  145. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/platforms/test_win32_permissions.py +0 -0
  146. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/pointer/__init__.py +0 -0
  147. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/pointer/test_pointer_chain.py +0 -0
  148. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/pointer/test_pointer_scan.py +0 -0
  149. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/pointer/test_remote_pointer.py +0 -0
  150. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/process/__init__.py +0 -0
  151. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/process/test_memory_region.py +0 -0
  152. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/process/test_module_enumeration.py +0 -0
  153. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/process/test_partial_name_match.py +0 -0
  154. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/process/test_process_enumeration.py +0 -0
  155. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/process/test_process_lookup.py +0 -0
  156. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/process/test_thread_enumeration.py +0 -0
  157. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/scan/__init__.py +0 -0
  158. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/scan/test_chunking_integration.py +0 -0
  159. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/scan/test_pattern_compile.py +0 -0
  160. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/scan/test_pattern_scan.py +0 -0
  161. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/scan/test_region_snapshot.py +0 -0
  162. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/scan/test_scan.py +0 -0
  163. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/scan/test_scan_numpy.py +0 -0
  164. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/tests/scan/test_scan_properties.py +0 -0
  165. {pymemoryeditor-2.2.0 → pymemoryeditor-2.2.1}/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: 2.2.1
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
@@ -71,18 +71,19 @@ A pure-Python library (built on [ctypes](https://docs.python.org/3/library/ctype
71
71
  <i>One unified API. Three operating systems. No C compiler. No native build step.</i>
72
72
  </p>
73
73
 
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
74
  <p align="center">
79
75
  <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>
76
+ <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
77
  <a href="https://pypi.org/project/PyMemoryEditor/"><img src="https://img.shields.io/pypi/v/PyMemoryEditor" alt="Pypi" /></a>
81
78
  <a href="https://github.com/JeanExtreme002/PyMemoryEditor"><img src="https://img.shields.io/pypi/l/PyMemoryEditor" alt="License" /></a>
82
79
  <a href="https://github.com/JeanExtreme002/PyMemoryEditor"><img src="https://img.shields.io/badge/python-3.10+-8A2BE2" alt="Python Version" /></a>
83
80
  <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
81
  </p>
85
82
 
83
+ <p align="center">
84
+ Runs on <b>Windows</b> · <b>Linux</b> · <b>macOS</b> — 32-bit and 64-bit.
85
+ </p>
86
+
86
87
  <p align="center">
87
88
  <img src="https://raw.githubusercontent.com/JeanExtreme002/PyMemoryEditor/main/assets/screenshots/app.png" alt="PyMemoryEditor app attached to a running process" width="820" />
88
89
  </p>
@@ -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__ = "2.2.1"
12
12
 
13
13
  import logging
14
14
  import sys
@@ -311,6 +311,31 @@ _PAGE_GONE_KRS = (
311
311
  KERN_MEMORY_ERROR,
312
312
  )
313
313
 
314
+ # KERN_PROTECTION_FAILURE is tolerated by a full-address-space *sweep* only,
315
+ # never by a read of caller-supplied addresses — hence a second tuple rather
316
+ # than another entry above.
317
+ #
318
+ # The sweeps walk every region the filter accepted and have no opinion about
319
+ # any single one: a range the kernel declines to hand over is a range with no
320
+ # matches in it, and aborting the whole scan over it loses every region that
321
+ # came after. `search_values_by_addresses` is the opposite case — the caller
322
+ # named those addresses, and its documented `raise_error=True` must still be
323
+ # able to report that one of them could not be read. Anything in the tuple
324
+ # above is swallowed even when `raise_error` is set (see
325
+ # process.scanning.iter_values_for_addresses), so putting kr=2 there would
326
+ # silently turn "permission denied" into the same `(address, None)` the caller
327
+ # gets for an address in a gap.
328
+ #
329
+ # Honest limits of what is known here. This was added because a plain
330
+ # search_by_value over the current process died with kr=2 on GitHub's
331
+ # virtualized macOS runners, on a 22 MB region that reported VM_PROT_READ and
332
+ # Shared=False. The mechanism was not established. It does *not* reproduce
333
+ # locally: probing all 135 scannable regions of a live process yields only kr=1
334
+ # and kr=10, and a page deliberately re-protected to PROT_NONE (or never
335
+ # mapped) answers KERN_INVALID_ADDRESS, not kr=2 — so the usual
336
+ # "protection changed under us" story does not explain it.
337
+ _SWEEP_SKIPPABLE_KRS = _PAGE_GONE_KRS + (KERN_PROTECTION_FAILURE,)
338
+
314
339
 
315
340
  class MachReadError(OSError):
316
341
  """OSError subclass that carries the underlying kern_return_t."""
@@ -494,6 +519,14 @@ def _is_transient(exc: BaseException) -> bool:
494
519
  return isinstance(exc, MachReadError) and exc.kr in _PAGE_GONE_KRS
495
520
 
496
521
 
522
+ def _is_skippable_by_sweep(exc: BaseException) -> bool:
523
+ """
524
+ Same as :func:`_is_transient`, plus the codes only a full-address-space
525
+ sweep may skip. See :data:`_SWEEP_SKIPPABLE_KRS`.
526
+ """
527
+ return isinstance(exc, MachReadError) and exc.kr in _SWEEP_SKIPPABLE_KRS
528
+
529
+
497
530
  def _query_region(task: int, address: int):
498
531
  """Return the region containing `address`, or None when the query fails."""
499
532
  addr = mach_vm_address_t(address)
@@ -683,7 +716,7 @@ def search_addresses_by_value(
683
716
  scan_type,
684
717
  _make_read_chunk(task),
685
718
  progress_information=progress_information,
686
- transient_error_check=_is_transient,
719
+ transient_error_check=_is_skippable_by_sweep,
687
720
  )
688
721
 
689
722
 
@@ -1044,7 +1077,7 @@ def search_addresses_by_pattern(
1044
1077
  length,
1045
1078
  _make_read_chunk(task),
1046
1079
  progress_information=progress_information,
1047
- transient_error_check=_is_transient,
1080
+ transient_error_check=_is_skippable_by_sweep,
1048
1081
  )
1049
1082
 
1050
1083
 
@@ -13,18 +13,19 @@ A pure-Python library (built on [ctypes](https://docs.python.org/3/library/ctype
13
13
  <i>One unified API. Three operating systems. No C compiler. No native build step.</i>
14
14
  </p>
15
15
 
16
- <p align="center">
17
- Runs on <b>🪟 Windows</b> · <b>🐧 Linux</b> · <b>🍎 macOS</b> — 32-bit and 64-bit.
18
- </p>
19
-
20
16
  <p align="center">
21
17
  <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>
18
+ <a href="https://codecov.io/gh/JeanExtreme002/PyMemoryEditor"><img src="https://codecov.io/gh/JeanExtreme002/PyMemoryEditor/branch/main/graph/badge.svg" alt="Coverage" /></a>
22
19
  <a href="https://pypi.org/project/PyMemoryEditor/"><img src="https://img.shields.io/pypi/v/PyMemoryEditor" alt="Pypi" /></a>
23
20
  <a href="https://github.com/JeanExtreme002/PyMemoryEditor"><img src="https://img.shields.io/pypi/l/PyMemoryEditor" alt="License" /></a>
24
21
  <a href="https://github.com/JeanExtreme002/PyMemoryEditor"><img src="https://img.shields.io/badge/python-3.10+-8A2BE2" alt="Python Version" /></a>
25
22
  <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>
26
23
  </p>
27
24
 
25
+ <p align="center">
26
+ Runs on <b>Windows</b> · <b>Linux</b> · <b>macOS</b> — 32-bit and 64-bit.
27
+ </p>
28
+
28
29
  <p align="center">
29
30
  <img src="https://raw.githubusercontent.com/JeanExtreme002/PyMemoryEditor/main/assets/screenshots/app.png" alt="PyMemoryEditor app attached to a running process" width="820" />
30
31
  </p>
@@ -15,6 +15,7 @@
15
15
 
16
16
  <p align="center">
17
17
  <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>
18
+ <a href="https://codecov.io/gh/JeanExtreme002/PyMemoryEditor"><img src="https://codecov.io/gh/JeanExtreme002/PyMemoryEditor/branch/main/graph/badge.svg" alt="Coverage" /></a>
18
19
  <a href="https://pypi.org/project/PyMemoryEditor/"><img src="https://img.shields.io/pypi/v/PyMemoryEditor" alt="Pypi" /></a>
19
20
  <a href="https://github.com/JeanExtreme002/PyMemoryEditor"><img src="https://img.shields.io/pypi/l/PyMemoryEditor" alt="License" /></a>
20
21
  <a href="https://github.com/JeanExtreme002/PyMemoryEditor"><img src="https://img.shields.io/badge/python-3.10+-8A2BE2" alt="Python Version" /></a>
@@ -25,6 +25,7 @@ if sys.platform != "darwin":
25
25
  from PyMemoryEditor.macos.functions import ( # noqa: E402
26
26
  MachPartialReadError,
27
27
  MachReadError,
28
+ _is_skippable_by_sweep,
28
29
  _is_transient,
29
30
  )
30
31
  from PyMemoryEditor.macos.types import ( # noqa: E402
@@ -59,6 +60,12 @@ def test_a_vanished_page_lets_the_scan_continue(kr):
59
60
  # KERN_MEMORY_FAILURE directly above KERN_MEMORY_ERROR and documents it as
60
61
  # permanent, which is exactly the distinction being drawn here; KERN_FAILURE is
61
62
  # what task_for_pid returns without the debugger entitlement.
63
+ #
64
+ # KERN_PROTECTION_FAILURE stays here even though a *sweep* skips it (see
65
+ # test_a_sweep_may_skip_a_protected_range below): this classifier also drives
66
+ # search_values_by_addresses, whose caller named the addresses and whose
67
+ # documented raise_error=True must still be able to report one it could not
68
+ # read.
62
69
  @pytest.mark.parametrize(
63
70
  "kr", (KERN_FAILURE, KERN_PROTECTION_FAILURE, KERN_MEMORY_FAILURE)
64
71
  )
@@ -79,3 +86,35 @@ def test_a_short_read_lets_the_scan_continue():
79
86
  def test_a_non_mach_error_is_never_transient():
80
87
  assert not _is_transient(OSError("some unrelated failure"))
81
88
  assert not _is_transient(ValueError("not an OSError at all"))
89
+
90
+
91
+ # A full-address-space sweep is the one caller allowed to skip a range the
92
+ # kernel refuses to hand over. It has no opinion about any single region, and
93
+ # aborting on one loses every region that came after it — which is how a plain
94
+ # search_by_value died on a virtualized macOS CI runner.
95
+ @pytest.mark.parametrize(
96
+ "kr",
97
+ (
98
+ KERN_INVALID_ADDRESS,
99
+ KERN_INVALID_ARGUMENT,
100
+ KERN_NO_ACCESS,
101
+ KERN_MEMORY_ERROR,
102
+ KERN_PROTECTION_FAILURE,
103
+ ),
104
+ )
105
+ def test_a_sweep_may_skip_a_protected_range(kr):
106
+ assert _is_skippable_by_sweep(MachReadError(kr, "read failed (kr=%d)" % kr))
107
+
108
+
109
+ # The sweep is more tolerant, not unconditionally tolerant: a task-level
110
+ # failure still has to stop it.
111
+ @pytest.mark.parametrize("kr", (KERN_FAILURE, KERN_MEMORY_FAILURE))
112
+ def test_a_sweep_still_stops_on_a_task_level_failure(kr):
113
+ assert not _is_skippable_by_sweep(MachReadError(kr, "read failed (kr=%d)" % kr))
114
+
115
+
116
+ def test_only_the_sweep_skips_a_protected_range():
117
+ """The two classifiers must disagree on exactly one code, and this is it."""
118
+ exc = MachReadError(KERN_PROTECTION_FAILURE, "read failed")
119
+ assert _is_skippable_by_sweep(exc)
120
+ assert not _is_transient(exc)
File without changes
File without changes
File without changes