We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
internal: setup env variables when launching driver
1.18 driver assumes the following environment variables are set:

```
PW_CLI_TARGET_LANG=python
PW_CLI_TARGET_LANG_VERSION=<version>
PW_CLI_DISPLAY_VERSION=CLI_VERSION (of the language)
```

`version` should not be too granular to avoid noise; IMO major + minor seems to be good for Python.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `playwright/_impl/_transport.py`
Content:
```
1 # Copyright (c) Microsoft Corporation.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 import asyncio
16 import io
17 import json
18 import os
19 import subprocess
20 import sys
21 from abc import ABC, abstractmethod
22 from pathlib import Path
23 from typing import Callable, Dict, Optional, Union
24 
25 import websockets
26 import websockets.exceptions
27 from pyee import AsyncIOEventEmitter
28 from websockets.client import connect as websocket_connect
29 
30 from playwright._impl._api_types import Error
31 from playwright._impl._helper import ParsedMessagePayload
32 
33 
34 # Sourced from: https://github.com/pytest-dev/pytest/blob/da01ee0a4bb0af780167ecd228ab3ad249511302/src/_pytest/faulthandler.py#L69-L77
35 def _get_stderr_fileno() -> Optional[int]:
36     if sys.stderr.closed:
37         return None
38 
39     try:
40         return sys.stderr.fileno()
41     except (AttributeError, io.UnsupportedOperation):
42         # pytest-xdist monkeypatches sys.stderr with an object that is not an actual file.
43         # https://docs.python.org/3/library/faulthandler.html#issue-with-file-descriptors
44         # This is potentially dangerous, but the best we can do.
45         if not hasattr(sys, "__stderr__") or not sys.__stderr__:
46             return None
47         return sys.__stderr__.fileno()
48 
49 
50 class Transport(ABC):
51     def __init__(self, loop: asyncio.AbstractEventLoop) -> None:
52         self._loop = loop
53         self.on_message: Callable[[ParsedMessagePayload], None] = lambda _: None
54         self.on_error_future: asyncio.Future = loop.create_future()
55 
56     @abstractmethod
57     def request_stop(self) -> None:
58         pass
59 
60     def dispose(self) -> None:
61         pass
62 
63     @abstractmethod
64     async def wait_until_stopped(self) -> None:
65         pass
66 
67     @abstractmethod
68     async def connect(self) -> None:
69         pass
70 
71     @abstractmethod
72     async def run(self) -> None:
73         pass
74 
75     @abstractmethod
76     def send(self, message: Dict) -> None:
77         pass
78 
79     def serialize_message(self, message: Dict) -> bytes:
80         msg = json.dumps(message)
81         if "DEBUGP" in os.environ:  # pragma: no cover
82             print("\x1b[32mSEND>\x1b[0m", json.dumps(message, indent=2))
83         return msg.encode()
84 
85     def deserialize_message(self, data: Union[str, bytes]) -> ParsedMessagePayload:
86         obj = json.loads(data)
87 
88         if "DEBUGP" in os.environ:  # pragma: no cover
89             print("\x1b[33mRECV>\x1b[0m", json.dumps(obj, indent=2))
90         return obj
91 
92 
93 class PipeTransport(Transport):
94     def __init__(
95         self, loop: asyncio.AbstractEventLoop, driver_executable: Path
96     ) -> None:
97         super().__init__(loop)
98         self._stopped = False
99         self._driver_executable = driver_executable
100 
101     def request_stop(self) -> None:
102         assert self._output
103         self._stopped = True
104         self._output.close()
105 
106     async def wait_until_stopped(self) -> None:
107         await self._stopped_future
108         await self._proc.wait()
109 
110     async def connect(self) -> None:
111         self._stopped_future: asyncio.Future = asyncio.Future()
112         # Hide the command-line window on Windows when using Pythonw.exe
113         creationflags = 0
114         if sys.platform == "win32" and sys.stdout is None:
115             creationflags = subprocess.CREATE_NO_WINDOW
116 
117         try:
118             # For pyinstaller
119             env = os.environ.copy()
120             if getattr(sys, "frozen", False):
121                 env.setdefault("PLAYWRIGHT_BROWSERS_PATH", "0")
122 
123             self._proc = await asyncio.create_subprocess_exec(
124                 str(self._driver_executable),
125                 "run-driver",
126                 stdin=asyncio.subprocess.PIPE,
127                 stdout=asyncio.subprocess.PIPE,
128                 stderr=_get_stderr_fileno(),
129                 limit=32768,
130                 creationflags=creationflags,
131                 env=env,
132             )
133         except Exception as exc:
134             self.on_error_future.set_exception(exc)
135             raise exc
136 
137         self._output = self._proc.stdin
138 
139     async def run(self) -> None:
140         assert self._proc.stdout
141         assert self._proc.stdin
142         while not self._stopped:
143             try:
144                 buffer = await self._proc.stdout.readexactly(4)
145                 length = int.from_bytes(buffer, byteorder="little", signed=False)
146                 buffer = bytes(0)
147                 while length:
148                     to_read = min(length, 32768)
149                     data = await self._proc.stdout.readexactly(to_read)
150                     length -= to_read
151                     if len(buffer):
152                         buffer = buffer + data
153                     else:
154                         buffer = data
155 
156                 obj = self.deserialize_message(buffer)
157                 self.on_message(obj)
158             except asyncio.IncompleteReadError:
159                 break
160             await asyncio.sleep(0)
161         self._stopped_future.set_result(None)
162 
163     def send(self, message: Dict) -> None:
164         assert self._output
165         data = self.serialize_message(message)
166         self._output.write(
167             len(data).to_bytes(4, byteorder="little", signed=False) + data
168         )
169 
170 
171 class WebSocketTransport(AsyncIOEventEmitter, Transport):
172     def __init__(
173         self,
174         loop: asyncio.AbstractEventLoop,
175         ws_endpoint: str,
176         headers: Dict[str, str] = None,
177         slow_mo: float = None,
178     ) -> None:
179         super().__init__(loop)
180         Transport.__init__(self, loop)
181 
182         self._stopped = False
183         self.ws_endpoint = ws_endpoint
184         self.headers = headers
185         self.slow_mo = slow_mo
186 
187     def request_stop(self) -> None:
188         self._stopped = True
189         self.emit("close")
190         self._loop.create_task(self._connection.close())
191 
192     def dispose(self) -> None:
193         self.on_error_future.cancel()
194 
195     async def wait_until_stopped(self) -> None:
196         await self._connection.wait_closed()
197 
198     async def connect(self) -> None:
199         try:
200             self._connection = await websocket_connect(
201                 self.ws_endpoint, extra_headers=self.headers
202             )
203         except Exception as exc:
204             self.on_error_future.set_exception(Error(f"websocket.connect: {str(exc)}"))
205             raise exc
206 
207     async def run(self) -> None:
208         while not self._stopped:
209             try:
210                 message = await self._connection.recv()
211                 if self.slow_mo is not None:
212                     await asyncio.sleep(self.slow_mo / 1000)
213                 if self._stopped:
214                     self.on_error_future.set_exception(
215                         Error("Playwright connection closed")
216                     )
217                     break
218                 obj = self.deserialize_message(message)
219                 self.on_message(obj)
220             except (
221                 websockets.exceptions.ConnectionClosed,
222                 websockets.exceptions.ConnectionClosedError,
223             ):
224                 if not self._stopped:
225                     self.emit("close")
226                 self.on_error_future.set_exception(
227                     Error("Playwright connection closed")
228                 )
229                 break
230             except Exception as exc:
231                 self.on_error_future.set_exception(exc)
232                 break
233 
234     def send(self, message: Dict) -> None:
235         if self._stopped or (hasattr(self, "_connection") and self._connection.closed):
236             raise Error("Playwright connection closed")
237         data = self.serialize_message(message)
238         self._loop.create_task(self._connection.send(data))
239
```

