1- from typing import ClassVar
1+ from pydantic import BaseModel , ConfigDict , model_validator
2+ from typing import Any
23
3- from pals .parameters ._multipole_base import _MultipoleBase
4+ # Valid parameter prefixes, their expected format and description
5+ _PARAMETER_PREFIXES = {
6+ "tilt" : ("tiltN" , "Tilt" ),
7+ "Bn" : ("BnN" , "Normal component" ),
8+ "Bs" : ("BsN" , "Skew component" ),
9+ "Kn" : ("KnN" , "Normalized normal component" ),
10+ "Ks" : ("KsN" , "Normalized skew component" ),
11+ }
412
513
6- class MagneticMultipoleParameters (_MultipoleBase ):
14+ def _validate_order (
15+ key_num : str , parameter_name : str , prefix : str , expected_format : str
16+ ) -> None :
17+ """Validate that the order number is a non-negative integer without leading zeros."""
18+ error_msg = (
19+ f"Invalid { parameter_name } : '{ prefix } { key_num } '. "
20+ f"Parameter must be of the form '{ expected_format } ', where 'N' is a non-negative integer without leading zeros."
21+ )
22+ if not key_num .isdigit () or (key_num .startswith ("0" ) and key_num != "0" ):
23+ raise ValueError (error_msg )
24+
25+
26+ class MagneticMultipoleParameters (BaseModel ):
727 """Magnetic multipole parameters
828
929 Valid parameter formats:
@@ -17,11 +37,31 @@ class MagneticMultipoleParameters(_MultipoleBase):
1737 Where N is a positive integer without leading zeros (except "0" itself).
1838 """
1939
20- _KIND_NAME : ClassVar [str ] = "magnetic"
21- _PARAMETER_PREFIXES : ClassVar [dict [str , tuple [str , str ]]] = {
22- "tilt" : ("tiltN" , "Tilt" ),
23- "Bn" : ("BnN" , "Normal component" ),
24- "Bs" : ("BsN" , "Skew component" ),
25- "Kn" : ("KnN" , "Normalized normal component" ),
26- "Ks" : ("KsN" , "Normalized skew component" ),
27- }
40+ model_config = ConfigDict (extra = "allow" )
41+
42+ @model_validator (mode = "before" )
43+ @classmethod
44+ def validate (cls , values : dict [str , Any ]) -> dict [str , Any ]:
45+ """Validate all parameter names match the expected multipole format."""
46+ for key in values :
47+ # Check if key ends with 'L' for length-integrated values
48+ is_length_integrated = key .endswith ("L" )
49+ base_key = key [:- 1 ] if is_length_integrated else key
50+
51+ # No length-integrated values allowed for tilt parameter
52+ if is_length_integrated and base_key .startswith ("tilt" ):
53+ raise ValueError (f"Invalid magnetic multipole parameter: '{ key } '. " )
54+
55+ # Find matching prefix
56+ for prefix , (expected_format , description ) in _PARAMETER_PREFIXES .items ():
57+ if base_key .startswith (prefix ):
58+ key_num = base_key [len (prefix ) :]
59+ _validate_order (key_num , description , prefix , expected_format )
60+ break
61+ else :
62+ raise ValueError (
63+ f"Invalid magnetic multipole parameter: '{ key } '. "
64+ f"Parameters must be of the form 'tiltN', 'BnN', 'BsN', 'KnN', or 'KsN' "
65+ f"(with optional 'L' suffix for length-integrated), where 'N' is a non-negative integer."
66+ )
67+ return values
0 commit comments