Skip to content

Commit b1696fc

Browse files
authored
chore: align selectors handling with upstream (microsoft#1176)
1 parent 0ffc788 commit b1696fc

File tree

5 files changed

+50
-13
lines changed

5 files changed

+50
-13
lines changed

playwright/_impl/_browser_type.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ async def connect(
206206
if not timeout_future.done():
207207
timeout_future.cancel()
208208
playwright: "Playwright" = next(iter(done)).result()
209+
playwright._set_selectors(self._playwright.selectors)
209210
self._connection._child_ws_connections.append(connection)
210211
pre_launched_browser = playwright._initializer.get("preLaunchedBrowser")
211212
assert pre_launched_browser
@@ -219,6 +220,7 @@ def handle_transport_close() -> None:
219220
page._on_close()
220221
context._on_close()
221222
browser._on_close()
223+
connection.cleanup()
222224

223225
transport.once("close", handle_transport_close)
224226

playwright/_impl/_connection.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Union
2020

2121
from greenlet import greenlet
22-
from pyee import AsyncIOEventEmitter
22+
from pyee import AsyncIOEventEmitter, EventEmitter
2323

2424
from playwright._impl._helper import ParsedMessagePayload, parse_error
2525
from playwright._impl._transport import Transport
@@ -141,14 +141,15 @@ async def initialize(self) -> "Playwright":
141141
)
142142

143143

144-
class Connection:
144+
class Connection(EventEmitter):
145145
def __init__(
146146
self,
147147
dispatcher_fiber: Any,
148148
object_factory: Callable[[ChannelOwner, str, str, Dict], ChannelOwner],
149149
transport: Transport,
150150
loop: asyncio.AbstractEventLoop,
151151
) -> None:
152+
super().__init__()
152153
self._dispatcher_fiber = dispatcher_fiber
153154
self._transport = transport
154155
self._transport.on_message = lambda msg: self.dispatch(msg)
@@ -195,6 +196,7 @@ async def stop_async(self) -> None:
195196
def cleanup(self) -> None:
196197
for ws_connection in self._child_ws_connections:
197198
ws_connection._transport.dispose()
199+
self.emit("close")
198200

199201
def call_on_object_with_known_name(
200202
self, guid: str, callback: Callable[[ChannelOwner], None]

playwright/_impl/_object_factory.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
from playwright._impl._network import Request, Response, Route, WebSocket
3131
from playwright._impl._page import BindingCall, Page, Worker
3232
from playwright._impl._playwright import Playwright
33-
from playwright._impl._selectors import Selectors
33+
from playwright._impl._selectors import SelectorsOwner
3434
from playwright._impl._stream import Stream
3535
from playwright._impl._tracing import Tracing
3636

@@ -90,5 +90,5 @@ def create_remote_object(
9090
if type == "Worker":
9191
return Worker(parent, type, guid, initializer)
9292
if type == "Selectors":
93-
return Selectors(parent, type, guid, initializer)
93+
return SelectorsOwner(parent, type, guid, initializer)
9494
return DummyObject(parent, type, guid, initializer)

playwright/_impl/_playwright.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from playwright._impl._connection import ChannelOwner, from_channel
1919
from playwright._impl._fetch import APIRequest
2020
from playwright._impl._local_utils import LocalUtils
21-
from playwright._impl._selectors import Selectors
21+
from playwright._impl._selectors import Selectors, SelectorsOwner
2222

2323

2424
class Playwright(ChannelOwner):
@@ -40,7 +40,14 @@ def __init__(
4040
self.firefox._playwright = self
4141
self.webkit = from_channel(initializer["webkit"])
4242
self.webkit._playwright = self
43-
self.selectors = from_channel(initializer["selectors"])
43+
44+
self.selectors = Selectors(self._loop)
45+
selectors_owner: SelectorsOwner = from_channel(initializer["selectors"])
46+
self.selectors._add_channel(selectors_owner)
47+
48+
self._connection.on(
49+
"close", lambda: self.selectors._remove_channel(selectors_owner)
50+
)
4451
self.devices = {}
4552
self.devices = {
4653
device["name"]: parse_device_descriptor(device["descriptor"])
@@ -57,6 +64,12 @@ def __getitem__(self, value: str) -> "BrowserType":
5764
return self.webkit
5865
raise ValueError("Invalid browser " + value)
5966

67+
def _set_selectors(self, selectors: SelectorsOwner) -> None:
68+
selectors_owner = from_channel(self._initializer["selectors"])
69+
self.selectors._remove_channel(selectors_owner)
70+
self.selectors = selectors
71+
self.selectors._add_channel(selectors_owner)
72+
6073
def stop(self) -> None:
6174
pass
6275

playwright/_impl/_selectors.py

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,20 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
import asyncio
1516
from pathlib import Path
16-
from typing import Any, Dict, Union
17+
from typing import Any, Dict, List, Set, Union
1718

1819
from playwright._impl._api_types import Error
1920
from playwright._impl._connection import ChannelOwner
2021
from playwright._impl._helper import async_readfile
2122

2223

23-
class Selectors(ChannelOwner):
24-
def __init__(
25-
self, parent: ChannelOwner, type: str, guid: str, initializer: Dict
26-
) -> None:
27-
super().__init__(parent, type, guid, initializer)
24+
class Selectors:
25+
def __init__(self, loop: asyncio.AbstractEventLoop) -> None:
26+
self._loop = loop
27+
self._channels: Set[SelectorsOwner] = set()
28+
self._registrations: List[Dict] = []
2829

2930
async def register(
3031
self,
@@ -40,4 +41,23 @@ async def register(
4041
params: Dict[str, Any] = dict(name=name, source=script)
4142
if contentScript:
4243
params["contentScript"] = True
43-
await self._channel.send("register", params)
44+
for channel in self._channels:
45+
await channel._channel.send("register", params)
46+
self._registrations.append(params)
47+
48+
def _add_channel(self, channel: "SelectorsOwner") -> None:
49+
self._channels.add(channel)
50+
for params in self._registrations:
51+
# This should not fail except for connection closure, but just in case we catch.
52+
channel._channel.send_no_reply("register", params)
53+
54+
def _remove_channel(self, channel: "SelectorsOwner") -> None:
55+
if channel in self._channels:
56+
self._channels.remove(channel)
57+
58+
59+
class SelectorsOwner(ChannelOwner):
60+
def __init__(
61+
self, parent: ChannelOwner, type: str, guid: str, initializer: Dict
62+
) -> None:
63+
super().__init__(parent, type, guid, initializer)

0 commit comments

Comments
 (0)