cellpycore 0.2.4__tar.gz → 0.2.6__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.
- {cellpycore-0.2.4/.issueflows/02-partly-solved-issues → cellpycore-0.2.6/.issueflows/03-solved-issues}/issue100_status.md +1 -1
- cellpycore-0.2.6/.issueflows/03-solved-issues/issue142_original.md +48 -0
- cellpycore-0.2.6/.issueflows/03-solved-issues/issue142_plan.md +86 -0
- cellpycore-0.2.6/.issueflows/03-solved-issues/issue142_status.md +20 -0
- cellpycore-0.2.6/.issueflows/03-solved-issues/issue147_original.md +15 -0
- cellpycore-0.2.6/.issueflows/03-solved-issues/issue147_plan.md +99 -0
- cellpycore-0.2.6/.issueflows/03-solved-issues/issue147_status.md +24 -0
- cellpycore-0.2.6/.issueflows/03-solved-issues/issue148_original.md +15 -0
- cellpycore-0.2.6/.issueflows/03-solved-issues/issue148_plan.md +144 -0
- cellpycore-0.2.6/.issueflows/03-solved-issues/issue148_status.md +27 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/04-designs-and-guides/cellpy-core-integration-roadmap.md +14 -10
- cellpycore-0.2.6/.vscode/settings.json +14 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/HISTORY.md +13 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/PKG-INFO +2 -2
- {cellpycore-0.2.4 → cellpycore-0.2.6}/pyproject.toml +1 -1
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/cell_core.py +51 -21
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/merge.py +37 -9
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/summarizers.py +18 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/uv.lock +2 -2
- cellpycore-0.2.4/.vscode/settings.json +0 -7
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.aliases +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.cursor/rules/cellpy-core-migration.mdc +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.cursor/rules/graphify.mdc +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.cursor/rules/issueflow-rules.mdc +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.cursor/rules/kiss.mdc +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.cursor/rules/this-project.mdc +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.cursor/skills/caveman/SKILL.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.cursor/skills/grill-me/SKILL.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.cursor/skills/iflow/SKILL.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.cursor/skills/iflow-archive/SKILL.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.cursor/skills/iflow-cleanup/SKILL.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.cursor/skills/iflow-close/SKILL.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.cursor/skills/iflow-comments/SKILL.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.cursor/skills/iflow-cycle/SKILL.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.cursor/skills/iflow-epic/SKILL.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.cursor/skills/iflow-fix/SKILL.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.cursor/skills/iflow-graphify/SKILL.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.cursor/skills/iflow-history-update/SKILL.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.cursor/skills/iflow-init/SKILL.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.cursor/skills/iflow-pause/SKILL.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.cursor/skills/iflow-pick/SKILL.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.cursor/skills/iflow-plan/SKILL.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.cursor/skills/iflow-start/SKILL.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.cursor/skills/iflow-status/SKILL.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.cursor/skills/iflow-version-bump/SKILL.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.cursor/skills/iflow-yolo/SKILL.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.gitattributes +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.gitignore +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/00-tools/.gitkeep +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/00-tools/README.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/01-current-issues/.gitkeep +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/02-partly-solved-issues/.gitkeep +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/.gitkeep +0 -0
- {cellpycore-0.2.4/.issueflows/02-partly-solved-issues → cellpycore-0.2.6/.issueflows/03-solved-issues}/issue100_original.md +0 -0
- {cellpycore-0.2.4/.issueflows/02-partly-solved-issues → cellpycore-0.2.6/.issueflows/03-solved-issues}/issue100_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue10_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue10_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue10_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue110_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue110_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue110_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue112_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue112_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue112_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue114_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue114_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue114_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue115_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue115_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue115_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue116_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue116_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue116_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue117_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue117_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue117_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue118_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue118_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue118_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue121_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue121_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue121_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue12_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue12_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue12_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue136_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue136_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue136_status.md +0 -0
- {cellpycore-0.2.4/.issueflows/01-current-issues → cellpycore-0.2.6/.issueflows/03-solved-issues}/issue138_original.md +0 -0
- {cellpycore-0.2.4/.issueflows/01-current-issues → cellpycore-0.2.6/.issueflows/03-solved-issues}/issue138_plan.md +0 -0
- {cellpycore-0.2.4/.issueflows/01-current-issues → cellpycore-0.2.6/.issueflows/03-solved-issues}/issue138_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue139_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue139_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue139_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue13_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue13_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue13_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue21_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue21_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue21_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue22_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue22_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue22_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue23_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue23_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue23_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue24_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue24_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue29_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue29_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue29_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue30_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue30_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue30_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue32_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue32_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue32_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue34_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue34_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue36_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue36_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue39_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue39_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue39_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue40_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue40_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue40_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue41_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue41_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue41_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue42_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue42_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue42_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue43_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue43_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue43_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue44_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue44_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue45_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue45_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue45_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue50_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue50_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue50_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue54_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue54_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue54_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue55_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue55_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue55_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue56_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue56_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue56_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue62_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue62_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue62_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue64_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue64_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue64_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue66_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue66_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue66_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue67_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue67_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue67_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue68_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue68_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue68_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue69_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue69_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue69_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue70_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue70_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue70_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue72_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue72_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue77_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue77_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue77_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue82_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue82_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue84_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue84_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue84_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue86_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue86_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue86_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue91_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue91_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue91_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue95_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue95_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue95_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue96_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue96_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue96_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue97_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue97_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue97_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue98_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue98_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue98_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue99_original.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue99_plan.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/03-solved-issues/issue99_status.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/04-designs-and-guides/.gitkeep +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/04-designs-and-guides/bdf-io-placement.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/04-designs-and-guides/cellpy-core-integration-into-cellpy.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/04-designs-and-guides/cellpy-core-migration.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/04-designs-and-guides/code-review-2026-07.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/04-designs-and-guides/column-headers-review.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/04-designs-and-guides/legacy-bridge-test-id.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/04-designs-and-guides/legacy-raw-energy-mapping.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/04-designs-and-guides/metadata-scaffolding.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/04-designs-and-guides/nom-cap-naming.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/04-designs-and-guides/rawcols-dtype-map.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/04-designs-and-guides/release-procedure.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/04-designs-and-guides/selector-dead-code-deferral.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/04-designs-and-guides/step-c-rate-split.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/04-designs-and-guides/step-table-polars-migration.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/04-designs-and-guides/summary-extractors.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/04-designs-and-guides/test-data-and-fixtures.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/04-designs-and-guides/test-metadata-and-merging.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/04-designs-and-guides/this-project.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/04-designs-and-guides/zensical-docs.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/05-epics/.gitkeep +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.issueflows/config.toml +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.pre-commit-config.yaml +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.python-version +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/.readthedocs.yaml +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/AGENTS.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/LICENSE +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/README.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/ROADMAP.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/SCRATCHPAD.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/graphify-out/.graphify_labels.json +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/graphify-out/.graphify_root +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/graphify-out/GRAPH_REPORT.md +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/graphify-out/graph.html +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/graphify-out/graph.json +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/graphify-out/manifest.json +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/__init__.py +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/config.py +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/curves.py +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/exceptions.py +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/extractors.py +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/legacy/__init__.py +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/legacy/headers.py +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/legacy/limits.py +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/legacy/mapping.py +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/legacy/meta.py +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/legacy/meta_mapping.py +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/legacy/mock_core.py +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/legacy/selectors.py +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/metadata/__init__.py +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/metadata/io.py +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/metadata/models.py +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/py.typed +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/settings_base.py +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/testing/__init__.py +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/testing/mock_data.py +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/timestamps.py +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/units/__init__.py +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/units/converters.py +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/src/cellpycore/units/spec.py +0 -0
- {cellpycore-0.2.4 → cellpycore-0.2.6}/zensical.toml +0 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Issue #142: Harden cycle_mode unwrapping in OldCellpyCellCore / _cycle_mode_to_test_mode
|
|
2
|
+
|
|
3
|
+
Source: https://github.com/cellpy/cellpy-core/issues/142
|
|
4
|
+
|
|
5
|
+
## Original issue text
|
|
6
|
+
|
|
7
|
+
## Context
|
|
8
|
+
|
|
9
|
+
Found while working **jepegit/cellpy#668** (v1.x batch notebook): after a custom `update_cell` → `make_step_table()` → `make_summary()`, the legacy bridge crashes with:
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
AttributeError: 'list' object has no attribute 'strip'
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
in `cellpycore.cell_core._cycle_mode_to_test_mode` when `OldCellpyCellCore.cycle_mode` is still list-shaped (often double-nested from cellpy-file meta, e.g. `[['anode']]`).
|
|
16
|
+
|
|
17
|
+
### Why this is a core issue (not just v1.x)
|
|
18
|
+
|
|
19
|
+
- `cellpy` **master** already mitigates on the **consumer load path** via recursive `test_meta._unwrap` after `meta_test_dependent.update(as_list=True, …)` (and has unit tests).
|
|
20
|
+
- The **engine/bridge** still assumes a scalar string:
|
|
21
|
+
- `OldCellpyCellCore.cycle_mode` getter only does one-level `m[0]`
|
|
22
|
+
- setter **keeps** list values (`[x.lower() for x in cycle_mode]`) instead of storing a scalar
|
|
23
|
+
- `_cycle_mode_to_test_mode` calls `cycle_mode.strip()` with no list/tuple handling
|
|
24
|
+
|
|
25
|
+
Any path that skips consumer unwrap (legacy loads, in-memory meta mutation, older cellpy pins) can still hit this. v1.x (#668) will add a consumer-side unwrap backport; core should still be defensive.
|
|
26
|
+
|
|
27
|
+
## What to do
|
|
28
|
+
|
|
29
|
+
1. **Getter** (`OldCellpyCellCore.cycle_mode`): recursively unwrap 1-element `list`/`tuple` to a scalar (same semantics as cellpy `test_meta._unwrap`).
|
|
30
|
+
2. **Setter**: unwrap first, then store a **scalar** string (or `None`) — do not persist a list of lowered strings.
|
|
31
|
+
3. **`_cycle_mode_to_test_mode`**: if given a list/tuple, unwrap before `.strip()`; keep existing string / `None` / unknown-spelling behaviour.
|
|
32
|
+
4. **Tests** covering at least:
|
|
33
|
+
- `'anode'` / `'full_cell'`
|
|
34
|
+
- `['anode']`
|
|
35
|
+
- `[['anode']]`
|
|
36
|
+
- `None`
|
|
37
|
+
- make_summary / make_core_summary does not raise on nested list meta
|
|
38
|
+
|
|
39
|
+
## Acceptance
|
|
40
|
+
|
|
41
|
+
- Nested list `cycle_mode` no longer crashes summarization through the legacy bridge.
|
|
42
|
+
- Existing CE / inverted-convention tests (issue #129 era) stay green.
|
|
43
|
+
- No API break for callers that already pass a plain string.
|
|
44
|
+
|
|
45
|
+
## Links
|
|
46
|
+
|
|
47
|
+
- Downstream report: https://github.com/jepegit/cellpy/issues/668
|
|
48
|
+
- Related consumer mitigation on master: unwrap in `cellpy.readers.cellpy_file.read` / `test_meta._unwrap`
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Issue #142 — plan: harden `cycle_mode` unwrapping
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
|
|
5
|
+
Stop nested list-shaped `cycle_mode` (e.g. `[['anode']]`) from crashing
|
|
6
|
+
`_cycle_mode_to_test_mode` / summarization on the legacy bridge; store and
|
|
7
|
+
expose a scalar string (or `None`) from the `cycle_mode` property.
|
|
8
|
+
|
|
9
|
+
## Constraints
|
|
10
|
+
|
|
11
|
+
- Back-compat: plain string callers unchanged; issue #127 spelling tables and
|
|
12
|
+
issue #129 bridge CE polarity tests stay green.
|
|
13
|
+
- KISS: no new package/module; private helper next to existing translator in
|
|
14
|
+
`cell_core.py`. No numpy dependency (cellpy’s `_unwrap` also peels numpy
|
|
15
|
+
scalars / NaN — out of scope here; meta on the bridge is Python
|
|
16
|
+
`list`/`tuple`/`str`/`None`).
|
|
17
|
+
- Metadata boundary unchanged: still optional; only normalize this one field
|
|
18
|
+
at the property / translator edge.
|
|
19
|
+
- Scope: getter, setter, `_cycle_mode_to_test_mode` (+ tests). No cellpy
|
|
20
|
+
consumer changes (jepegit/cellpy#668 stays separate).
|
|
21
|
+
|
|
22
|
+
### Prior art
|
|
23
|
+
|
|
24
|
+
- `cellpy.readers.test_meta._unwrap` — recursive peel of 1-element
|
|
25
|
+
`list`/`tuple`; multi-element left as-is. **Mirror** that rule in core
|
|
26
|
+
(list/tuple only).
|
|
27
|
+
- `_cycle_mode_to_test_mode` + `#127` tests in `tests/test_schema.py` —
|
|
28
|
+
spelling / warning contract; **extend**, don’t rewrite.
|
|
29
|
+
- `CellpyCellCore.cycle_mode` getter already does one-level `m[0]`; setter
|
|
30
|
+
wrongly keeps a lowered **list**. `OldCellpyCellCore` inherits this
|
|
31
|
+
property (no override).
|
|
32
|
+
- `test_bridge_summary_respects_cycle_mode` (`tests/test_golden.py`) — CE
|
|
33
|
+
polarity regression for string `"anode"`; keep green; add a nested-list
|
|
34
|
+
smoke if cheap.
|
|
35
|
+
- Toolbox: empty (nothing reusable). Graph: `cycle_mode` /
|
|
36
|
+
`_cycle_mode_to_test_mode` / `OldCellpyCellCore` communities confirm the
|
|
37
|
+
change set is `cell_core.py` + `test_schema.py`.
|
|
38
|
+
|
|
39
|
+
## Approach
|
|
40
|
+
|
|
41
|
+
1. Add `_unwrap_meta_scalar(value)` in `cell_core.py` (module-private):
|
|
42
|
+
while `list`/`tuple` and `len == 1`, recurse; else return value.
|
|
43
|
+
2. **Getter:** unwrap `meta_test_dependent.cycle_mode`; if still
|
|
44
|
+
`list`/`tuple`, take `[0]` when non-empty else `None` (preserves today’s
|
|
45
|
+
first-element behaviour for multi-element placeholders).
|
|
46
|
+
3. **Setter:** unwrap first; if still sequence, take first or `None`; then
|
|
47
|
+
store **scalar** `str.lower()` or `None` on both meta and `_cycle_mode`
|
|
48
|
+
(never a list of lowered strings). Handle `None` without calling `.lower()`.
|
|
49
|
+
4. **`_cycle_mode_to_test_mode`:** unwrap (+ first-element if still sequence)
|
|
50
|
+
before `.strip()`; keep existing `None` / empty / known / unknown+warn
|
|
51
|
+
behaviour. Type hint can widen to `Optional[str | list | tuple]` or stay
|
|
52
|
+
loose — behaviour matters more than the annotation.
|
|
53
|
+
5. No public API export of the helper.
|
|
54
|
+
|
|
55
|
+
Multi-element lists (`['anode','cathode']`) are not a real cellpy-file shape
|
|
56
|
+
today; taking `[0]` matches the old getter and avoids a new failure mode.
|
|
57
|
+
|
|
58
|
+
## Files to touch
|
|
59
|
+
|
|
60
|
+
| Path | Change |
|
|
61
|
+
|------|--------|
|
|
62
|
+
| [`src/cellpycore/cell_core.py`](../../src/cellpycore/cell_core.py) | `_unwrap_meta_scalar`; harden getter / setter / `_cycle_mode_to_test_mode` |
|
|
63
|
+
| [`tests/test_schema.py`](../../tests/test_schema.py) | Parametrize unwrap cases next to `#127` block; nested-list → INVERTED; setter stores scalar; optional `make_core_summary` / `make_summary` smoke with nested meta |
|
|
64
|
+
|
|
65
|
+
## Test strategy
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
uv run pytest tests/test_schema.py -k cycle_mode
|
|
69
|
+
uv run pytest # full suite before close
|
|
70
|
+
uv run ruff check && uv run ruff format --check
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
New coverage (minimum from issue):
|
|
74
|
+
|
|
75
|
+
- `_cycle_mode_to_test_mode`: `'anode'`, `'full_cell'`, `['anode']`,
|
|
76
|
+
`[['anode']]`, `None` (and keep existing spelling params green).
|
|
77
|
+
- Getter/setter: set `[['anode']]` or assign list → property returns
|
|
78
|
+
`"anode"`; stored meta is a `str`, not a list.
|
|
79
|
+
- Smoke: `OldCellpyCellCore` (or `CellpyCellCore`) with nested list on
|
|
80
|
+
`meta_test_dependent.cycle_mode` → `make_core_summary` / `make_summary`
|
|
81
|
+
does not raise.
|
|
82
|
+
|
|
83
|
+
## Open questions
|
|
84
|
+
|
|
85
|
+
None blocking — defaults above match the issue + cellpy `_unwrap`. Say if
|
|
86
|
+
you want multi-element lists to warn instead of silently taking `[0]`.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Issue #142 — status
|
|
2
|
+
|
|
3
|
+
- [x] Done
|
|
4
|
+
|
|
5
|
+
## What's done
|
|
6
|
+
|
|
7
|
+
- Plan confirmed (`issue142_plan.md`).
|
|
8
|
+
- Added `_unwrap_meta_scalar` / `_as_cycle_mode_scalar` in `cell_core.py`.
|
|
9
|
+
- Hardened `CellpyCellCore.cycle_mode` getter/setter to store/return scalar
|
|
10
|
+
(or `None`); nested lists no longer persist as lowered lists.
|
|
11
|
+
- `_cycle_mode_to_test_mode` unwraps list/tuple before `.strip()`.
|
|
12
|
+
- Tests in `tests/test_schema.py` (issue #142 block): translator shapes,
|
|
13
|
+
setter scalar store, getter unwrap, `OldCellpyCellCore.make_core_summary`
|
|
14
|
+
smoke with `[['anode']]` meta.
|
|
15
|
+
- Full suite: 281 passed; ruff green.
|
|
16
|
+
- `HISTORY.md` Unreleased bullet added.
|
|
17
|
+
|
|
18
|
+
## Remaining work
|
|
19
|
+
|
|
20
|
+
- None (close / PR).
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Issue #147: update_core_data: empty new_raw with refresh_derived duplicates c-rate columns
|
|
2
|
+
|
|
3
|
+
Source: https://github.com/cellpy/cellpy-core/issues/147
|
|
4
|
+
|
|
5
|
+
## Original issue text
|
|
6
|
+
|
|
7
|
+
Found by the cellpy L6 golden-equality oracle (jepegit/cellpy#778).
|
|
8
|
+
|
|
9
|
+
`CellpyCellCore.update_core_data(data, new_raw=<empty frame>)` short-circuits inside `merge.update_data` (returns `_copy_data(data)`), but `refresh_derived=True` (default) then runs `summarizers.c_rates_to_summary` on a summary that already carries `charge_c_rate` / `discharge_c_rate`. The join adds `charge_c_rate_right` / `discharge_c_rate_right`.
|
|
10
|
+
|
|
11
|
+
Expected: an empty `new_raw` is a no-op (frames identical to the input).
|
|
12
|
+
|
|
13
|
+
Repro (cellpy 2.1.4 / cellpycore 0.2.5): `tests/test_incremental_update.py::test_empty_tail_is_noop` in jepegit/cellpy (strict xfail until fixed).
|
|
14
|
+
|
|
15
|
+
Suggested fix: skip the `refresh_derived` block when `new_raw` is empty, or make `c_rates_to_summary` drop existing c-rate columns before joining (idempotent).
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Issue #147 — plan
|
|
2
|
+
|
|
3
|
+
Source: https://github.com/cellpy/cellpy-core/issues/147
|
|
4
|
+
|
|
5
|
+
## Goal
|
|
6
|
+
|
|
7
|
+
`CellpyCellCore.update_core_data(data, new_raw=<empty>)` must be a true no-op:
|
|
8
|
+
returned frames identical to the input (no `charge_c_rate_right` /
|
|
9
|
+
`discharge_c_rate_right` / `ir_*_right` columns).
|
|
10
|
+
|
|
11
|
+
## Constraints
|
|
12
|
+
|
|
13
|
+
- Polars-native engine; accept pandas frames for convenience (existing pattern).
|
|
14
|
+
- Input `Data` must not be mutated (`update_data` contract; keep the `_copy_data` return).
|
|
15
|
+
- Non-empty `new_raw` path unchanged (oracle tests in `tests/test_merge.py` stay green).
|
|
16
|
+
- Google-style docstrings; `ruff check` + `ruff format --check` clean.
|
|
17
|
+
- Downstream: cellpy `tests/test_incremental_update.py::test_empty_tail_is_noop` is
|
|
18
|
+
`xfail(strict=True)` against this issue. Once cellpy bumps its `cellpycore` pin to a
|
|
19
|
+
release containing this fix, that xfail marker must be removed (cellpy follow-up, out
|
|
20
|
+
of scope here — note in PR body).
|
|
21
|
+
|
|
22
|
+
### Prior art
|
|
23
|
+
|
|
24
|
+
- `merge.update_data` (`src/cellpycore/merge.py:221`): already short-circuits on
|
|
25
|
+
`new_raw is None or _frame_is_empty(new_raw)` → `_copy_data(data)`. The bug is that
|
|
26
|
+
`update_core_data` does not honour that short-circuit before `refresh_derived`.
|
|
27
|
+
- `merge._frame_is_empty` (`merge.py:389`): polars/pandas-agnostic emptiness check —
|
|
28
|
+
reuse it in `cell_core.py` instead of writing a new one.
|
|
29
|
+
- `summarizers.c_rates_to_summary` (`summarizers.py:1172`) and
|
|
30
|
+
`summarizers.ir_to_summary` (`summarizers.py:1274`): both do a bare
|
|
31
|
+
`summary.join(..., how="left")` and are therefore **not idempotent** — calling either
|
|
32
|
+
twice on the same summary yields `*_right` columns. `ir_to_summary` has the identical
|
|
33
|
+
latent defect (only masked because the issue repro has no IR column in raw).
|
|
34
|
+
- `tests/test_merge.py::test_update_core_data_refresh_derived` (line 336): existing
|
|
35
|
+
test for the derived-refresh path; new tests go beside it, reusing `_single_test_raw`,
|
|
36
|
+
`_process_raw`, `_schema` helpers.
|
|
37
|
+
- Toolbox (`.issueflows/00-tools/`) empty; graphify report not needed (three
|
|
38
|
+
known call sites, all located by grep).
|
|
39
|
+
|
|
40
|
+
## Approach
|
|
41
|
+
|
|
42
|
+
Two small changes — a direct no-op fix plus idempotency hardening of the two
|
|
43
|
+
summarizers so the same class of bug cannot recur from another caller.
|
|
44
|
+
|
|
45
|
+
1. **`update_core_data`: return early on empty `new_raw`.**
|
|
46
|
+
After the pandas→polars coercion, if `_frame_is_empty(new_raw)` (or `new_raw is None`),
|
|
47
|
+
return `update_data(...)`'s result directly (it already returns `_copy_data(data)`)
|
|
48
|
+
and skip the whole `refresh_derived` block. Cheapest, and matches the documented
|
|
49
|
+
"empty tail is a no-op" expectation. Docstring: add one sentence stating that an
|
|
50
|
+
empty `new_raw` returns an unmodified copy and skips derived refresh.
|
|
51
|
+
|
|
52
|
+
2. **Make `c_rates_to_summary` and `ir_to_summary` idempotent.**
|
|
53
|
+
Before the join, drop the target columns if already present:
|
|
54
|
+
`summary = summary.drop([c for c in (charge_c_rate, discharge_c_rate) if c in summary.columns])`
|
|
55
|
+
(same for `ir_charge` / `ir_discharge`). Re-running then overwrites instead of
|
|
56
|
+
producing `*_right`. This is the "either" alternative from the issue; doing both
|
|
57
|
+
keeps the no-op guarantee cheap (1) and removes the footgun for any other caller (2).
|
|
58
|
+
|
|
59
|
+
Order: 1 → 2 → tests → ruff.
|
|
60
|
+
|
|
61
|
+
## Files to touch
|
|
62
|
+
|
|
63
|
+
- `src/cellpycore/cell_core.py` — `update_core_data`: early return on empty `new_raw`
|
|
64
|
+
(import `_frame_is_empty` alongside `update_data` from `cellpycore.merge`); docstring note.
|
|
65
|
+
- `src/cellpycore/summarizers.py` — `c_rates_to_summary`, `ir_to_summary`: drop
|
|
66
|
+
pre-existing target columns before the join; one docstring line each ("idempotent:
|
|
67
|
+
existing columns are replaced").
|
|
68
|
+
- `tests/test_merge.py` — new tests (see below).
|
|
69
|
+
- `CHANGELOG.md` (if present — check at close) — fix entry.
|
|
70
|
+
|
|
71
|
+
## Test strategy
|
|
72
|
+
|
|
73
|
+
Run: `uv run pytest` then `uv run ruff check && uv run ruff format --check`.
|
|
74
|
+
|
|
75
|
+
New tests in `tests/test_merge.py`:
|
|
76
|
+
|
|
77
|
+
- `test_update_core_data_empty_new_raw_is_noop` — build `base` via `_process_raw`, run
|
|
78
|
+
`cell.update_core_data(base, extension.clear())` (polars empty frame with same
|
|
79
|
+
schema) with default `refresh_derived=True`; assert `updated.summary.columns ==
|
|
80
|
+
base.summary.columns`, no column ends with `_right`, and `raw`/`steps`/`summary`
|
|
81
|
+
`.equals()` the input. Also assert input `base` untouched.
|
|
82
|
+
- `test_update_core_data_empty_pandas_new_raw_is_noop` — same with
|
|
83
|
+
`extension.to_pandas().iloc[0:0]` (the cellpy repro shape).
|
|
84
|
+
- `test_c_rates_to_summary_idempotent` — call twice on processed data; columns
|
|
85
|
+
unchanged after second call, values equal.
|
|
86
|
+
- `test_ir_to_summary_idempotent` — same for IR (needs raw with
|
|
87
|
+
`internal_resistance` column; check `_single_test_raw` provides it, else add it).
|
|
88
|
+
|
|
89
|
+
Existing oracle tests (`test_update_overlap_matches_full_recompute_oracle`,
|
|
90
|
+
`test_update_gap_append_matches_full_recompute_oracle`,
|
|
91
|
+
`test_update_core_data_refresh_derived`, `tests/test_e2e.py`) guard the non-empty path.
|
|
92
|
+
|
|
93
|
+
## Open questions
|
|
94
|
+
|
|
95
|
+
- Scope of step 2 (idempotency hardening of both summarizers): include it, or ship only
|
|
96
|
+
the early return (step 1)? Recommendation: include — two-line change each, closes the
|
|
97
|
+
same defect in `ir_to_summary`, and the issue lists it as an acceptable fix.
|
|
98
|
+
- Version bump at close: `patch` (bug fix, no API change). Cellpy needs a new
|
|
99
|
+
`cellpycore` release to drop its xfail.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Issue #147 — status
|
|
2
|
+
|
|
3
|
+
- [x] Done
|
|
4
|
+
|
|
5
|
+
## What's done
|
|
6
|
+
|
|
7
|
+
- Plan accepted (2026-09-08): early return in `update_core_data` on empty `new_raw`
|
|
8
|
+
+ idempotent `c_rates_to_summary` / `ir_to_summary`.
|
|
9
|
+
- `cell_core.update_core_data`: returns the `update_data` copy directly when `new_raw`
|
|
10
|
+
is `None` or empty (skips `refresh_derived`); docstring updated.
|
|
11
|
+
- `summarizers.c_rates_to_summary` / `ir_to_summary`: drop pre-existing target columns
|
|
12
|
+
before the join via new `_drop_existing` helper → idempotent; docstrings updated.
|
|
13
|
+
- Tests (`tests/test_merge.py`): `test_update_core_data_empty_new_raw_is_noop`,
|
|
14
|
+
`test_update_core_data_empty_pandas_new_raw_is_noop`,
|
|
15
|
+
`test_c_rates_to_summary_idempotent`, `test_ir_to_summary_idempotent`.
|
|
16
|
+
Verified all 4 fail on `main` code, pass with fix.
|
|
17
|
+
- Full suite: 285 passed. `ruff check` + `ruff format --check` clean.
|
|
18
|
+
- `HISTORY.md` bullet under `[Unreleased]`. No version bump (0.2.5 already pending release).
|
|
19
|
+
|
|
20
|
+
## Remaining work
|
|
21
|
+
|
|
22
|
+
- None in this repo.
|
|
23
|
+
- Follow-up (cellpy repo, after `cellpycore` pin bump to a release with this fix): remove
|
|
24
|
+
strict `xfail` on `tests/test_incremental_update.py::test_empty_tail_is_noop`.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Issue #148: update_data: gap-append keeps the partial trailing step (step spanning the cut is split)
|
|
2
|
+
|
|
3
|
+
Source: https://github.com/cellpy/cellpy-core/issues/148
|
|
4
|
+
|
|
5
|
+
## Original issue text
|
|
6
|
+
|
|
7
|
+
Found by the cellpy L6 golden-equality oracle (jepegit/cellpy#778).
|
|
8
|
+
|
|
9
|
+
When `new_raw` starts strictly after the existing `datapoint_num` max (`gap_append=True`), `merge.update_data` keeps *all* existing step rows and rebuilds only from the first new datapoint. If the existing raw ends mid-step (the tester step continues in the new rows), that step ends up as two rows: the kept partial row and a new partial row. Downstream the per-cycle summary C-rate drifts (e.g. `discharge_c_rate` 248.6919 vs 248.68871 on `neware_uio.csv` cut at row 4000).
|
|
10
|
+
|
|
11
|
+
With any overlap (>= 1 already-seen row) `_trim_steps_for_overlap` rebuilds from the start of the spanning step and the result is identical to a full load.
|
|
12
|
+
|
|
13
|
+
Expected: gap-append should also trim the trailing step of `kept_steps` when the first new row continues the same (cycle, step) and rebuild from that step's `datapoint_num_first`; alternatively document that callers must re-read from the start of the last step.
|
|
14
|
+
|
|
15
|
+
Repro: `tests/test_incremental_update.py::test_gap_append_mid_step_equals_full_load` in jepegit/cellpy (strict xfail until fixed).
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Issue #148 — plan
|
|
2
|
+
|
|
3
|
+
Source: https://github.com/cellpy/cellpy-core/issues/148
|
|
4
|
+
|
|
5
|
+
## Goal
|
|
6
|
+
|
|
7
|
+
`merge.update_data` gap-append (`new_raw` starts strictly after existing
|
|
8
|
+
`datapoint_num` / `source_datapoint_num` max) must not split a tester step that
|
|
9
|
+
continues across the cut. Resulting steps + summary match a full
|
|
10
|
+
`make_step_table` / `make_summary` on the concatenated raw (same contract as
|
|
11
|
+
the overlap path).
|
|
12
|
+
|
|
13
|
+
## Constraints
|
|
14
|
+
|
|
15
|
+
- Polars-native; do not mutate the input `Data` (`_copy_data` / new frames).
|
|
16
|
+
- Overlap path (`r2_start <= r1_max`) stays unchanged — already trims via
|
|
17
|
+
`_trim_steps_for_overlap` and the existing oracle stays green.
|
|
18
|
+
- Gap-append that starts on a **new** (cycle, step) stays as today: keep every
|
|
19
|
+
existing step row, rebuild from the first new `datapoint_num`.
|
|
20
|
+
- Single-`test_id` only (`update_data` v1). Match `(cycle_num, step_num)` as
|
|
21
|
+
the issue states; do not invent `sub_step_num` matching (engine still
|
|
22
|
+
hardcodes sub-step `1`).
|
|
23
|
+
- Google-style docstrings; `ruff check` + `ruff format --check` clean.
|
|
24
|
+
- Downstream: cellpy `tests/test_incremental_update.py::test_gap_append_mid_step_equals_full_load`
|
|
25
|
+
is `xfail(strict=True)` against this issue. Dropping that marker is a cellpy
|
|
26
|
+
follow-up after the next `cellpycore` pin bump — note in PR body, out of
|
|
27
|
+
scope here.
|
|
28
|
+
|
|
29
|
+
### Prior art
|
|
30
|
+
|
|
31
|
+
- `merge.update_data` (`src/cellpycore/merge.py`): `gap_append = r2_start > r1_max`
|
|
32
|
+
keeps **all** `steps_pl` and sets `from_data_point` to `min(new datapoint_num)`.
|
|
33
|
+
That is the bug. Overlap branch already calls `_trim_steps_for_overlap`.
|
|
34
|
+
- `_trim_steps_for_overlap` (`merge.py`): finds the step whose
|
|
35
|
+
`[datapoint_num_first, datapoint_num_last]` contains the first overlapping
|
|
36
|
+
datapoint, drops that step and later ones, returns `from_data_point` = that
|
|
37
|
+
step's first. On a **gap**, the first new datapoint is *after* every existing
|
|
38
|
+
`datapoint_num_last`, so this helper currently keeps all steps — it cannot
|
|
39
|
+
detect continuation by range alone.
|
|
40
|
+
- `summarizers.make_step_table(..., from_data_point=)` (`summarizers.py`):
|
|
41
|
+
filters `datapoint_num >= from_data_point` then `group_by(test_id, cycle_num,
|
|
42
|
+
step_num, sub)`. Rebuilding from the spanning step's first datapoint
|
|
43
|
+
concatenates the kept partial raw + new rows into one step group. That is
|
|
44
|
+
why overlap works and why gap-append must use the same `from_data_point`.
|
|
45
|
+
- Issue #86 original algorithm: *"If r2(0) >= r1(last): find what step r2(0)
|
|
46
|
+
is in. That step and all the ones after will then belong to R2."* Gap-append
|
|
47
|
+
skipped that "find the step" part; this issue completes it.
|
|
48
|
+
- `tests/test_merge.py::test_update_gap_append_matches_full_recompute_oracle`:
|
|
49
|
+
cut is at `source_datapoint_num == 20` (`_single_test_raw` n_cycles=3) —
|
|
50
|
+
**step boundary** (start of cycle 3 step 1), so it does not catch this bug.
|
|
51
|
+
New tests go beside it; reuse `_single_test_raw`, `_process_raw`,
|
|
52
|
+
`_steps_oracle_equal`, `_summary_oracle_equal`.
|
|
53
|
+
- `step-c-rate-split.md`: `update_data` still appends `c_rate` to rebuilt rows
|
|
54
|
+
when kept steps carry it — keep that. Split steps are why downstream
|
|
55
|
+
`discharge_c_rate` drifts.
|
|
56
|
+
- Toolbox (`.issueflows/00-tools/`) empty. Graphify community 76 is the
|
|
57
|
+
`merge.py` helper cluster (`_trim_steps_for_overlap`, `update_data`); no
|
|
58
|
+
extra helper to reuse.
|
|
59
|
+
|
|
60
|
+
## Approach
|
|
61
|
+
|
|
62
|
+
Implement the issue's primary expected behaviour (trim), not the
|
|
63
|
+
"document that callers must re-read" alternative.
|
|
64
|
+
|
|
65
|
+
1. **Continuation trim on gap-append.** After detecting `gap_append`, still
|
|
66
|
+
keep **all** existing raw (`kept_raw = raw_pl` — new rows do not repeat the
|
|
67
|
+
partial step). Trim steps: if the first new row's `(cycle_num, step_num)`
|
|
68
|
+
equals the **last** existing step's `(cycle_num, step_num)`, drop that last
|
|
69
|
+
step and set `from_data_point` to its `datapoint_num_first`. Else keep all
|
|
70
|
+
steps and `from_data_point = min(new datapoint_num)` (current behaviour).
|
|
71
|
+
|
|
72
|
+
Implement as a **continuation fallback inside** `_trim_steps_for_overlap`
|
|
73
|
+
(when `overlap_idx is None`), then call that helper from the gap-append
|
|
74
|
+
branch with `new_pl` as the "incoming" frame. One trim function, two
|
|
75
|
+
callers. Do not add a second helper unless the fallback makes the overlap
|
|
76
|
+
docstring dishonest — if so, a tiny `_trim_steps_for_gap_append` next to it
|
|
77
|
+
is the fallback (same predicate).
|
|
78
|
+
|
|
79
|
+
Predicate (last step vs first incoming row, after sort by
|
|
80
|
+
`datapoint_num` / `datapoint_num_first`):
|
|
81
|
+
|
|
82
|
+
```text
|
|
83
|
+
last[shdr.cycle_num] == first_new[nhdr.cycle_num]
|
|
84
|
+
and last[shdr.step_num] == first_new[nhdr.step_num]
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
2. **Do not trim `kept_raw` on gap.** Overlap drops existing rows with
|
|
88
|
+
`partition >= r2_start` because `new_raw` re-sends them. Gap does not.
|
|
89
|
+
`make_step_table(from_data_point=spanning_first)` then sees kept partial
|
|
90
|
+
points **plus** new points and rebuilds one step row.
|
|
91
|
+
|
|
92
|
+
3. **Docs.** One sentence on `update_data` and on `_trim_steps_for_overlap`:
|
|
93
|
+
gap-append that continues the trailing `(cycle, step)` rebuilds that step
|
|
94
|
+
from `datapoint_num_first`, same as overlap.
|
|
95
|
+
|
|
96
|
+
Order: helper + `update_data` call site → tests → ruff → `HISTORY.md` at
|
|
97
|
+
close.
|
|
98
|
+
|
|
99
|
+
## Files to touch
|
|
100
|
+
|
|
101
|
+
- `src/cellpycore/merge.py` — continuation fallback in
|
|
102
|
+
`_trim_steps_for_overlap` (or sibling helper); gap-append branch calls it
|
|
103
|
+
instead of keeping all steps; docstring.
|
|
104
|
+
- `tests/test_merge.py` — new oracle test(s) (see below).
|
|
105
|
+
- `HISTORY.md` — `[Unreleased]` fix bullet at close.
|
|
106
|
+
|
|
107
|
+
No `cell_core.py` change unless a docstring cross-ref is useful;
|
|
108
|
+
`update_core_data` already forwards to `update_data`.
|
|
109
|
+
|
|
110
|
+
## Test strategy
|
|
111
|
+
|
|
112
|
+
Run: `uv run pytest` then `uv run ruff check && uv run ruff format --check`.
|
|
113
|
+
|
|
114
|
+
New tests in `tests/test_merge.py`, same helpers as the existing update
|
|
115
|
+
oracles:
|
|
116
|
+
|
|
117
|
+
- `test_update_gap_append_mid_step_matches_full_recompute_oracle` — the
|
|
118
|
+
issue. `_single_test_raw(..., n_cycles=2)`: cycle 2 step 1 is datapoints
|
|
119
|
+
10–14. `base_raw` = `source_datapoint_num <= 12`, `extension` =
|
|
120
|
+
`source_datapoint_num >= 13` (`r2_start > r1_max` → gap). Assert
|
|
121
|
+
`_steps_oracle_equal` + `_summary_oracle_equal` vs `_process_raw(full_raw)`.
|
|
122
|
+
Also `updated.steps.height == oracle.steps.height` (no extra split row).
|
|
123
|
+
- `test_update_core_data_gap_append_mid_step_c_rate_matches_full` — same cut
|
|
124
|
+
through `CellpyCellCore.update_core_data` (default `refresh_derived=True`);
|
|
125
|
+
`discharge_c_rate` / `charge_c_rate` match a fully processed oracle
|
|
126
|
+
(`pytest.approx`). Guards the cellpy L6 symptom.
|
|
127
|
+
|
|
128
|
+
Existing `test_update_gap_append_matches_full_recompute_oracle` (step-boundary
|
|
129
|
+
gap) and `test_update_overlap_matches_full_recompute_oracle` stay green.
|
|
130
|
+
Optional e2e mid-step cut on the Arbin fixture is **out of scope** (unit
|
|
131
|
+
oracle is enough; fixture may be absent).
|
|
132
|
+
|
|
133
|
+
## Open questions
|
|
134
|
+
|
|
135
|
+
- Trim vs document-only (issue lists both)? **Recommend trim** — overlap
|
|
136
|
+
already does this; #86's update algorithm already said "find what step
|
|
137
|
+
r2(0) is in". Document-only would leave core wrong and keep the cellpy
|
|
138
|
+
xfail forever.
|
|
139
|
+
- Extend `_trim_steps_for_overlap` vs a new `_trim_steps_for_gap_append`?
|
|
140
|
+
**Recommend extend** (continuation fallback when the first incoming
|
|
141
|
+
datapoint is past every `datapoint_num_last`). New helper if that muddies
|
|
142
|
+
the overlap-only name.
|
|
143
|
+
- Version bump at close: **patch** (behaviour bug, no API change). Cellpy
|
|
144
|
+
needs a new `cellpycore` release to drop its xfail.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Issue #148 — status
|
|
2
|
+
|
|
3
|
+
- [x] Done
|
|
4
|
+
|
|
5
|
+
## What's done
|
|
6
|
+
|
|
7
|
+
- Plan accepted (2026-09-08): trim trailing step on gap-append continuation;
|
|
8
|
+
rebuild from that step's `datapoint_num_first`.
|
|
9
|
+
- `_trim_steps_for_overlap`: continuation fallback when the first incoming
|
|
10
|
+
datapoint is past every existing step but `(cycle_num, step_num)` matches
|
|
11
|
+
the last kept step.
|
|
12
|
+
- `update_data` gap-append branch now calls `_trim_steps_for_overlap` on
|
|
13
|
+
`new_pl`; post-offset `from_data_point` still follows a non-continuation
|
|
14
|
+
gap.
|
|
15
|
+
- Tests: `test_update_gap_append_mid_step_matches_full_recompute_oracle`,
|
|
16
|
+
`test_update_core_data_gap_append_mid_step_c_rate_matches_full`.
|
|
17
|
+
- `uv run pytest`: 287 passed, 3 deselected. `ruff check` + `ruff format --check`
|
|
18
|
+
clean.
|
|
19
|
+
- Version bump `0.2.5` → `0.2.6`. `HISTORY.md` promoted (`#147`/`#148` under
|
|
20
|
+
`[0.2.6]`; `#142` backfilled under `[0.2.5]` to match tag `v0.2.5`).
|
|
21
|
+
|
|
22
|
+
## Remaining work
|
|
23
|
+
|
|
24
|
+
- None in this repo.
|
|
25
|
+
- Follow-up (cellpy repo, after `cellpycore` pin bump to a release with this
|
|
26
|
+
fix): remove strict `xfail` on
|
|
27
|
+
`tests/test_incremental_update.py::test_gap_append_mid_step_equals_full_load`.
|
|
@@ -46,7 +46,7 @@ Reconciled against the actual repo state on **2026-06-26**. Status legend: ✅ d
|
|
|
46
46
|
| STEP-09 Harmonize headers | ✅ done | `config.Cols` + spec tests; `legacy/mapping.py` gives lossless/total `config.Cols` ↔ legacy `Headers*` round-trip (`tests/test_header_mapping.py`) (#34/#35) |
|
|
47
47
|
| STEP-10 Metadata scaffolding | ✅ done | `cellpycore.metadata` (`models.py`/`io.py`); `TestMeta`/`CellMeta`/`TestMetaCollection` + (de)serialize/merge; graceful-degradation guard (`tests/test_metadata.py`) (#37) |
|
|
48
48
|
| STEP-11 Timestamp representation | ✅ done | `epoch_time_utc` + `first/last_epoch_time_utc` are int64-ns UTC; `cellpycore.timestamps` conversion helpers + fixture regenerated (`tests/test_timestamps.py`) (#32, PR #38) |
|
|
49
|
-
| STEP-12 Unit-handling boundary |
|
|
49
|
+
| STEP-12 Unit-handling boundary | ✅ done | `CellpyUnits` schema in `units/spec.py` (#40/#112) + `units.py` tooling behind the optional `units` extra; factors cross the seam by value; `cellpy` now delegates `get_converter_to_specific` / `nominal_capacity_as_absolute` to `cellpycore.units` (jepegit/cellpy #451) — the duplicate converters are retired |
|
|
50
50
|
|
|
51
51
|
Per-step `Status:` lines below repeat this for context; this table is the quick reference.
|
|
52
52
|
The forward work beyond these twelve steps (STEP-13+) is enumerated in
|
|
@@ -266,12 +266,15 @@ Adopt the internal int64-ns timestamp representation.
|
|
|
266
266
|
|
|
267
267
|
## STEP-12 Unit-handling boundary (scaffolding/tooling in core; population & policy upstream)
|
|
268
268
|
|
|
269
|
-
**Status:**
|
|
269
|
+
**Status:** ✅ done — the `CellpyUnits` schema lives in `cellpycore.units.spec`
|
|
270
270
|
(#40, #112) and the pint-based conversion tooling (`cellpycore.units`:
|
|
271
271
|
`get_converter_to_specific`, `nominal_capacity_as_absolute`, `Q`, output-unit defaults)
|
|
272
|
-
|
|
273
|
-
bridge, and conversion factors
|
|
274
|
-
|
|
272
|
+
exists behind the optional `units` extra, attached to the `OldCellpyCellCore`
|
|
273
|
+
bridge, and conversion factors cross the seam **by value**. The final cellpy-side move
|
|
274
|
+
has landed: `CellpyCell.get_converter_to_specific` / `nominal_capacity_as_absolute`
|
|
275
|
+
(and `convert_value` / `calculate_scaler`) now delegate to `cellpycore.units`
|
|
276
|
+
(jepegit/cellpy #451, unit plan Phase 2), guarded by converter-parity fixtures on both
|
|
277
|
+
sides — the duplicated converters are retired.
|
|
275
278
|
|
|
276
279
|
**Codebase:** `cellpy-core` (scaffolding/tooling — `legacy.py` + `units.py`); population
|
|
277
280
|
(`raw_units` from loaders) and the decision to delegate are `cellpy`'s opt-in.
|
|
@@ -299,8 +302,9 @@ already did for headers and the step engine).
|
|
|
299
302
|
|
|
300
303
|
## Remaining work (STEP-13+) — finalized 2026-06-28 (issue #39)
|
|
301
304
|
|
|
302
|
-
The original twelve steps are complete except for the
|
|
303
|
-
|
|
305
|
+
The original twelve steps are complete except for the one intentionally-continuous
|
|
306
|
+
one (STEP-06 golden fixtures); STEP-12 (unit boundary) closed once the cellpy-side
|
|
307
|
+
converter delegation landed (jepegit/cellpy #451). Going through the
|
|
304
308
|
roadmap and the companion design docs surfaced the remaining work below. Each item is now
|
|
305
309
|
tracked as its own **cellpy-core** GitHub issue (the cellpy-side delegation work stays on
|
|
306
310
|
jepegit/cellpy). Captured under issue #39.
|
|
@@ -339,12 +343,12 @@ flowchart TD
|
|
|
339
343
|
S08 --> S09["STEP-09 Harmonize headers ✅"]
|
|
340
344
|
S08 --> S10["STEP-10 Metadata scaffolding ✅"]
|
|
341
345
|
S08 --> S11["STEP-11 Timestamp representation ✅"]
|
|
342
|
-
S03 --> S12["STEP-12 Unit-handling boundary
|
|
346
|
+
S03 --> S12["STEP-12 Unit-handling boundary ✅"]
|
|
343
347
|
S07["STEP-07 Build-backend swap ✅"] -.independent.-> S08
|
|
344
348
|
|
|
345
349
|
classDef done fill:#d4edda,stroke:#28a745,color:#155724;
|
|
346
350
|
classDef partly fill:#fff3cd,stroke:#ffc107,color:#856404;
|
|
347
351
|
classDef todo fill:#f8d7da,stroke:#dc3545,color:#721c24;
|
|
348
|
-
class S01,S02,S03,S04,S05,S07,S08,S09,S10,S11 done;
|
|
349
|
-
class S06
|
|
352
|
+
class S01,S02,S03,S04,S05,S07,S08,S09,S10,S11,S12 done;
|
|
353
|
+
class S06 partly;
|
|
350
354
|
```
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"python.testing.pytestArgs": [
|
|
3
|
+
"tests"
|
|
4
|
+
],
|
|
5
|
+
"python.testing.unittestEnabled": false,
|
|
6
|
+
"python.testing.pytestEnabled": true,
|
|
7
|
+
"python-envs.pythonProjects": [
|
|
8
|
+
{
|
|
9
|
+
"path": ".",
|
|
10
|
+
"envManager": "ms-python.python:venv",
|
|
11
|
+
"packageManager": "ms-python.python:pip"
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
@@ -4,6 +4,19 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.2.6] - 2026-09-08
|
|
8
|
+
|
|
9
|
+
- `update_core_data` treats an empty `new_raw` as a no-op (skips the derived refresh
|
|
10
|
+
instead of re-joining `*_c_rate` / `ir_*` columns as `*_right` duplicates);
|
|
11
|
+
`c_rates_to_summary` and `ir_to_summary` are now idempotent. (#147)
|
|
12
|
+
- `update_data` gap-append that continues the trailing `(cycle, step)` now
|
|
13
|
+
rebuilds that step from `datapoint_num_first` instead of splitting it into
|
|
14
|
+
two partial rows (summary C-rate matches a full load). (#148)
|
|
15
|
+
|
|
16
|
+
## [0.2.5] - 2026-09-08
|
|
17
|
+
|
|
18
|
+
- Harden `cycle_mode` unwrapping in `OldCellpyCellCore` / `_cycle_mode_to_test_mode`. (#142)
|
|
19
|
+
|
|
7
20
|
## [0.2.4] - 2026-07-23
|
|
8
21
|
|
|
9
22
|
- Add Equivalent Full Cycles (EFC) utilities (#138). `summarizers.throughput_to_raw`
|