chore: bump version to 3.0.0 - #99
Merged
Merged
Conversation
Major, not minor, because of one change: `read_process_memory(addr, int, N)`
with N in 3, 5, 6 or 7 and the value's top bit set now returns a different
number, on every platform, with no exception raised.
bytes in memory: FF FF FF (a 24-bit unsigned field at its maximum)
2.2.1 -> 16777215
3.0.0 -> -1
Half the value space of each affected width changes sign. A guard like
`if money < 1000` silently inverts, and in a memory editor the branch that
flips is the one that writes. The round trip also stops closing: the range
check on the write path accepts the union of the signed and unsigned ranges,
so 16777215 is still a valid 3-byte write and reads back as -1.
Nothing in the API signals it. Measured across 220 read combinations, the
whole surface of the change is four of them — but semver is not about how many
callers break, it is about whether they can break without knowing.
The five other behaviour changes do not on their own need a major. Their
previous behaviour was memory-unsafe or meaningless, so no working code
depends on it: a width wider than the type's C representation overflowed the
caller's buffer (`get_c_type_of(bool, 8)` sized 1 byte for an 8-byte read),
`float` at 3 bytes returned a plausible-looking number from unread bytes, and
Linux read and wrote `sizeof(buffer)` rather than the width asked for, which
made the same call answer differently per platform.
Also in this release: the MCP server (14 tools, opt-in via the `mcp` extra),
`iter_processes()`, and `decode_scan_target` / `make_predicate` promoted from
private.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #99 +/- ##
=======================================
Coverage 89.89% 89.89%
=======================================
Files 41 41
Lines 3632 3632
=======================================
Hits 3265 3265
Misses 367 367
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bumps
PyMemoryEditor/__init__.pyto3.0.0. Hatch reads the version fromthere (
[tool.hatch.version]), so it is the only place it lives — confirmed bybuilding an sdist, which came out as
pymemoryeditor-3.0.0.tar.gz.Why major and not minor
One change forces it.
read_process_memory(addr, int, N)with N in 3, 5, 6 or7 and the value's top bit set returns a different number now — on every
platform, with no exception raised.
Cheat Engine offers a "3 Bytes" type precisely because games cap money and
score in 24-bit fields, and this library exists to reproduce that workflow — so
a reader following a tutorial lands exactly there. An existing script, with no
line changed:
money < 1000FalseTrueThe guard inverted, and in a memory editor the branch that flips is the one
that writes. The round trip also stops closing: the write path's range
check accepts the union of the signed and unsigned ranges, so
16777215isstill a valid 3-byte write and reads back as
-1.Half the value space of each affected width changes sign (8388608–16777215
at width 3, and the equivalent band at 5, 6 and 7). Widths 1, 2, 4 and 8 are
untouched, and so is the
intdefault of 4.Why the other five behaviour changes would not have needed one
Measured across 220 read combinations, only 4 change a value silently — the
ones above. Of the rest, 88 turn a value into a
ValueError, and no workingcode depends on what they returned before:
caller's buffer —
get_c_type_of(bool, 8)sized 1 byte for an 8-byte read,and
intat 16 overflowed 8;floatat any width but 4 or 8 returned a plausible-looking number decodedfrom bytes nobody read (
5.5e-318);sizeof(buffer)instead of the width asked for, so thesame call answered differently per platform.
strandbytesdid not change at all — none of their 44 combinations.Also shipping
The MCP server (14 tools, opt-in through the
mcpextra — the core librarystays dependency-free),
iter_processes()as a dependency-free counterpart topsutil.process_iter(), anddecode_scan_target/make_predicatepromotedfrom private.
Ordering
Merge #96 first. It is still open, and it adds a session cap whose refusal
is new behaviour an embedder could hit. This branch is a one-line change and
rebases trivially, so it should be the last thing in before the release is cut.