3030TEnum = TypeVar ('TEnum' , bound = StrEnum )
3131
3232
33- @dataclass (kw_only = True )
33+ @dataclass (kw_only = True , slots = True )
3434class InputData :
3535 """
3636 Input dataclass
@@ -50,12 +50,12 @@ class InputData:
5050 display : _display .Display | None = None
5151
5252
53- old_input_values : dict [str , Any ] = {}
53+ _old_input_values : dict [str , Any ] = {}
5454inputs : dict [str | None , InputData ] = {}
5555
5656
5757# noinspection PyShadowingBuiltins,PyShadowingNames
58- @dataclass (kw_only = True )
58+ @dataclass (kw_only = True , slots = True )
5959class Script :
6060 """
6161 Script parameters dataclass
@@ -73,7 +73,7 @@ class Script:
7373 format : _format .Format = _format .inherit
7474 precision : int | None = None
7575 scale : _scale .Scale | None = None
76- pyramiding : int = 0
76+ pyramiding : int = 1
7777 calc_on_order_fills : bool = False
7878 calc_on_every_tick : bool = False
7979 max_bars_back : int = 0
@@ -137,7 +137,10 @@ def _format_value(value) -> str:
137137 ]
138138
139139 # Save general settings
140- for key , value in self .__dict__ .items ():
140+ from dataclasses import fields
141+ for field in fields (self ):
142+ key = field .name
143+ value = getattr (self , key )
141144 if key .startswith ('_' ) or key in self ._SKIP_FIELDS :
142145 continue
143146 if value is None :
@@ -153,11 +156,17 @@ def _format_value(value) -> str:
153156
154157 # Save inputs
155158 for arg_name , input_data in self .inputs .items ():
159+ # Skip None keys (can happen with some input configurations)
160+ if arg_name is None :
161+ continue
156162 lines .append (f"\n [inputs.{ arg_name .removesuffix ('__global__' )} ]" )
157163 lines .append ("# Input metadata, cannot be modified" )
158164
159165 # Add all metadata as comments
160- for key , value in input_data .__dict__ .items ():
166+ from dataclasses import fields as input_fields
167+ for field in input_fields (input_data ):
168+ key = field .name
169+ value = getattr (input_data , key )
161170 if key == 'id' :
162171 continue
163172 if value is not None :
@@ -167,8 +176,8 @@ def _format_value(value) -> str:
167176 lines .append ("# Change here to modify the input value" )
168177
169178 # Add the actual value
170- if input_data .defval is not None and arg_name in old_input_values :
171- lines .append (f"value = { _format_value (old_input_values [arg_name ])} " )
179+ if input_data .defval is not None and arg_name in _old_input_values :
180+ lines .append (f"value = { _format_value (_old_input_values [arg_name ])} " )
172181 else :
173182 lines .append ("#value =" )
174183
@@ -207,8 +216,8 @@ def load(self, path: str | Path) -> None:
207216 for arg_name , arg_data in data ['inputs' ].items ():
208217 if 'value' not in arg_data :
209218 continue
210- old_input_values [arg_name ] = arg_data ['value' ]
211- old_input_values [arg_name + '__global__' ] = arg_data ['value' ] # For strict mode
219+ _old_input_values [arg_name ] = arg_data ['value' ]
220+ _old_input_values [arg_name + '__global__' ] = arg_data ['value' ] # For strict mode
212221
213222 #
214223 # decorators
@@ -223,6 +232,10 @@ def _decorate(self):
223232 if toml_path .exists ():
224233 self .load (toml_path )
225234
235+ # Pyramiding must be at least 1
236+ if self .pyramiding <= 0 :
237+ self .pyramiding = 1
238+
226239 def decorator (func ):
227240 # Save inputs to script instance then clear inputs (for next script)
228241 self .inputs = inputs .copy () # type: ignore
@@ -236,7 +249,7 @@ def decorator(func):
236249 if os .environ .get ('PYNE_SAVE_SCRIPT_TOML' , '1' ) == '1' and 'pytest' not in sys .modules :
237250 self .save (toml_path )
238251
239- old_input_values .clear ()
252+ _old_input_values .clear ()
240253 return func
241254
242255 return decorator
@@ -523,7 +536,7 @@ def __call__(self, defval: Any, title: str | None = None, *,
523536 group = group ,
524537 display = display ,
525538 )
526- return defval if _id not in old_input_values else old_input_values [_id ]
539+ return defval if _id not in _old_input_values else _old_input_values [_id ]
527540
528541 @classmethod
529542 def _int (cls , defval : int , title : str | None = None , * ,
@@ -564,7 +577,7 @@ def _int(cls, defval: int, title: str | None = None, *,
564577 options = options ,
565578 display = display ,
566579 )
567- return defval if _id not in old_input_values else safe_convert .safe_int (old_input_values [_id ])
580+ return defval if _id not in _old_input_values else safe_convert .safe_int (_old_input_values [_id ])
568581
569582 @classmethod
570583 def _bool (cls , defval : bool , title : str | None = None , * ,
@@ -596,7 +609,7 @@ def _bool(cls, defval: bool, title: str | None = None, *,
596609 confirm = confirm ,
597610 display = display ,
598611 )
599- return defval if _id not in old_input_values else bool (old_input_values [_id ])
612+ return defval if _id not in _old_input_values else bool (_old_input_values [_id ])
600613
601614 @classmethod
602615 def _float (cls , defval : float , title : str | None = None , * ,
@@ -637,7 +650,7 @@ def _float(cls, defval: float, title: str | None = None, *,
637650 options = options ,
638651 display = display ,
639652 )
640- return defval if _id not in old_input_values else safe_convert .safe_float (old_input_values [_id ])
653+ return defval if _id not in _old_input_values else safe_convert .safe_float (_old_input_values [_id ])
641654
642655 @classmethod
643656 def string (cls , defval : str , title : str | None = None , * ,
@@ -673,7 +686,7 @@ def string(cls, defval: str, title: str | None = None, *,
673686 display = display ,
674687 options = options ,
675688 )
676- return defval if _id not in old_input_values else str (old_input_values [_id ])
689+ return defval if _id not in _old_input_values else str (_old_input_values [_id ])
677690
678691 @classmethod
679692 def color (cls , defval : Color , title : str | None = None , * ,
@@ -705,7 +718,7 @@ def color(cls, defval: Color, title: str | None = None, *,
705718 confirm = confirm ,
706719 display = display ,
707720 )
708- return defval if _id not in old_input_values else Color (old_input_values [_id ])
721+ return defval if _id not in _old_input_values else Color (_old_input_values [_id ])
709722
710723 @classmethod
711724 def source (cls , defval : str | Source , title : str | None = None , * ,
@@ -740,7 +753,7 @@ def source(cls, defval: str | Source, title: str | None = None, *,
740753 display = display ,
741754 )
742755 # We actually return a string here, but the InputTransformer will add a `getattr()` call to get the
743- return cast (Series [float ], defval if _id not in old_input_values else old_input_values [_id ])
756+ return cast (Series [float ], defval if _id not in _old_input_values else _old_input_values [_id ])
744757
745758 @classmethod
746759 def enum (cls , defval : TEnum , title : str | None = None , * ,
@@ -776,11 +789,11 @@ def enum(cls, defval: TEnum, title: str | None = None, *,
776789 display = display ,
777790 options = options ,
778791 )
779- if _id not in old_input_values :
792+ if _id not in _old_input_values :
780793 return defval
781794 else :
782795 # Convert string value back to the specific enum type
783- value = old_input_values [_id ]
796+ value = _old_input_values [_id ]
784797 if isinstance (value , str ):
785798 try :
786799 return defval .__class__ (value )
0 commit comments