Skip to content

Commit 05142c8

Browse files
committed
perf(robot): fix ArgumentSpec.resolve() caching bug for RobotArgumentSpec
The RobotArgumentSpec was recreated on every call (100K times) because: - hasattr() always returned False with @DataClass(slots=True) - Assignment went to a local variable instead of self RobotArgumentSpec.__init__ calls: 100K → 1.3K (-98.7%) resolve cumtime: 3.93s → 3.29s (-0.64s) Warm no-NS total: 30.78s → 29.81s (-0.97s, -3.2%)
1 parent f3118bd commit 05142c8

File tree

1 file changed

+24
-9
lines changed

1 file changed

+24
-9
lines changed

packages/robot/src/robotcode/robot/diagnostics/library_doc.py

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,21 @@ class ArgumentSpec:
535535
defaults: Any
536536
types: Optional[Dict[str, str]] = None
537537
return_type: Optional[str] = None
538+
_robot_arguments: Any = field(init=False, default=None, repr=False, compare=False)
539+
540+
def __getstate__(self) -> Dict[str, Any]:
541+
return {k: getattr(self, k) for k in self.__slots__ if k != "_robot_arguments"}
542+
543+
def __setstate__(self, state: Any) -> None:
544+
if isinstance(state, dict):
545+
for k, v in state.items():
546+
object.__setattr__(self, k, v)
547+
else:
548+
# Legacy pickle format: tuple of (dict_or_none, slot_dict)
549+
_, slot_state = state
550+
for k, v in slot_state.items():
551+
object.__setattr__(self, k, v)
552+
object.__setattr__(self, "_robot_arguments", None)
538553

539554
@staticmethod
540555
def from_robot_argument_spec(spec: Any) -> ArgumentSpec:
@@ -561,9 +576,9 @@ def resolve(
561576
dict_to_kwargs: bool = False,
562577
validate: bool = True,
563578
) -> Tuple[List[Any], List[Tuple[str, Any]]]:
564-
if not hasattr(self, "__robot_arguments"):
579+
if self._robot_arguments is None:
565580
if get_robot_version() < (7, 0):
566-
__robot_arguments = RobotArgumentSpec(
581+
self._robot_arguments = RobotArgumentSpec(
567582
self.name,
568583
self.type,
569584
self.positional_only,
@@ -575,7 +590,7 @@ def resolve(
575590
None,
576591
)
577592
else:
578-
__robot_arguments = RobotArgumentSpec(
593+
self._robot_arguments = RobotArgumentSpec(
579594
self.name,
580595
self.type,
581596
self.positional_only,
@@ -587,18 +602,18 @@ def resolve(
587602
self.embedded,
588603
None,
589604
)
590-
__robot_arguments.name = self.name
605+
self._robot_arguments.name = self.name
591606
if validate:
592607
if get_robot_version() < (7, 0):
593608
resolver = ArgumentResolver(
594-
__robot_arguments,
609+
self._robot_arguments,
595610
resolve_named=resolve_named,
596611
resolve_variables_until=resolve_variables_until,
597612
dict_to_kwargs=dict_to_kwargs,
598613
)
599614
else:
600615
resolver = ArgumentResolver(
601-
__robot_arguments,
616+
self._robot_arguments,
602617
resolve_named=resolve_named,
603618
resolve_args_until=resolve_variables_until,
604619
dict_to_kwargs=dict_to_kwargs,
@@ -612,14 +627,14 @@ class MyNamedArgumentResolver(NamedArgumentResolver):
612627
def _raise_positional_after_named(self) -> None:
613628
pass
614629

615-
positional, named = MyNamedArgumentResolver(__robot_arguments).resolve(arguments, variables)
630+
positional, named = MyNamedArgumentResolver(self._robot_arguments).resolve(arguments, variables)
616631
if get_robot_version() < (7, 0):
617632
positional, named = ArgumentsVariableReplacer(resolve_variables_until).replace(positional, named, variables)
618633
else:
619-
positional, named = ArgumentsVariableReplacer(__robot_arguments, resolve_variables_until).replace(
634+
positional, named = ArgumentsVariableReplacer(self._robot_arguments, resolve_variables_until).replace(
620635
positional, named, variables
621636
)
622-
positional, named = DictToKwargs(__robot_arguments, dict_to_kwargs).handle(positional, named)
637+
positional, named = DictToKwargs(self._robot_arguments, dict_to_kwargs).handle(positional, named)
623638
return positional, named
624639

625640

0 commit comments

Comments
 (0)