@@ -290,8 +290,47 @@ def _value_is_not_none_or_type_is_filemodel(field_type: type, value: Any) -> boo
290
290
class DataBlockINIBasedModel (INIBasedModel ):
291
291
"""DataBlockINIBasedModel defines the base model for ini models with datablocks.
292
292
293
+ This class extends the functionality of INIBasedModel to handle structured data blocks
294
+ commonly found in INI files. It provides validation, serialization, and conversion methods
295
+ for working with these data blocks.
296
+
293
297
Attributes:
294
298
datablock (Datablock): (class attribute) the actual data columns.
299
+
300
+ Attributes:
301
+ datablock (List[List[Union[float, str]]]):
302
+ A two-dimensional list representing the data block. Each sub-list corresponds to
303
+ a row in the data block, and the values can be either floats or strings.
304
+
305
+ Args:
306
+ datablock (List[List[Union[float, str]]], optional):
307
+ The initial data block for the model. Defaults to an empty list.
308
+
309
+ Returns:
310
+ None
311
+
312
+ Raises:
313
+ ValueError: If a NaN value is found within the data block.
314
+
315
+ See Also:
316
+ INIBasedModel: The parent class for models representing INI-based configurations.
317
+ INISerializerConfig: Provides configuration for INI serialization.
318
+
319
+ Examples:
320
+ Create a model and validate its data block:
321
+ >>> from hydrolib.core.dflowfm.ini.models import DataBlockINIBasedModel
322
+ >>> model = DataBlockINIBasedModel(datablock=[[1.0, 2.0], [3.0, 4.0]])
323
+ >>> print(model.datablock)
324
+ [[1.0, 2.0], [3.0, 4.0]]
325
+
326
+ Attempt to create a model with invalid data:
327
+
328
+ >>> model = DataBlockINIBasedModel(datablock=[[1.0, None]])
329
+ ValueError: NaN is not supported in datablocks.
330
+
331
+ Notes:
332
+ - The class includes a validator to ensure that no NaN values are present in the data block.
333
+ - Data blocks are converted to a serialized format for writing to INI files.
295
334
"""
296
335
297
336
datablock : Datablock = Field (default_factory = list )
@@ -302,6 +341,9 @@ class DataBlockINIBasedModel(INIBasedModel):
302
341
def _get_unknown_keyword_error_manager (cls ) -> Optional [UnknownKeywordErrorManager ]:
303
342
"""
304
343
The DataBlockINIBasedModel does not need to raise an error on unknown keywords.
344
+
345
+ Returns:
346
+ Optional[UnknownKeywordErrorManager]: Returns None as unknown keywords are ignored.
305
347
"""
306
348
return None
307
349
@@ -310,11 +352,30 @@ def _to_section(
310
352
config : DataBlockINIBasedSerializerConfig ,
311
353
save_settings : ModelSaveSettings ,
312
354
) -> Section :
355
+ """
356
+ Converts the current model to an INI Section representation.
357
+
358
+ Args:
359
+ config (DataBlockINIBasedSerializerConfig): Configuration for serializing the data block.
360
+ save_settings (ModelSaveSettings): Settings for saving the model.
361
+
362
+ Returns:
363
+ Section: The INI Section containing serialized data and the data block.
364
+ """
313
365
section = super ()._to_section (config , save_settings )
314
366
section .datablock = self ._to_datablock (config )
315
367
return section
316
368
317
369
def _to_datablock (self , config : DataBlockINIBasedSerializerConfig ) -> List [List ]:
370
+ """
371
+ Converts the data block to a serialized format based on the configuration.
372
+
373
+ Args:
374
+ config (DataBlockINIBasedSerializerConfig): Configuration for serializing the data block.
375
+
376
+ Returns:
377
+ List[List]: A serialized representation of the data block.
378
+ """
318
379
converted_datablock = []
319
380
320
381
for row in self .datablock :
@@ -329,6 +390,16 @@ def _to_datablock(self, config: DataBlockINIBasedSerializerConfig) -> List[List]
329
390
def convert_value (
330
391
cls , value : Union [float , str ], config : DataBlockINIBasedSerializerConfig
331
392
) -> str :
393
+ """
394
+ Converts a value in the data block to its serialized string representation.
395
+
396
+ Args:
397
+ value (Union[float, str]): The value to be converted.
398
+ config (DataBlockINIBasedSerializerConfig): Configuration for the conversion.
399
+
400
+ Returns:
401
+ str: The serialized string representation of the value.
402
+ """
332
403
if isinstance (value , float ):
333
404
return f"{ value :{config .float_format_datablock }} "
334
405
@@ -339,21 +410,30 @@ def _validate_no_nans_are_present(cls, datablock: Datablock) -> Datablock:
339
410
"""Validate that the datablock does not have any NaN values.
340
411
341
412
Args:
342
- datablock (Datablock): The datablock to verify .
413
+ datablock (Datablock): The datablock to validate .
343
414
344
415
Raises:
345
416
ValueError: When a NaN is present in the datablock.
346
417
347
418
Returns:
348
419
Datablock: The validated datablock.
349
420
"""
350
- if any (cls ._is_float_and_nan (value ) for list in datablock for value in list ):
421
+ if any (cls ._is_float_and_nan (value ) for row in datablock for value in row ):
351
422
raise ValueError ("NaN is not supported in datablocks." )
352
423
353
424
return datablock
354
425
355
426
@staticmethod
356
427
def _is_float_and_nan (value : float ) -> bool :
428
+ """
429
+ Determines whether a value is a float and is NaN.
430
+
431
+ Args:
432
+ value (float): The value to check.
433
+
434
+ Returns:
435
+ bool: True if the value is a NaN float; otherwise, False.
436
+ """
357
437
return isinstance (value , float ) and isnan (value )
358
438
359
439
0 commit comments