44
55import logging
66from collections .abc import Callable , Iterable
7+ from copy import deepcopy
78from dataclasses import dataclass , field
89from enum import Enum
910from typing import Any , Final , cast
@@ -126,6 +127,7 @@ def parse_value(
126127 self ,
127128 value : ConfigValueType ,
128129 allow_none : bool = True ,
130+ raise_on_error : bool = True ,
129131 ) -> ConfigValueType :
130132 """Parse value from the config entry details and plain value."""
131133 if self .type == ConfigEntryType .LABEL :
@@ -137,9 +139,13 @@ def parse_value(
137139 value = self .default_value
138140
139141 if isinstance (value , list ) and not self .multi_value :
140- raise ValueError (f"{ self .key } must be a single value" )
142+ if raise_on_error :
143+ raise ValueError (f"{ self .key } must be a single value" )
144+ value = self .default_value
141145 if self .multi_value and not isinstance (value , list ):
142- raise ValueError (f"value for { self .key } must be a list" )
146+ if raise_on_error :
147+ raise ValueError (f"value for { self .key } must be a list" )
148+ value = self .default_value
143149
144150 # handle some value type conversions caused by the serialization
145151 def convert_value (_value : _ConfigValueTypeSingle ) -> _ConfigValueTypeSingle :
@@ -152,11 +158,15 @@ def convert_value(_value: _ConfigValueTypeSingle) -> _ConfigValueTypeSingle:
152158 return _value
153159
154160 if value is None and self .required and not allow_none :
155- raise ValueError (f"{ self .key } is required" )
161+ if raise_on_error :
162+ raise ValueError (f"{ self .key } is required" )
163+ value = self .default_value
156164
157165 # handle optional validation callback
158166 if self .validate is not None and not (self .validate (value )):
159- raise ValueError (f"{ value } is not a valid value for { self .key } " )
167+ if raise_on_error :
168+ raise ValueError (f"{ value } is not a valid value for { self .key } " )
169+ value = self .default_value
160170
161171 if self .multi_value and value is not None :
162172 value = cast ("_ConfigValueTypeMulti" , value )
@@ -212,10 +222,12 @@ def parse(
212222 # unpack Enum value in default_value
213223 if isinstance (entry .default_value , Enum ):
214224 entry .default_value = entry .default_value .value # type: ignore[unreachable]
215- # create a copy of the entry
216- conf .values [entry .key ] = ConfigEntry . from_dict (entry . to_dict () )
225+ # copy original entry to prevent mutation
226+ conf .values [entry .key ] = deepcopy (entry )
217227 conf .values [entry .key ].parse_value (
218- raw .get ("values" , {}).get (entry .key ), allow_none = True
228+ raw .get ("values" , {}).get (entry .key ),
229+ allow_none = True ,
230+ raise_on_error = False ,
219231 )
220232 return conf
221233
0 commit comments