1- from collections import ChainMap
2- from collections .abc import Mapping
31from pathlib import Path
42from typing import Any
53
64import numpy as np
75import xarray as xr
86from lark import Token , Transformer
97from modflow_devtools .dfn import Dfn
10- from modflow_devtools .dfn .schema .v2 import SCALAR_TYPES
118
129
1310class BasicTransformer (Transformer ):
@@ -76,22 +73,19 @@ def start(self, items: list[Any]) -> dict:
7673 if not isinstance (item , dict ):
7774 continue
7875 for block_name , block_data in item .items ():
79- # Pluralize indexed blocks (e.g., period -> periods)
80- if isinstance (block_data , dict ) and all (isinstance (k , int ) for k in block_data .keys ()):
81- # This is an indexed block, use plural form
82- if not block_name .endswith ('s' ):
83- block_name = block_name + 's'
84-
85- if block_name not in merged :
76+ # Check if this is an indexed block (dict with integer keys)
77+ if isinstance (block_data , dict ) and all (
78+ isinstance (k , int ) for k in block_data .keys ()
79+ ):
80+ # Flatten indexed blocks into separate keys like "period 1", "period 2"
81+ for index , data in block_data .items ():
82+ indexed_key = f"{ block_name } { index } "
83+ merged [indexed_key ] = data
84+ elif block_name not in merged :
8685 merged [block_name ] = block_data
8786 else :
88- # If both are dicts with integer keys (indexed blocks), merge them
89- existing = merged [block_name ]
90- if (isinstance (existing , dict ) and isinstance (block_data , dict ) and
91- all (isinstance (k , int ) for k in existing .keys ()) and
92- all (isinstance (k , int ) for k in block_data .keys ())):
93- existing .update (block_data )
94- # Otherwise, indexed block overwrites (shouldn't happen for well-formed input)
87+ # This shouldn't happen for well-formed input
88+ pass
9589 return merged
9690
9791 def block (self , items : list [Any ]) -> dict :
@@ -160,7 +154,7 @@ def factor(self, items: list[Any]) -> dict[str, float]:
160154 def iprn (self , items : list [Any ]) -> dict [str , int ]:
161155 return {"iprn" : items [0 ]}
162156
163- def binary (self , items : list [ Any ] ) -> dict [str , bool ]:
157+ def binary (self , _ ) -> dict [str , bool ]:
164158 return {"binary" : True }
165159
166160 def filename (self , items : list [Any ]) -> Path :
@@ -193,59 +187,20 @@ def number(self, items: list[Any]) -> int | float:
193187 def data (self , items : list [Any ]) -> np .ndarray :
194188 return np .array (items )
195189
196- def netcdf (self , items : list [ Any ] ) -> dict [str , bool ]:
190+ def netcdf (self , _ ) -> dict [str , bool ]:
197191 return {"netcdf" : True }
198192
199- # Handle typed__ prefixed rules from imports
200- def typed__single_array (self , items : list [Any ]) -> dict :
201- return self .single_array (items )
202-
203- def typed__layered_array (self , items : list [Any ]) -> list [dict ]:
204- return self .layered_array (items )
205-
206- def typed__readarray (self , items : list [Any ]) -> dict [str , Any ]:
207- return self .readarray (items )
208-
209- def typed__control (self , items : list [Any ]) -> dict [str , Any ]:
210- return self .control (items )
211-
212- def typed__constant (self , items : list [Any ]) -> dict [str , Any ]:
213- return self .constant (items )
214-
215- def typed__internal (self , items : list [Any ]) -> dict [str , Any ]:
216- return self .internal (items )
217-
218- def typed__external (self , items : list [Any ]) -> dict [str , Any ]:
219- return self .external (items )
220-
221- def typed__factor (self , items : list [Any ]) -> dict [str , float ]:
222- return self .factor (items )
223-
224- def typed__iprn (self , items : list [Any ]) -> dict [str , int ]:
225- return self .iprn (items )
226-
227- def typed__binary (self , items : list [Any ]) -> dict [str , bool ]:
228- return self .binary (items )
229-
230- def typed__filename (self , items : list [Any ]) -> Path :
231- return self .filename (items )
232-
233- def typed__data (self , items : list [Any ]) -> np .ndarray :
234- return self .data (items )
235-
236- def typed__netcdf (self , items : list [Any ]) -> dict [str , bool ]:
237- return self .netcdf (items )
238-
239- def typed__layered (self , items : list [Any ]) -> dict [str , bool ]:
240- return {"layered" : True }
241-
242193 def block_index (self , items : list [Any ]) -> int :
243194 """Extract block index (e.g., period number)."""
244195 return items [0 ]
245196
246197 def stress_period_data (self , items : list [Any ]) -> list [Any ]:
247- """Handle stress period data (list of values for a single record)."""
248- return items
198+ """Handle stress period data (one row of values).
199+
200+ The parser gives us the values for one row plus a NEWLINE token.
201+ Filter out the NEWLINE token and return just the data values.
202+ """
203+ return [item for item in items if not isinstance (item , Token ) or item .type != "NEWLINE" ]
249204
250205 @staticmethod
251206 def try_create_dataarray (array_info : dict ) -> dict :
@@ -263,7 +218,7 @@ def __default__(self, data, children, meta):
263218 if self .blocks is None or self .fields is None :
264219 return super ().__default__ (data , children , meta )
265220 if data .endswith ("_block" ) and (block_name := data [:- 6 ]) in self .blocks :
266- # Check if this is an indexed block (period blocks have 3 children: [ index, fields, index])
221+ # See if this is an indexed block (period blocks have 3 children: index, fields, index
267222 if len (children ) == 3 and isinstance (children [0 ], int ) and isinstance (children [2 ], int ):
268223 # Indexed block: [index, fields, index]
269224 block_index = children [0 ]
0 commit comments