Skip to content

Commit ab6c0af

Browse files
authored
fix: do not leak api wrappers (#495)
1 parent 63ea579 commit ab6c0af

File tree

1 file changed

+16
-14
lines changed

1 file changed

+16
-14
lines changed

playwright/_impl/_impl_to_api_mapping.py

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@
1414

1515
import inspect
1616
from typing import Any, Callable, Dict, List, Optional
17-
from weakref import WeakKeyDictionary
1817

1918
from playwright._impl._api_types import Error
2019

20+
INSTANCE_ATTR = "_pw_api_instance"
21+
2122

2223
class ImplWrapper:
2324
def __init__(self, impl_obj: Any) -> None:
@@ -27,7 +28,6 @@ def __init__(self, impl_obj: Any) -> None:
2728
class ImplToApiMapping:
2829
def __init__(self) -> None:
2930
self._mapping: Dict[type, type] = {}
30-
self._instances: WeakKeyDictionary[Any, Any] = WeakKeyDictionary()
3131

3232
def register(self, impl_class: type, api_class: type) -> None:
3333
self._mapping[impl_class] = api_class
@@ -39,13 +39,15 @@ def from_maybe_impl(self, obj: Any) -> Any:
3939
return {name: self.from_maybe_impl(value) for name, value in obj.items()}
4040
if isinstance(obj, list):
4141
return [self.from_maybe_impl(item) for item in obj]
42-
if obj not in self._instances:
43-
api_class = self._mapping.get(type(obj))
44-
if not api_class:
45-
return obj
46-
api_instance = api_class(obj)
47-
self._instances[obj] = api_instance
48-
return self._instances[obj]
42+
api_class = self._mapping.get(type(obj))
43+
if api_class:
44+
api_instance = getattr(obj, INSTANCE_ATTR, None)
45+
if not api_instance:
46+
api_instance = api_class(obj)
47+
setattr(obj, INSTANCE_ATTR, api_instance)
48+
return api_instance
49+
else:
50+
return obj
4951

5052
def from_impl(self, obj: Any) -> Any:
5153
assert obj
@@ -77,14 +79,14 @@ def to_impl(self, obj: Any) -> Any:
7779
raise Error("Maximum argument depth exceeded")
7880

7981
def wrap_handler(self, handler: Callable[..., None]) -> Callable[..., None]:
80-
if handler in self._instances:
81-
return self._instances[handler]
82-
83-
def wrapper(*args: Any) -> Any:
82+
def wrapper_func(*args: Any) -> Any:
8483
arg_count = len(inspect.signature(handler).parameters)
8584
return handler(
8685
*list(map(lambda a: self.from_maybe_impl(a), args))[:arg_count]
8786
)
8887

89-
self._instances[handler] = wrapper
88+
wrapper = getattr(handler, INSTANCE_ATTR, None)
89+
if not wrapper:
90+
wrapper = wrapper_func
91+
setattr(handler, INSTANCE_ATTR, wrapper)
9092
return wrapper

0 commit comments

Comments
 (0)