Path: `playwright/_impl/_driver.py`
Content:
```
1 # Copyright (c) Microsoft Corporation.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 import asyncio
16 import inspect
17 import sys
18 from pathlib import Path
19 
20 import playwright
21 
22 
23 def compute_driver_executable() -> Path:
24     package_path = Path(inspect.getfile(playwright)).parent
25     platform = sys.platform
26     if platform == "win32":
27         return package_path / "driver" / "playwright.cmd"
28     return package_path / "driver" / "playwright.sh"
29 
30 
31 if sys.version_info.major == 3 and sys.version_info.minor == 7:
32     if sys.platform == "win32":
33         # Use ProactorEventLoop in 3.7, which is default in 3.8
34         asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
35     else:
36         # Prevent Python 3.7 from throwing on Linux:
37         # RuntimeError: Cannot add child handler, the child watcher does not have a loop attached
38         asyncio.get_event_loop()
39         try:
40             asyncio.get_child_watcher()
41         except Exception:
42             # uvloop does not support child watcher
43             # see https://github.com/microsoft/playwright-python/issues/582
44             pass
45
```

Path: `playwright/__main__.py`
Content:
```
1 # Copyright (c) Microsoft Corporation.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 import os
16 import subprocess
17 import sys
18 
19 from playwright._impl._driver import compute_driver_executable
20 from playwright._repo_version import version
21 
22 
23 def main() -> None:
24     driver_executable = compute_driver_executable()
25     env = os.environ.copy()
26     env["PW_CLI_TARGET_LANG"] = "python"
27     env["PW_CLI_DISPLAY_VERSION"] = version
28     completed_process = subprocess.run([str(driver_executable), *sys.argv[1:]], env=env)
29     sys.exit(completed_process.returncode)
30 
31 
32 if __name__ == "__main__":
33     main()
34
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/playwright/__main__.py b/playwright/__main__.py
--- a/playwright/__main__.py
+++ b/playwright/__main__.py
@@ -12,20 +12,17 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import os
 import subprocess
 import sys
 
-from playwright._impl._driver import compute_driver_executable
-from playwright._repo_version import version
+from playwright._impl._driver import compute_driver_executable, get_driver_env
 
 
 def main() -> None:
     driver_executable = compute_driver_executable()
-    env = os.environ.copy()
-    env["PW_CLI_TARGET_LANG"] = "python"
-    env["PW_CLI_DISPLAY_VERSION"] = version
-    completed_process = subprocess.run([str(driver_executable), *sys.argv[1:]], env=env)
+    completed_process = subprocess.run(
+        [str(driver_executable), *sys.argv[1:]], env=get_driver_env()
+    )
     sys.exit(completed_process.returncode)
 
 
diff --git a/playwright/_impl/_driver.py b/playwright/_impl/_driver.py
--- a/playwright/_impl/_driver.py
+++ b/playwright/_impl/_driver.py
@@ -14,10 +14,12 @@
 
 import asyncio
 import inspect
+import os
 import sys
 from pathlib import Path
 
 import playwright
+from playwright._repo_version import version
 
 
 def compute_driver_executable() -> Path:
@@ -42,3 +44,13 @@
             # uvloop does not support child watcher
             # see https://github.com/microsoft/playwright-python/issues/582
             pass
+
+
+def get_driver_env() -> dict:
+    env = os.environ.copy()
+    env["PW_CLI_TARGET_LANG"] = "python"
+    env[
+        "PW_CLI_TARGET_LANG_VERSION"
+    ] = f"{sys.version_info.major}.{sys.version_info.minor}"
+    env["PW_CLI_DISPLAY_VERSION"] = version
+    return env
diff --git a/playwright/_impl/_transport.py b/playwright/_impl/_transport.py
--- a/playwright/_impl/_transport.py
+++ b/playwright/_impl/_transport.py
@@ -28,6 +28,7 @@
 from websockets.client import connect as websocket_connect
 
 from playwright._impl._api_types import Error
+from playwright._impl._driver import get_driver_env
 from playwright._impl._helper import ParsedMessagePayload
 
 
@@ -116,7 +117,7 @@
 
         try:
             # For pyinstaller
-            env = os.environ.copy()
+            env = get_driver_env()
             if getattr(sys, "frozen", False):
                 env.setdefault("PLAYWRIGHT_BROWSERS_PATH", "0")

{"golden_diff": "diff --git a/playwright/__main__.py b/playwright/__main__.py\n--- a/playwright/__main__.py\n+++ b/playwright/__main__.py\n@@ -12,20 +12,17 @@\n # See the License for the specific language governing permissions and\n # limitations under the License.\n \n-import os\n import subprocess\n import sys\n \n-from playwright._impl._driver import compute_driver_executable\n-from playwright._repo_version import version\n+from playwright._impl._driver import compute_driver_executable, get_driver_env\n \n \n def main() -> None:\n     driver_executable = compute_driver_executable()\n-    env = os.environ.copy()\n-    env[\"PW_CLI_TARGET_LANG\"] = \"python\"\n-    env[\"PW_CLI_DISPLAY_VERSION\"] = version\n-    completed_process = subprocess.run([str(driver_executable), *sys.argv[1:]], env=env)\n+    completed_process = subprocess.run(\n+        [str(driver_executable), *sys.argv[1:]], env=get_driver_env()\n+    )\n     sys.exit(completed_process.returncode)\n \n \ndiff --git a/playwright/_impl/_driver.py b/playwright/_impl/_driver.py\n--- a/playwright/_impl/_driver.py\n+++ b/playwright/_impl/_driver.py\n@@ -14,10 +14,12 @@\n \n import asyncio\n import inspect\n+import os\n import sys\n from pathlib import Path\n \n import playwright\n+from playwright._repo_version import version\n \n \n def compute_driver_executable() -> Path:\n@@ -42,3 +44,13 @@\n             # uvloop does not support child watcher\n             # see https://github.com/microsoft/playwright-python/issues/582\n             pass\n+\n+\n+def get_driver_env() -> dict:\n+    env = os.environ.copy()\n+    env[\"PW_CLI_TARGET_LANG\"] = \"python\"\n+    env[\n+        \"PW_CLI_TARGET_LANG_VERSION\"\n+    ] = f\"{sys.version_info.major}.{sys.version_info.minor}\"\n+    env[\"PW_CLI_DISPLAY_VERSION\"] = version\n+    return env\ndiff --git a/playwright/_impl/_transport.py b/playwright/_impl/_transport.py\n--- a/playwright/_impl/_transport.py\n+++ b/playwright/_impl/_transport.py\n@@ -28,6 +28,7 @@\n from websockets.client import connect as websocket_connect\n \n from playwright._impl._api_types import Error\n+from playwright._impl._driver import get_driver_env\n from playwright._impl._helper import ParsedMessagePayload\n \n \n@@ -116,7 +117,7 @@\n \n         try:\n             # For pyinstaller\n-            env = os.environ.copy()\n+            env = get_driver_env()\n             if getattr(sys, \"frozen\", False):\n                 env.setdefault(\"PLAYWRIGHT_BROWSERS_PATH\", \"0\")\n", "issue": "internal: setup env variables when launching driver\n1.18 driver assumes the following environment variables are set:\r\n\r\n```\r\nPW_CLI_TARGET_LANG=python\r\nPW_CLI_TARGET_LANG_VERSION=<version>\r\nPW_CLI_DISPLAY_VERSION=CLI_VERSION (of the language)\r\n```\r\n\r\n`version` should not be too granular to avoid noise; IMO major + minor seems to be good for Python.\n", "before_files": [{"content": "# Copyright (c) Microsoft Corporation.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport asyncio\nimport io\nimport json\nimport os\nimport subprocess\nimport sys\nfrom abc import ABC, abstractmethod\nfrom pathlib import Path\nfrom typing import Callable, Dict, Optional, Union\n\nimport websockets\nimport websockets.exceptions\nfrom pyee import AsyncIOEventEmitter\nfrom websockets.client import connect as websocket_connect\n\nfrom playwright._impl._api_types import Error\nfrom playwright._impl._helper import ParsedMessagePayload\n\n\n# Sourced from: https://github.com/pytest-dev/pytest/blob/da01ee0a4bb0af780167ecd228ab3ad249511302/src/_pytest/faulthandler.py#L69-L77\ndef _get_stderr_fileno() -> Optional[int]:\n    if sys.stderr.closed:\n        return None\n\n    try:\n        return sys.stderr.fileno()\n    except (AttributeError, io.UnsupportedOperation):\n        # pytest-xdist monkeypatches sys.stderr with an object that is not an actual file.\n        # https://docs.python.org/3/library/faulthandler.html#issue-with-file-descriptors\n        # This is potentially dangerous, but the best we can do.\n        if not hasattr(sys, \"__stderr__\") or not sys.__stderr__:\n            return None\n        return sys.__stderr__.fileno()\n\n\nclass Transport(ABC):\n    def __init__(self, loop: asyncio.AbstractEventLoop) -> None:\n        self._loop = loop\n        self.on_message: Callable[[ParsedMessagePayload], None] = lambda _: None\n        self.on_error_future: asyncio.Future = loop.create_future()\n\n    @abstractmethod\n    def request_stop(self) -> None:\n        pass\n\n    def dispose(self) -> None:\n        pass\n\n    @abstractmethod\n    async def wait_until_stopped(self) -> None:\n        pass\n\n    @abstractmethod\n    async def connect(self) -> None:\n        pass\n\n    @abstractmethod\n    async def run(self) -> None:\n        pass\n\n    @abstractmethod\n    def send(self, message: Dict) -> None:\n        pass\n\n    def serialize_message(self, message: Dict) -> bytes:\n        msg = json.dumps(message)\n        if \"DEBUGP\" in os.environ:  # pragma: no cover\n            print(\"\\x1b[32mSEND>\\x1b[0m\", json.dumps(message, indent=2))\n        return msg.encode()\n\n    def deserialize_message(self, data: Union[str, bytes]) -> ParsedMessagePayload:\n        obj = json.loads(data)\n\n        if \"DEBUGP\" in os.environ:  # pragma: no cover\n            print(\"\\x1b[33mRECV>\\x1b[0m\", json.dumps(obj, indent=2))\n        return obj\n\n\nclass PipeTransport(Transport):\n    def __init__(\n        self, loop: asyncio.AbstractEventLoop, driver_executable: Path\n    ) -> None:\n        super().__init__(loop)\n        self._stopped = False\n        self._driver_executable = driver_executable\n\n    def request_stop(self) -> None:\n        assert self._output\n        self._stopped = True\n        self._output.close()\n\n    async def wait_until_stopped(self) -> None:\n        await self._stopped_future\n        await self._proc.wait()\n\n    async def connect(self) -> None:\n        self._stopped_future: asyncio.Future = asyncio.Future()\n        # Hide the command-line window on Windows when using Pythonw.exe\n        creationflags = 0\n        if sys.platform == \"win32\" and sys.stdout is None:\n            creationflags = subprocess.CREATE_NO_WINDOW\n\n        try:\n            # For pyinstaller\n            env = os.environ.copy()\n            if getattr(sys, \"frozen\", False):\n                env.setdefault(\"PLAYWRIGHT_BROWSERS_PATH\", \"0\")\n\n            self._proc = await asyncio.create_subprocess_exec(\n                str(self._driver_executable),\n                \"run-driver\",\n                stdin=asyncio.subprocess.PIPE,\n                stdout=asyncio.subprocess.PIPE,\n                stderr=_get_stderr_fileno(),\n                limit=32768,\n                creationflags=creationflags,\n                env=env,\n            )\n        except Exception as exc:\n            self.on_error_future.set_exception(exc)\n            raise exc\n\n        self._output = self._proc.stdin\n\n    async def run(self) -> None:\n        assert self._proc.stdout\n        assert self._proc.stdin\n        while not self._stopped:\n            try:\n                buffer = await self._proc.stdout.readexactly(4)\n                length = int.from_bytes(buffer, byteorder=\"little\", signed=False)\n                buffer = bytes(0)\n                while length:\n                    to_read = min(length, 32768)\n                    data = await self._proc.stdout.readexactly(to_read)\n                    length -= to_read\n                    if len(buffer):\n                        buffer = buffer + data\n                    else:\n                        buffer = data\n\n                obj = self.deserialize_message(buffer)\n                self.on_message(obj)\n            except asyncio.IncompleteReadError:\n                break\n            await asyncio.sleep(0)\n        self._stopped_future.set_result(None)\n\n    def send(self, message: Dict) -> None:\n        assert self._output\n        data = self.serialize_message(message)\n        self._output.write(\n            len(data).to_bytes(4, byteorder=\"little\", signed=False) + data\n        )\n\n\nclass WebSocketTransport(AsyncIOEventEmitter, Transport):\n    def __init__(\n        self,\n        loop: asyncio.AbstractEventLoop,\n        ws_endpoint: str,\n        headers: Dict[str, str] = None,\n        slow_mo: float = None,\n    ) -> None:\n        super().__init__(loop)\n        Transport.__init__(self, loop)\n\n        self._stopped = False\n        self.ws_endpoint = ws_endpoint\n        self.headers = headers\n        self.slow_mo = slow_mo\n\n    def request_stop(self) -> None:\n        self._stopped = True\n        self.emit(\"close\")\n        self._loop.create_task(self._connection.close())\n\n    def dispose(self) -> None:\n        self.on_error_future.cancel()\n\n    async def wait_until_stopped(self) -> None:\n        await self._connection.wait_closed()\n\n    async def connect(self) -> None:\n        try:\n            self._connection = await websocket_connect(\n                self.ws_endpoint, extra_headers=self.headers\n            )\n        except Exception as exc:\n            self.on_error_future.set_exception(Error(f\"websocket.connect: {str(exc)}\"))\n            raise exc\n\n    async def run(self) -> None:\n        while not self._stopped:\n            try:\n                message = await self._connection.recv()\n                if self.slow_mo is not None:\n                    await asyncio.sleep(self.slow_mo / 1000)\n                if self._stopped:\n                    self.on_error_future.set_exception(\n                        Error(\"Playwright connection closed\")\n                    )\n                    break\n                obj = self.deserialize_message(message)\n                self.on_message(obj)\n            except (\n                websockets.exceptions.ConnectionClosed,\n                websockets.exceptions.ConnectionClosedError,\n            ):\n                if not self._stopped:\n                    self.emit(\"close\")\n                self.on_error_future.set_exception(\n                    Error(\"Playwright connection closed\")\n                )\n                break\n            except Exception as exc:\n                self.on_error_future.set_exception(exc)\n                break\n\n    def send(self, message: Dict) -> None:\n        if self._stopped or (hasattr(self, \"_connection\") and self._connection.closed):\n            raise Error(\"Playwright connection closed\")\n        data = self.serialize_message(message)\n        self._loop.create_task(self._connection.send(data))\n", "path": "playwright/_impl/_transport.py"}, {"content": "# Copyright (c) Microsoft Corporation.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport asyncio\nimport inspect\nimport sys\nfrom pathlib import Path\n\nimport playwright\n\n\ndef compute_driver_executable() -> Path:\n    package_path = Path(inspect.getfile(playwright)).parent\n    platform = sys.platform\n    if platform == \"win32\":\n        return package_path / \"driver\" / \"playwright.cmd\"\n    return package_path / \"driver\" / \"playwright.sh\"\n\n\nif sys.version_info.major == 3 and sys.version_info.minor == 7:\n    if sys.platform == \"win32\":\n        # Use ProactorEventLoop in 3.7, which is default in 3.8\n        asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())\n    else:\n        # Prevent Python 3.7 from throwing on Linux:\n        # RuntimeError: Cannot add child handler, the child watcher does not have a loop attached\n        asyncio.get_event_loop()\n        try:\n            asyncio.get_child_watcher()\n        except Exception:\n            # uvloop does not support child watcher\n            # see https://github.com/microsoft/playwright-python/issues/582\n            pass\n", "path": "playwright/_impl/_driver.py"}, {"content": "# Copyright (c) Microsoft Corporation.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport os\nimport subprocess\nimport sys\n\nfrom playwright._impl._driver import compute_driver_executable\nfrom playwright._repo_version import version\n\n\ndef main() -> None:\n    driver_executable = compute_driver_executable()\n    env = os.environ.copy()\n    env[\"PW_CLI_TARGET_LANG\"] = \"python\"\n    env[\"PW_CLI_DISPLAY_VERSION\"] = version\n    completed_process = subprocess.run([str(driver_executable), *sys.argv[1:]], env=env)\n    sys.exit(completed_process.returncode)\n\n\nif __name__ == \"__main__\":\n    main()\n", "path": "playwright/__main__.py"}], "after_files": [{"content": "# Copyright (c) Microsoft Corporation.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport asyncio\nimport io\nimport json\nimport os\nimport subprocess\nimport sys\nfrom abc import ABC, abstractmethod\nfrom pathlib import Path\nfrom typing import Callable, Dict, Optional, Union\n\nimport websockets\nimport websockets.exceptions\nfrom pyee import AsyncIOEventEmitter\nfrom websockets.client import connect as websocket_connect\n\nfrom playwright._impl._api_types import Error\nfrom playwright._impl._driver import get_driver_env\nfrom playwright._impl._helper import ParsedMessagePayload\n\n\n# Sourced from: https://github.com/pytest-dev/pytest/blob/da01ee0a4bb0af780167ecd228ab3ad249511302/src/_pytest/faulthandler.py#L69-L77\ndef _get_stderr_fileno() -> Optional[int]:\n    if sys.stderr.closed:\n        return None\n\n    try:\n        return sys.stderr.fileno()\n    except (AttributeError, io.UnsupportedOperation):\n        # pytest-xdist monkeypatches sys.stderr with an object that is not an actual file.\n        # https://docs.python.org/3/library/faulthandler.html#issue-with-file-descriptors\n        # This is potentially dangerous, but the best we can do.\n        if not hasattr(sys, \"__stderr__\") or not sys.__stderr__:\n            return None\n        return sys.__stderr__.fileno()\n\n\nclass Transport(ABC):\n    def __init__(self, loop: asyncio.AbstractEventLoop) -> None:\n        self._loop = loop\n        self.on_message: Callable[[ParsedMessagePayload], None] = lambda _: None\n        self.on_error_future: asyncio.Future = loop.create_future()\n\n    @abstractmethod\n    def request_stop(self) -> None:\n        pass\n\n    def dispose(self) -> None:\n        pass\n\n    @abstractmethod\n    async def wait_until_stopped(self) -> None:\n        pass\n\n    @abstractmethod\n    async def connect(self) -> None:\n        pass\n\n    @abstractmethod\n    async def run(self) -> None:\n        pass\n\n    @abstractmethod\n    def send(self, message: Dict) -> None:\n        pass\n\n    def serialize_message(self, message: Dict) -> bytes:\n        msg = json.dumps(message)\n        if \"DEBUGP\" in os.environ:  # pragma: no cover\n            print(\"\\x1b[32mSEND>\\x1b[0m\", json.dumps(message, indent=2))\n        return msg.encode()\n\n    def deserialize_message(self, data: Union[str, bytes]) -> ParsedMessagePayload:\n        obj = json.loads(data)\n\n        if \"DEBUGP\" in os.environ:  # pragma: no cover\n            print(\"\\x1b[33mRECV>\\x1b[0m\", json.dumps(obj, indent=2))\n        return obj\n\n\nclass PipeTransport(Transport):\n    def __init__(\n        self, loop: asyncio.AbstractEventLoop, driver_executable: Path\n    ) -> None:\n        super().__init__(loop)\n        self._stopped = False\n        self._driver_executable = driver_executable\n\n    def request_stop(self) -> None:\n        assert self._output\n        self._stopped = True\n        self._output.close()\n\n    async def wait_until_stopped(self) -> None:\n        await self._stopped_future\n        await self._proc.wait()\n\n    async def connect(self) -> None:\n        self._stopped_future: asyncio.Future = asyncio.Future()\n        # Hide the command-line window on Windows when using Pythonw.exe\n        creationflags = 0\n        if sys.platform == \"win32\" and sys.stdout is None:\n            creationflags = subprocess.CREATE_NO_WINDOW\n\n        try:\n            # For pyinstaller\n            env = get_driver_env()\n            if getattr(sys, \"frozen\", False):\n                env.setdefault(\"PLAYWRIGHT_BROWSERS_PATH\", \"0\")\n\n            self._proc = await asyncio.create_subprocess_exec(\n                str(self._driver_executable),\n                \"run-driver\",\n                stdin=asyncio.subprocess.PIPE,\n                stdout=asyncio.subprocess.PIPE,\n                stderr=_get_stderr_fileno(),\n                limit=32768,\n                creationflags=creationflags,\n                env=env,\n            )\n        except Exception as exc:\n            self.on_error_future.set_exception(exc)\n            raise exc\n\n        self._output = self._proc.stdin\n\n    async def run(self) -> None:\n        assert self._proc.stdout\n        assert self._proc.stdin\n        while not self._stopped:\n            try:\n                buffer = await self._proc.stdout.readexactly(4)\n                length = int.from_bytes(buffer, byteorder=\"little\", signed=False)\n                buffer = bytes(0)\n                while length:\n                    to_read = min(length, 32768)\n                    data = await self._proc.stdout.readexactly(to_read)\n                    length -= to_read\n                    if len(buffer):\n                        buffer = buffer + data\n                    else:\n                        buffer = data\n\n                obj = self.deserialize_message(buffer)\n                self.on_message(obj)\n            except asyncio.IncompleteReadError:\n                break\n            await asyncio.sleep(0)\n        self._stopped_future.set_result(None)\n\n    def send(self, message: Dict) -> None:\n        assert self._output\n        data = self.serialize_message(message)\n        self._output.write(\n            len(data).to_bytes(4, byteorder=\"little\", signed=False) + data\n        )\n\n\nclass WebSocketTransport(AsyncIOEventEmitter, Transport):\n    def __init__(\n        self,\n        loop: asyncio.AbstractEventLoop,\n        ws_endpoint: str,\n        headers: Dict[str, str] = None,\n        slow_mo: float = None,\n    ) -> None:\n        super().__init__(loop)\n        Transport.__init__(self, loop)\n\n        self._stopped = False\n        self.ws_endpoint = ws_endpoint\n        self.headers = headers\n        self.slow_mo = slow_mo\n\n    def request_stop(self) -> None:\n        self._stopped = True\n        self.emit(\"close\")\n        self._loop.create_task(self._connection.close())\n\n    def dispose(self) -> None:\n        self.on_error_future.cancel()\n\n    async def wait_until_stopped(self) -> None:\n        await self._connection.wait_closed()\n\n    async def connect(self) -> None:\n        try:\n            self._connection = await websocket_connect(\n                self.ws_endpoint, extra_headers=self.headers\n            )\n        except Exception as exc:\n            self.on_error_future.set_exception(Error(f\"websocket.connect: {str(exc)}\"))\n            raise exc\n\n    async def run(self) -> None:\n        while not self._stopped:\n            try:\n                message = await self._connection.recv()\n                if self.slow_mo is not None:\n                    await asyncio.sleep(self.slow_mo / 1000)\n                if self._stopped:\n                    self.on_error_future.set_exception(\n                        Error(\"Playwright connection closed\")\n                    )\n                    break\n                obj = self.deserialize_message(message)\n                self.on_message(obj)\n            except (\n                websockets.exceptions.ConnectionClosed,\n                websockets.exceptions.ConnectionClosedError,\n            ):\n                if not self._stopped:\n                    self.emit(\"close\")\n                self.on_error_future.set_exception(\n                    Error(\"Playwright connection closed\")\n                )\n                break\n            except Exception as exc:\n                self.on_error_future.set_exception(exc)\n                break\n\n    def send(self, message: Dict) -> None:\n        if self._stopped or (hasattr(self, \"_connection\") and self._connection.closed):\n            raise Error(\"Playwright connection closed\")\n        data = self.serialize_message(message)\n        self._loop.create_task(self._connection.send(data))\n", "path": "playwright/_impl/_transport.py"}, {"content": "# Copyright (c) Microsoft Corporation.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport asyncio\nimport inspect\nimport os\nimport sys\nfrom pathlib import Path\n\nimport playwright\nfrom playwright._repo_version import version\n\n\ndef compute_driver_executable() -> Path:\n    package_path = Path(inspect.getfile(playwright)).parent\n    platform = sys.platform\n    if platform == \"win32\":\n        return package_path / \"driver\" / \"playwright.cmd\"\n    return package_path / \"driver\" / \"playwright.sh\"\n\n\nif sys.version_info.major == 3 and sys.version_info.minor == 7:\n    if sys.platform == \"win32\":\n        # Use ProactorEventLoop in 3.7, which is default in 3.8\n        asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())\n    else:\n        # Prevent Python 3.7 from throwing on Linux:\n        # RuntimeError: Cannot add child handler, the child watcher does not have a loop attached\n        asyncio.get_event_loop()\n        try:\n            asyncio.get_child_watcher()\n        except Exception:\n            # uvloop does not support child watcher\n            # see https://github.com/microsoft/playwright-python/issues/582\n            pass\n\n\ndef get_driver_env() -> dict:\n    env = os.environ.copy()\n    env[\"PW_CLI_TARGET_LANG\"] = \"python\"\n    env[\n        \"PW_CLI_TARGET_LANG_VERSION\"\n    ] = f\"{sys.version_info.major}.{sys.version_info.minor}\"\n    env[\"PW_CLI_DISPLAY_VERSION\"] = version\n    return env\n", "path": "playwright/_impl/_driver.py"}, {"content": "# Copyright (c) Microsoft Corporation.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport subprocess\nimport sys\n\nfrom playwright._impl._driver import compute_driver_executable, get_driver_env\n\n\ndef main() -> None:\n    driver_executable = compute_driver_executable()\n    completed_process = subprocess.run(\n        [str(driver_executable), *sys.argv[1:]], env=get_driver_env()\n    )\n    sys.exit(completed_process.returncode)\n\n\nif __name__ == \"__main__\":\n    main()\n", "path": "playwright/__main__.py"}]}