Repository navigation
Omit blank fields from the model, as both writers already do - #242
Merged
Merged
Conversation
A blank field of an object type with no repeating group was stored as "", numeric fields included, while write_idf and write_epjson drop it. Re-parsing idfkit's own IDF output therefore did not equal the original document. The parser now skips a blank field, as it already did inside repeating groups and as idfkit-js and ConvertInputFormat do, so it reads as None like a field cut off by an earlier semicolon. Closes #183 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LEegXpWqwRPaofngRx6L3h
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LEegXpWqwRPaofngRx6L3h
Collaborator
Author
|
Nothing else changed: the 5 outstanding exceptions (#186, #187) are the same ones This can't go green from this repo alone. As with #226 →
Moving to an existing later tag doesn't help: Generated by Claude Code |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LEegXpWqwRPaofngRx6L3h
… fields With a parsed blank field now absent from obj.data, assigning it its own value (obj.f = obj.f) stored None, bumped the mutation version and cleared the preserved source text, so a preserving write reformatted an object nobody edited. _set_field now treats None and "" as clearing the field, as assign_slot already does for an extensible slot, and a blank written over an unset field is no change. The parser's fixed-field loop zips the named fields so it no longer walks the extensible tail, and the changelog entry is scoped to fixed fields in every object type and written in the past tense. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LEegXpWqwRPaofngRx6L3h
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LEegXpWqwRPaofngRx6L3h
The level differs from conformance-2026.19 only by removing the two python round-trip entries that this change closes (#183, idfkit-conformance#47). idfkit.CONFORMANCE_LEVEL and the EPW sentinel table are regenerated from the new tag; only their recorded level changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LEegXpWqwRPaofngRx6L3h
samuelduchesne
pushed a commit
that referenced
this pull request
Oct 28, 2026
Brings in the conformance-2026.20 pin from #242. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JkhUjaZe78iCNB1nvAkuzN
Merged
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.
Closes #183
Problem
For an object type with no extensible group, the IDF parser stored every blank field as
""(numeric fields too).write_idfandwrite_epjsonboth drop those blanks, so re-parsing idfkit's own IDF output did not equal the original. For example,Zone, Z1, 0, 0, 0, 0, 1, 1, , , , , ;had 12 keys into_dict()before the write and 7 after.Change
IDFParser._build_data_dict_cachednow skips blank values instead of storing"", for the fixed fields of every object type. This matches what the extensible-group path already did after #182, and what idfkit-js does:packages/core/src/parse/idf.tsskips blank fields and drops trailing blank padding. The loop now zips the named fields, so it no longer walks the extensible tail.IDFObject._set_fieldnow treatsNoneand""as clearing a field, asassign_slotalready does for an extensible slot. Writing a blank over an unset field does nothing. Without this,obj.f = obj.fon a parsed blank field storedNone, bumped the mutation version and cleared the preserved source text. That madewrite_idf(preserve_formatting=True)reformat an object nobody had changed. Onmain, the stored""matched and the assignment did nothing.Effects:
Nonethrough attribute, item (obj["..."],obj[i]) andget()access. That is what a field cut off by an earlier semicolon has always returned. Understrict=True, an unset schema field still reads asNoneand never raises.fieldvaluesis built fromfield_orderwithdata.get, so a blank slot now givesNone, the same as a field never given. It used to give"".write_idfalready writes a missing field as an empty slot, so an interior blank keeps its position (Zone,Gap Zone,,0,0,0,,2;). When an edited object is written withpreserve_formatting=True, its blank commas are still kept, because of the existingkeep_at_leastrule.0(0,0.0,-0.0,0.0E+0) is still a value.The change is user-visible, since
""becameNone. So it comes with a CHANGELOG### Fixedentry and a new "Blank fields are unset" section in theparsing-idf-epjsonagent reference, with the bundle re-baked.Not changed here:
doc.add(..., field="")still stores"", because that path is indocument.py. A strict parse still refuses a non-extensible object with extra trailing blank fields, as before.Levels
[tool.idfkit.conformance] levelmoves fromconformance-2026.19(set by #236) toconformance-2026.20. That level differs from.19only in removing the two Python round-trip entries this PR closes (idfkit/idfkit-conformance#47).idfkit.CONFORMANCE_LEVELand the EPW sentinel table are regenerated from the tag; only their recorded level changes.Tests
tests/test_idf_roundtrip.py::TestBlankFieldsAreUnsetcovers:None, in strict mode and through eppyfieldvalueswrite_idf→ re-parse giving an equal model, with the same key orderwrite_epjsonequallingobj.dataNoneor""clearing a fieldmake checkpasses.make testhas one failure:test_weather_offline.py::test_a_read_only_cache_stops_the_nudge_without_the_env_var. It fails the same way on unmodifiedmainin this environment, because the container runs as root and achmod 0o500cache directory is still writable for root. It is unrelated to this change.Conformance
python3 runners/run.py --library ../idfkitat theconformance-2026.20tag: PASS, exit 0. 74 cases, 226 assertions: 218 passed, 5 failed, all 5 of them outstanding exceptions (#186, #187). No stale entries and no unexpected failures.🤖 Generated with Claude Code
https://claude.ai/code/session_01LEegXpWqwRPaofngRx6L3h