Repository navigation
Write item name, quantity and axis changes to an edited dfs file - #79
Draft
ryan-kipawa wants to merge 29 commits into
Draft
ryan-kipawa wants to merge 29 commits into
ryan-kipawa wants to merge 29 commits into
Conversation
They fail: setting Name, Quantity or the spatial axis on a file opened for editing is not written to the file (#38). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Assigning Name or Quantity on a dynamic item of a file opened for editing calls dfsUpdateItemInfo, and changing its SpatialAxis writes the axis, as the C# library does. Dfs123File.SpatialAxis is now a copy of the first item's axis; changes to it are written to all dynamic items and to static items with the same axis type when the file is flushed or closed. Closes #38 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Flush after changing SpatialAxis rewrites the static items and moves the file pointer, so the next appended time step overwrites the first one. A Name that cannot be encoded is kept in memory though not written. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Flush writes the axis to the dynamic items only, and Close rewrites the static items, so a time step written after Flush lands where expected. Close always releases the file. Name and Quantity keep their old value when writing them fails, and copying an axis writes it once. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After Close, setting Name, Quantity or an axis attribute still calls the native library with pointers into the freed header. A failing axis write keeps the new value in memory. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Close clears the item and axis callbacks, as the item pointers point into the destroyed header, and Flush on a closed file raises before writing. An axis attribute keeps its old value when writing it fails, as Name and Quantity do. The changelog says static items are written on Close only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On an editable file, setting Z0 on a 2D item axis raises AttributeError when the old value is looked up for a rollback. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The rollback of a failed axis write now handles an attribute that was not set before. The changelog no longer promises that Flush writes the axis: in Append mode the native flush does not write item axes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each axis-change test now checks the axis values OresundHD.dfs2 starts with before editing them, so a passing test shows the edit changed them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The fix applies to every dfs file type but only dfs2 was tested. Each test asserts the values the file starts with before editing them. There is no dfs1 file in testdata, so the dfs1 tests create one. The dfs3 axis test also checks that the static data of the encoded file is kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The edit tests were copies per file type, and the edge cases (name length, rejected values, Read mode, after Close, flush then append) ran on dfs2 only, although the code they test is shared by every dfs file type. tests/test_dfs_edit.py parametrizes them over dfs0, dfs1, dfs2, dfs3 and dfsu, and over Edit, Append and generic Edit. Each edit is made to every item in turn, and checked against invariants: the edited item has the new value and the others keep theirs, the file keeps its size, the raw bytes of the dynamic data at the end of the file are unchanged (the edit wrote only the header), and the data reads back unchanged. The written name is checked in the file's bytes, at the offset of the old name. The dfs2 tests ported from C# stay; the copies this replaces are removed. Fails for dfsu: DfsuFile.Flush passes an extra argument, and DfsuFileOpenAppend requires parameters. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DfsuFile.Flush passed itself to DfsFile.Flush, which takes no argument, so flushing a dfsu file raised TypeError. DfsuFileOpenAppend was the only factory Open method without a parameters default. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Static items inherit the Name, Quantity and axis setters, but their changes were not written: WriteStaticItemData wrote the old item info. As in the C# library, a static item changed in an editable file is written by WriteStaticItemData, and not without it. A static item read before Close must not write after it. A file made with DfsBuilder is open in Append mode, so item edits made before its data is written go to the file; the test pins that. Fails at the static item tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A static item read from an editable file gets the same update hooks as a dynamic item, so WriteStaticItemData writes its changes, as in the C# library. Close detaches every hooked item, dynamic or static, since their item pointers depend on the destroyed header. The file axis write on Close now goes through those hooks. Flush says why it leaves static items to Close, and the changelog names static items and files being built. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A name with a byte cp1252 leaves undefined (a UTF-8 name written by another tool, say) is read with U+FFFD, so writing a new Quantity re-encoded the name and raised UnicodeEncodeError. Also check, in the flush then append test, that a changed file axis reaches the static items in Append mode. Fails at the new test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The item keeps the name it read from the file and the bytes it read it from. While Name is unchanged, a Name or Quantity write sends those bytes, so a name with a byte cp1252 leaves undefined no longer stops a Quantity edit. The changelog notes that a dfs1/2/3 file's SpatialAxis is a copy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The changelog says changing the file axis no longer changes the first item's axis in a file opened to read, and in an editable file only on Flush or Close. Nothing tested that. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every static item read in Edit or Append mode was kept, with its data, until Close, so reading static items in a loop kept every copy alive. Fails at the new test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The file keeps the items it hooks in a WeakSet, so a static item read from an editable file is freed when the caller drops it, instead of at Close. The changelog says it is the attributes of SpatialAxis that are written. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
copy.copy and copy.deepcopy kept the write hook, which writes the item the copy was taken from. Changing the copy wrote the original's values, and after Close it called the native library with a pointer into the destroyed header (DFS error 1000). Fails at the new test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
copy.copy and copy.deepcopy go through __getstate__, which now leaves out the write hook, so a copy of an item or axis taken from an editable file is a plain object. Dfs123File no longer clears the hook of the file axis copy by hand. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The axis hook wrote whatever the item's axis was when it fired, and Close detached only the axis the item held then. After an item's SpatialAxis was replaced, changing the old axis wrote the new one's values, and after Close it called the native library with a pointer into the destroyed header (DFS error 1000). Fails at the new test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The axis hook is bound to the axis it was attached to and writes only while the item still holds that axis, as in the C# library, so assigning another axis to an item writes nothing through either. Close detaches every hooked axis, including one the item no longer holds. The changelog says dynamic items get a changed file axis on Flush as well as Close. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dfs123File wrote the file axis through each item's current SpatialAxis object. For an item whose axis was replaced by a copy, the change reached only the copy in memory, and for an axis of another type Flush and Close raised ValueError after writing some items. Fails at the new test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dfs123File writes a changed file axis to each dynamic item's axis as read from the file, so it reaches an item whose SpatialAxis object was replaced, whatever that object's type. The item's SpatialAxis is updated in memory when it is an axis of the same type. Flush says that a bad file axis value is rejected only on Flush or Close, as in the C# library. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The value is accepted when set, as in the C# library, so Flush and Close must reject it and still close the file, unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The changelog says it is the file axis's attributes that are written, the Flush docstring no longer credits C# for deferring a bad value, and the bad file axis test checks that the file is closed through Flush, not a field. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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 #38
What and why
Opening a dfs file for editing and assigning
ItemInfo[0].NameorItemInfo[0].Quantitychanged only the Python object; closing the file wrote nothing back, so the only way to fix a wrong eumItem/eumUnit was to rewrite the file or click through DataUtility. In the C# library these setters write the item info to the file, andDfs123Filewrites a changedSpatialAxisto all items on close; none of that had been ported. This PR ports both. The issue reported it on a dfs2 file, but the setters are inDfsFile, so the fix covers every case that reaches them: every dfs file type (dfs0, dfs1, dfs2, dfs3, dfsu), Edit and Append mode through the typed and the generic factory methods, dynamic items and static items (written byWriteStaticItemData, as in C#), and files being created withDfsBuilder(open in Append mode). As in C#, an axis writes only while it is its item's axis: assigning anotherSpatialAxisobject to an item writes nothing. The file axis is written byDfs123File, the base of dfs1, dfs2 and dfs3. As decided on the issue, it follows C#: assigning a newQuantitywrites it, but changingQuantity.Item/Quantity.Unitin place does not.Flushwrites a changed file axis to the dynamic items only, andClosealso rewrites the static items. C# rewrites static items onFlushtoo, but that moves the file pointer, so the next appended time step overwrote time step 0 (review round 1).DfsuFile.Flush()raisedTypeError(it passed itself toDfsFile.Flush), andDfsuFileOpenAppendwas the onlyOpenmethod that requiredparameters. Test in9518fd2, fix ince3e353.Commits
bdf4203Port the dfs2 item info and item axis modify tests: the two commented-out C# ports, now live; the item info one runs the issue's own example (ExamplesDfs2.ModifyDfs2ItemInfo). Fails on master.abc41a4Write item name, quantity and axis changes to an edited dfs file:Name/Quantitybecome properties with an_OnUpdatehook, axes get one through__setattr__, andDfs123Filewrites its axis onFlush/Close.2479afbTest appending after an axis flush, item axis edits and failing setters: fails atabc41a4.c601158Write a changed axis without moving the file pointer on Flush: the static-item rewrite moves toClose; setters roll back on failure;_Updatewrites once.e9f111aTest item edits after Close and a failing axis write: fails atc601158with DFS error 1000.21cded3Stop writing item changes after Close and roll back failed axis writes:Closeclears the callbacks, since the item pointers point into the freed header.e49e30aTest setting an axis attribute the axis type does not have.67236bbAllow setting an axis attribute the axis type does not have: rollback handles an unset attribute; changelog wording.a0e6049Assert initial axis values in dfs2 axis-change tests.a45d04cTest item and axis edits on dfs0, dfs1, dfs3 and dfsu files.0ba2079Mergeorigin/master: no conflicts; brings in the new ruff rules and the file name encoding change.9518fd2Test item and axis edits on every dfs file type and way of opening it: the newtests/test_dfs_edit.py, parametrized over file type and opener and checked against invariants (see Evidence). It replaces the per-type copies from commits 3, 5, 7 and 10; the two C# ports stay intest_dfs2.py. Fails only for dfsu, on the side finding.ce3e353Fix DfsuFile.Flush and let DfsuFileOpenAppend default its parameters.0c55a8eTest static item edits and item edits while a file is built: fails at the 16 static item cases.80137e7Write static item name, quantity and axis changes: static items get the same hooks,Closedetaches every hooked item, and the file axis write onClosegoes through the hooks.ed1d1f2Test a Quantity edit on an item whose name cp1252 cannot decode: fails at80137e7withUnicodeEncodeError; also checks the static items intest_flush_then_append.af51545Write back a name cp1252 cannot decode unchanged: the item keeps the name and bytes it read, and sends the bytes whileNameis unchanged.d278e70Test that a dfs1/2/3 file's SpatialAxis is a copy of the item axis: fails with thecopy.copyreverted.4daf251Test that a static item read from an editable file can be freed: fails atd278e70.b26c945Let the file drop static items it no longer needs to detach: the hooked items are kept in aweakref.WeakSet.930d056Test that a copy of an item or axis from an editable file writes nothing: fails atb26c945(DFS error 1000 afterClose).7d41b5fDetach a copy of an item or axis from the file:__getstate__leaves the hook out of a copy.1ac3f51Test that a replaced item axis writes nothing: fails at7d41b5f(DFS error 1000 afterClose).e404877Write an item axis only while it is the item's axis: the hook is bound to its axis and checksitem.SpatialAxis is axis;Closedetaches every hooked axis.bca52d0Test that a file axis change reaches an item whose axis was replaced: fails ate404877.06e9297Write the file axis to every item's axis in the file:Dfs123Filewrites to each item's axis as read from the file, not through the item's current object.eba1e3dTest that a bad file axis value is rejected on Flush and Close: passes; it pins thetry/finallyinClose(fails without it).b366af3,bedcd18Docstring and changelog wording, and a test check throughFlushinstead of a field.Code Review Guide
Glossary
_OnUpdate: a callback attribute an object calls after one of its values changes.DfsTemporalAxisalready uses it to write the time axis to the header.Closedestroys; a static item's points into its static vector, whichWriteStaticItemDatawrites.dfsUpdateItemInfo: the native call that changes an existing item's eumItem, name and eumUnit. UnlikedfsSetItemInfoit does not take a data type.WriteStaticItemData).testdata/OresundHD.dfs3.Where the change sits
The setters are the entry points. Every item read from an editable file, dynamic or static, gets its hooks in one place (
__AttachItemUpdate).Dfs123Fileroutes a file-level axis change through the same item-axis hooks and, onClose, through the existing static-item writer.Conventions followed
_OnUpdatecallback, attached by the file after readingDfsFile.py:203-215
DfsFile.py:620-629
DfsFile.py:804, 838-839
DfsFile.py:1581-1607
DfsDLL.InitDfsDLL.py:208-212
DfsDLL.py:213-220
tmp_path, as in the newest test moduletest_filename_encoding.py:29-34
test_dfs_edit.py
Deviations
__setattr__, not properties. Why: the 7 updatable attributes are spread over 9 axis classes as plain fields; one hook keeps them plain. Alternative: a property per attribute per class, likeDfsTemporalAxis.DfsFile.py:210-215
DfsFile.py:412-426
DfsFile.py:804
DfsFile.py:1585-1586
Dfs123File.Flushwrites the axis to dynamic items only; the C# library'sFlushalso rewrites the static items. Why: rewriting static items moves the file pointer, and an append afterFlushthen overwrote time step 0. Alternative: save and restore the pointer state around the rewrite.DfsFile.py
Flush(the base, unchanged)Dfs123File.py:61-74
Evidence
Claims:
ExamplesDfs2.ModifyDfs2ItemInfo) now writes the name and quantity:tests/test_dfs2.py::Dfs2Tests::test_ModifyLanduseItemInfoTest.Name,Quantity,SpatialAxis.AxisUnitorSpatialAxis.X0writes that value to that item only, on every dfs type, in Edit, Append and generic Edit mode, for each item of the file:tests/test_dfs_edit.py::test_edit_each_item(57 cases; dfs0 axes have noX0).test_edit_each_item,test_edit_each_static_item,test_name_keeps_its_length_in_the_fileandtest_file_axis_is_written_to_every_item; at scale by the spike below (20 GB file, < 0.1 s and ≤ 78 KB written per edit, against ≥ 20 s to rewrite it).test_name_keeps_its_length_in_the_file, which reads the bytes at the old name's offset in the file, for an empty, 1-character, shorter, same-length and longer name on every type.test_rejected_value_keeps_old_value(byte-identical file).Quantityedit on an item whose name has a byte cp1252 leaves undefined writes the name bytes back unchanged:test_quantity_edit_keeps_a_name_cp1252_cannot_decode(bytes at the name's offset).Close, nor an in-placeQuantity.Item/Unitchange:test_read_mode_writes_nothing,test_edit_after_close_writes_nothing,test_quantity_changed_in_place_is_not_written(byte-identical file each).WriteStaticItemDataand not without it, on every type with static items, for each static item:test_edit_each_static_item,test_static_item_edit_is_written_only_by_write_static_item_data.test_file_axis_is_written_to_every_item(dfs1, dfs2, dfs3).Flushlands at the end, on every type:test_flush_then_append.DfsBuilderare written:test_edit_while_building.SpatialAxisis a copy of the first item's axis: changing it reaches the items only onFlush/Close, and never in Read mode:test_file_axis_is_a_copy_of_the_item_axis.SpatialAxiswrites nothing through the old or the new object, before or afterClose:test_replaced_axis_writes_nothing. A copy of an item or axis writes nothing:test_copy_of_an_item_is_not_written.test_file_axis_reaches_an_item_whose_axis_was_replaced.FlushandClose, and the file is still closed, unchanged:test_bad_file_axis_value_is_rejected_on_flush_and_close.test_static_item_read_from_an_editable_file_is_freed.Each claim's test was checked to fail when the claim is false. With all work committed, the code was broken one way at a time and
tests/test_dfs_edit.pyrun, then restored withgit checkout HEAD -- <file>:test_read_mode_writes_nothing(5 types)test_name_keeps_its_length_in_the_file(20)test_rejected_value_keeps_old_value(5)test_rejected_value_keeps_old_value(5)Flushalso rewrites static itemstest_flush_then_append(dfs1, dfs2, dfs3)Closetest_file_axis_is_written_to_every_item(3),test_ModifyAxisTestClosekeeps item callbacks / doesn't detach an itemtest_edit_after_close_writes_nothing(5, DFS error 1000)AxisUnitnot an updatable attributetest_edit_each_item(15),test_rejected_value_keeps_old_value(5)test_file_axis_is_a_copy_of_the_item_axis(6)test_replaced_axis_writes_nothing(5)Closedoesn't detach a hooked axistest_edit_after_close_writes_nothing(5)try/finallyinDfs123File.Closetest_bad_file_axis_value_is_rejected_on_flush_and_close(3)Before: the new and ported tests, run with master's
mikecore/(check outorigin/master -- mikecore/first):uv run pytest -q tests/test_dfs_edit.py tests/test_dfs2.py -k "test_dfs_edit or Modify" -rAThe 63 that pass on master are the "writes nothing" guards (Read mode, after
Close, in-place quantity, copies, a replaced axis, an attribute the axis lacks, a static item withoutWriteStaticItemData, a freed static item) and two unrelated dfs2 data tests. Master never writes item info, so they guard against this PR writing too much, which the table above shows they catch.After (
bedcd18):uv run pytest -q tests/test_dfs_edit.py tests/test_dfs2.py -k "test_dfs_edit or Modify"Full checks at
bedcd18:uv run pytest394 passed, 5 skipped, 8 xfailed;uvx pre-commit run --all-filesall Passed;uv run pyrefly check0 errors, 328 warnings (the same as master; the CI cap is 330).Spike: edits rewrite only the header, not the file
The issue's files are over 100 GB, so an edit must not rewrite the data. At
bedcd18, a dfs2 file of 20 GB (2500 time steps, 2 items of 1000×1000 floats, a 4 MB static item) was edited three times per kind of edit, one edit per process, with nothing else running on the disk. The file is larger than the machine's 15 GB of RAM, so the page cache cannot absorb a full rewrite. On this diskddwithconv=fdatasyncwrote 10 GiB in 10.4 s (1.0 GB/s), and creating the file through mikecore took 42.1 s includingsync(475 MB/s), so rewriting the file would take at least 20 s. The kernel has no per-process I/O accounting, so the bytes written are the/proc/diskstatscount for the whole disk, from just before the edit (after async) to just after thesyncthat followsClose.Close), 3 runs eachClosesyncItemInfo[0].NameItemInfo[0].QuantityItemInfo[1].SpatialAxis.X0(generic file)SpatialAxis.X0and.Dy(file axis)Every edit finishes,
syncincluded, in at most 62 ms: over 300 times faster than the disk could rewrite the file. The name, quantity and item-axis edits write exactly what the control writes. The file-axis edit writes 3,997,696 B more, the 4,000,000 B static item in whole 4 KiB pages: onCloseit rewrites the static item, as C# does, and that data is written back unchanged. Its cost grows with the size of the static items, not with the number of time steps. Afterwards the file reads back with the new names, quantities and axes, all 2500 time steps, an unchanged static item and the expected last time step:An earlier run at
a45d04cgave the same byte counts. On a 2 GB file,cmp -lagainst a copy taken before each edit found 9, 3, 1 and 15 changed bytes for the name, quantity, item axis and file axis edits, all at offsets 370 to 855.Spike script
Verify it yourself
The issue's own case, on a copy of
testdata/Landuse.dfs2:MIKE Zero 2023
A copy of
testdata/Landuse.dfs2was edited at67236bb(Name = "Land",Quantity = eumQuantity(eumIAreaFraction, eumUPerCent),SpatialAxis.X0 = 1000,SpatialAxis.Y0 = 2000, thenClose) and opened in the MIKE Zero 2023 Grid Editor next to the original. mikecore reads it back as'Land '(padded to the old 7 characters),100311-99001, X0 1000, Y0 2000. MIKE Zero shows the same name and unit: the title isLandand the legendLand [%], where the original showsLanduse [Integer]. The data is unchanged. The dynamic item path it checks has not changed since67236bb.Review
Rounds 1 to 4 ran on the first version of the PR (up to
a45d04c); rounds 5 to 12 on the merge with master and the commits after it. Round 9 found a must-fix after the ready-pr round limit; the user then asked for it to be fixed (rounds 10 to 12). Round 12 reported no must-fix findings.Round 1:
Flushafter an axis change moved the file pointer, so an appended time step overwrote step 0. Fixed inc601158(test2479afb, nowtest_flush_then_append).Closeleaked the native handles if the axis write raised. Fixed inc601158(try/finally).Name/Quantitykept the new value when the write failed. Fixed inc601158._Updatewrote the axis once per attribute. Fixed inc601158.2479afb.test_name_keeps_its_length_in_the_filereads the bytes).0c55a8e.Round 2:
Close, the setters andFlushcalled the native library with item pointers into the freed header. Fixed in21cded3(teste9f111a).e9f111a.21cded3, and reworded in67236bb.21cded3.Quantitywrite raisesUnicodeEncodeError. Declined: the strict encode raises a clear error, whereas a lenient encode would silently rewrite the name to?. Such names are rare.Round 3 (no must-fix):
67236bb.Flushwrites. Fixed in67236bbby dropping the claim: in Append mode the nativedfsFileFlushdoes not write item axes.getattrraised for an attribute the axis type lacks. Fixed in67236bb(teste49e30a).Flushdiffers from C#? Answered: listed under Deviations.file.SpatialAxisis now a copy. Answered under Risk.Round 4 (no must-fix):
__setattr__is a second notification pattern. Declined: listed under Deviations with the reason.file.SpatialAxissurfaces only atFlush/Close. Declined: C# behaves the same (its file axis only sets a flag), andClosestill releases the file throughtry/finally.dfsSetItemSpatialAxissilently skips Neq/CurveLinear axes. Declined: an existing limitation, listed under Not in this PR.Round 5:
WriteStaticItemData. Fixed in80137e7(test0c55a8e).DfsBuilder(Append mode) now gets the hooks, untested and not in the changelog. Fixed: tested in0c55a8e(test_edit_while_building), changelog in80137e7. It matches C#, which uses the same setters for files it creates._Updatewhen its write fails. Declined: it can only fail insideClose, after which the items are detached from a closed file, so the in-memory value no longer reaches any file.Flushwhy static items wait forClose. Fixed in80137e7(docstring).Round 6 (the first after the static item fix):
Quantity, the issue's own operation, raisedUnicodeEncodeError. Fixed inaf51545(tested1d1f2). This supersedes the "declined" answer in rounds 2 and 5.test_flush_then_append, for the Append-mode static rewrite. Fixed ined1d1f2.SpatialAxisis now a copy. Fixed inaf51545.Round 7:
d278e70.Close. Fixed inb26c945(test4daf251).b26c945); see round 9.SpatialAxisin Read mode (fromNoneto an axis), beyond the issue; listed under Not in this PR.dfsSetItemSpatialAxisfor axis types it doesn't write. Declined: no axis of those types is read today, so none can reach the hook.Round 8:
Closereached the destroyed header. Fixed in7d41b5f(test930d056).SpatialAxisis never written. Became round 9's must-fix.06e9297, which writes to each item's axis as read from the file.Round 9:
item.SpatialAxis = other, the old axis wrote the new one's values and reached the destroyed header afterClose. Fixed ine404877(test1ac3f51), as the user decided: an axis writes only while it is the item's axis, as in C#, andSpatialAxisstays a plain attribute.Flushtoo. Fixed ine404877.SpatialAxiscopy note under "Changed". Declined: it is part of the fix for Modify dfs2 items not working #38, so it stays in the Modify dfs2 items not working #38 entry.test_static_item_read_from_an_editable_file_is_freedchecks.Round 10:
06e9297(testbca52d0)._Updatewhen its write fails. Declined, as in round 5.Flush/Close. Said in theFlushdocstring (06e9297), and tested in round 11.origin/masterhas 328 too.Round 11:
eba1e3d; it fails when thetry/finallyinCloseis removed.b366af3(Flushdocstring).Round 12 (no must-fix):
SpatialAxisis also a plain attribute. Fixed: the changelog says it is the file axis's attributes that are written (bedcd18).bedcd18.Flush, not an internal field. Fixed inbedcd18.Risk
Dfs123File.SpatialAxisis now a copy ofItemInfo[0].SpatialAxis, not the same object, as in C#. Code that changed one and read the other would see a difference. Nothing in this repo does, and MIKE IO (main) never assigns toSpatialAxisattributes or to an item'sName/Quantity(grep ofsrc/). The MIKE IO downstream workflow atb366af3(run 38417752079) has the same results as master (run 38416560809);bedcd18changes only a docstring, the changelog and a test: 978 passed on every job, and the same two known failures,test_eum_conversion(all jobs) andtest_select_area_rotated_UTM_2(Linux only). That workflow always concludes "failure" because of those two.DfsBuildernow write item edits made before their data, and pad a new name to the built one's length, as C# does (test_edit_while_building). Before, such an edit was kept in memory only.dfsUpdateItemInfoanddfsSetItemAxis*only change the header (or, for a static item, its static vector), whichClose(orWriteStaticItemData) writes.assertOnlyHeaderChangedintests/test_dfs_edit.pychecks after every edit that the file size and the raw dynamic data bytes are unchanged, and the spike shows it at 20 GB.Closedetaches every item and axis it hooked, also an axis the item no longer holds, and a copy never carries a hook (test_edit_after_close_writes_nothing,test_replaced_axis_writes_nothing,test_copy_of_an_item_is_not_written, and the mutation table).SpatialAxiscan still be assigned, as before; the new object is not written, as decided on the PR (C# has no setter). The file axis still reaches that item.DfsFilecode as the dfsu 2D file that is.bedcd18: Lint (run 38418355877), Type check (run 38418355941) and Test Windows and Linux (run 38418355960) all passed.Not in this PR
Dfs123Filetakes the file axis from the first static item when a dfs1/2/3 file has no dynamic items; hereSpatialAxisstaysNonethere, as before. Porting it changesSpatialAxisin Read mode, which is beyond the issue.dfsSetItemSpatialAxishas no branch for NeqD1/2/3 and CurveLinear axes (they are commented out), so changing those axes is not written. This is an existing limitation, and porting them needs the coordinate-array marshalling, which roughly doubles the diff.🤖 Generated with Claude Code