Modernize como: packaging, battery collection, SQLite storage and CI - #7
Merged
Merged
Conversation
cwoebker
force-pushed
the
claude/battery-tracker-modernize-WVj8X
branch
3 times, most recently
from
June 2, 2026 20:01
8e8c3a2 to
63c1d60
Compare
cwoebker
force-pushed
the
claude/battery-tracker-modernize-WVj8X
branch
from
August 5, 2026 18:19
2237145 to
0b22d45
Compare
Bring the project up to current Python standards and fix battery collection on hardware and kernels released since it was last touched. Packaging: - Replace setup.py and Pipfile with pyproject.toml + uv (Python >=3.10) - Drop .travis.yml, MANIFEST.in and the como_run wrapper - Configure ruff (lint + format) and ty (type checking) - Relicense from BSD to MIT Dependencies: - Replace paxo (CLI framework) and clint (text UI), both unmaintained, with click and rich; sparkline rendering is now a small local function Battery collection: - macOS: parse `ioreg -r -c AppleSmartBattery -a` with plistlib instead of matching grep output by line position, which was pinned to 10.14/10.15 - Linux: read /sys/class/power_supply/, since /proc/acpi/battery/ was removed from the kernel; handle both charge_* and energy_* driver variants - Windows: query CIM via PowerShell, replacing the pywin32/wmi dependency - Drop the server upload/open/init commands; como.cwoebker.com is gone Everything is type-annotated and uses pathlib, f-strings and timezone-aware datetimes throughout.
Four functional improvements on top of the modernized battery layer. Multiple batteries: - get_batteries() returns one entry per physical pack; get_battery() keeps returning a single aggregate for saving, summing capacities and taking the highest cycle count - `como info` lists each pack separately when more than one is present Power reporting: - BatteryInfo gains power_mw and is_charging, computed consistently on every platform. Windows reports ChargeRate/DischargeRate in milliwatts and has no current reading at all, so deriving watts from voltage x current only worked on macOS and Linux - macOS capacity now reads AppleRawMaxCapacity/AppleRawCurrentCapacity where present; on Apple Silicon the legacy keys report a percentage rather than mAh, which made health readings meaningless - Windows raises when no battery is present instead of reporting zeroes, since each CIM query is wrapped in try/catch and yields an empty result Time filtering: - `como data --since 30d` (also w/m/y) limits output to a recent window Exit codes: - Failures raise ComoError, which the CLI turns into a non-zero exit instead of printing a message and returning success
The database was a zlib-compressed JSON blob handled through tablib, rewritten in full on every save. Replace it with SQLite from the standard library. - Schema records the full battery snapshot: time, capacity, cycles, voltage_mv, power_mw and is_charging. Previously only capacity and cycles were kept, so the readings shown by `como info` were never retained - time is UNIQUE, making saves idempotent within a second - --since is applied as a SQL WHERE clause rather than filtering in Python - The file moves to como.db; databases from earlier versions are migrated on first use from both the old format and the old unsuffixed filename, keeping a .bak of the original - tablib is no longer a runtime dependency; import and export use stdlib csv, and export/import now round-trip every column rather than silently dropping voltage, power and charge state - Saving and importing report what actually changed instead of assuming the write succeeded, since duplicate rows are ignored by the UNIQUE constraint
76 tests covering the three modules, with no reliance on real battery hardware. - test_battery.py: macOS plist parsing including the unsigned-amperage conversion and Apple Silicon raw-capacity keys, Linux sysfs across both the charge_* and energy_* driver variants, Windows CIM JSON parsing, multi-pack aggregation and platform dispatch - test_core.py: sparkline rendering, SQLite schema and round-trips, migration from the legacy format and legacy path, --since parsing and filtering, and each command's success and failure paths - test_cli.py: every subcommand through Click's CliRunner, including exit codes Relative timestamps are used wherever a test depends on the current date, so the --since cases cannot rot as they age.
- ci.yml runs ruff, ty and pytest as three parallel jobs on pull requests and on pushes to master. Limiting the push trigger to master keeps branch pushes from duplicating the pull-request run - .pre-commit-config.yaml runs ruff lint and format, plus ty through uv so it resolves against the project environment - pytest-cov is wired into the default pytest invocation with branch coverage, and CI uploads coverage.xml as an artifact - dependabot.yml tracks uv and GitHub Actions dependencies weekly, with Python updates grouped into a single pull request. The alerts on master predate pyproject.toml and no longer describe what the project depends on - mise.toml pins the toolchain for local development
Document the supported platforms, the SQLite database location and schema, the migration from earlier versions, and the current command set. The previous README still described the server upload workflow and the paxo-based install.
cwoebker
force-pushed
the
claude/battery-tracker-modernize-WVj8X
branch
from
August 5, 2026 18:24
0b22d45 to
acb12e3
Compare
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.
Brings
comoup to current Python standards, fixes battery collection on hardware and kernels released since it was last touched, and replaces the flat-file database with SQLite.Why
The tool had stopped working correctly on modern systems. macOS collection matched
ioregoutput by line position with branches pinned to 10.14/10.15, so it read wrong values on anything newer — and on Apple Silicon the capacity keys report a percentage rather than mAh, making health readings meaningless. Linux read/proc/acpi/battery/, removed from the kernel years ago. Bothpaxoandclintare unmaintained.What changed
eccd289a0f1c24--sinceand exit codes05cd8cc6695d46eb44fc10b22d45Packaging —
pyproject.toml+ uv replacesetup.py/Pipfile; Python >= 3.10; ruff and ty configured and clean.Battery collection — macOS parses
ioreg -aoutput withplistlib(works on Intel and Apple Silicon, no version branches); Linux reads/sys/class/power_supply/handling bothcharge_*andenergy_*drivers; Windows queries CIM through PowerShell, dropping thepywin32/wmidependency.New capability — multiple battery packs are reported individually and aggregated for storage; power draw is normalized to milliwatts across all three platforms (Windows exposes only milliwatts, so the old voltage × current calculation never worked there);
como data --since 30dfilters by time window; failures exit non-zero instead of printing and returning success.Storage — SQLite replaces the zlib-compressed JSON blob that was rewritten in full on every save. The schema now retains voltage, power and charge state, which
como infodisplayed but never recorded.Upgrading
Existing databases are migrated automatically on first run, from both the old format and the old filename, and the original is kept alongside as
como.bak. No action needed, but the migration is one-way — the new database is not readable by 0.7.x.Two other things to be aware of: the licence changes from BSD to MIT, and the
upload,openandinitcommands are gone, since the server they talked to no longer exists.Verification
76 tests covering all three modules and all three platforms' collection paths, with no dependence on real battery hardware. ruff, ruff-format, ty and pytest all pass; CI runs them as separate jobs. The upgrade path was also exercised end to end against a real pre-0.8 database rather than only in tests.