python_ics is now versioned after the Vehicle Spy release its headers come from: Vspy 3.26.3.9 → python_ics 26.3.9.
⚠️ New version scheme — read before pinning
Older releases used the icsneo40 DLL version (e.g. 923.11), which sorts above 26.3.9 under PEP 440. This release therefore carries a version epoch: 1!26.3.9.
pip install python_icsandpip install -U python_icsdo the right thing — pip resolves1!26.3.9as newer than923.11.- Exact pins must include the epoch:
python_ics==1!26.3.9. - Range pins work with or without it:
python_ics>=1!26.3andpython_ics>=26.3both match.
💥 Breaking changes
- Headers updated to Vehicle Spy 3.26.3.9 (
icsnVC40.hverbatim). Upstream renamed 9 legacy device constants —NEODEVICE_BLUE,_DW_VCAN,_FIRE,_VCAN3,_RED,_ECU,_PENDANT,_NEOANALOG,_CT_OBDare now*_DEPRECATED— and removed their settings structs (SRedSettings,SFireSettings,SVCAN3Settings,SECUSettings,SPendantSettings). The module mirrors the header exactly; no compat aliases. Scripts using these legacy devices should stay on923.11. PyNeoDeviceEx.serial_numberboundary fix: serial16796160(MIN_BASE36_SERIAL) now correctly renders as"A0000"instead of"16796160".
🐛 Bug fixes (#229, #233)
- SpyMessage memory corruption: the J1850
Headersetter wrote up to 8 bytes into the 4-byte array, spilling intoData;ExtraDataPtrlengths were silently truncated through 8/16-bit fields; broken null checks could dereference NULL and leak pending exceptions into later calls;ExtraDataPtrcoulddelete[]DLL-owned buffers (double free) and returned an under-referencedPy_None; unsafeT_OBJECT_EXmember descriptors removed. Lengths and element types are now validated (ValueError/TypeError). - 32/64-bit and overflow fixes across the extension:
find_devicesheap overflow (new unsigned int(N)→new[]) and0xFFFFFFFFdevice-type masks no longer raiseOverflowError;get/set_device_settingsno longer write 8 bytes into a 4-byte enum on Linux/macOS; serial numbers ≥0x80000000(ZIK0ZK–ZZZZZZ) are returned positive;script_get_script_statusreported 127 of 255 parameters on Win64; RTC offset, reflash-progress callback, bus-voltage and VNET getters widened to correct types;coremini_load/load_readbinvalidateftell()beforemalloc; several byte-sized parse targets fixed (stack-write hazards). DeviceSettingsNoneis now4294967295on every platform (was-1on Windows); theDeviceSettingTypestruct field round-trips the full 32 bits;DescriptionIDis a signedint16matching the header.- Fixed documentation generation missing functions (#227) and an ignored exception on device close (#228).
📦 Packaging & CI
- Linux/macOS wheels now bundle libicsneo master with full 3.26.3.9 ABI parity — upstream's vendored header is byte-identical to this release's. This includes building libicsneo's new mandatory icspb/protobuf dependency (Ninja generator, per-arch protobuf bootstrap, universal2-correct macOS builds) (#236).
- PyPI deploys work again: the wheel-contents check now accepts the delvewheel-repaired Windows wheel layout (#235).
- New regression tests: generated ctypes struct sizes are validated against the header's
*_SIZEmacros, and the 3.26.3.9 API surface is pinned.
✅ Verification
26→30 tests green on win_amd64/CPython 3.14; hardware-verified on a neoVI FIRE3 (byte-exact Ethernet TX report round-trip, DLL-owned ExtraDataPtr reads, RAM-only settings writes restored).
Known issues
examples/lin_settings_example.pyreferences enum members that predate this release's headers and needs a rewrite.
Full changelog: v923.11...v1!26.3.9