1- # Licensed to the Software Freedom Conservancy (SFC) under one
2- # or more contributor license agreements. See the NOTICE file
3- # distributed with this work for additional information
4- # regarding copyright ownership. The SFC licenses this file
5- # to you under the Apache License, Version 2.0 (the
6- # "License"); you may not use this file except in compliance
7- # with the License. You may obtain a copy of the License at
1+ # The MIT License(MIT)
82#
9- # http://www.apache.org/licenses/LICENSE-2.0
3+ # Copyright(c) 2018 Hyperion Gray
104#
11- # Unless required by applicable law or agreed to in writing,
12- # software distributed under the License is distributed on an
13- # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14- # KIND, either express or implied. See the License for the
15- # specific language governing permissions and limitations
16- # under the License.
17-
5+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6+ # of this software and associated documentation files(the "Software"), to deal
7+ # in the Software without restriction, including without limitation the rights
8+ # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
9+ # copies of the Software, and to permit persons to whom the Software is
10+ # furnished to do so, subject to the following conditions:
11+ #
12+ # The above copyright notice and this permission notice shall be included in
13+ # all copies or substantial portions of the Software.
14+ #
15+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+ # THE SOFTWARE.
22+ #
23+ # This code comes from https://github.com/HyperionGray/trio-chrome-devtools-protocol/tree/master/trio_cdp
1824
1925import contextvars
2026import importlib
@@ -54,7 +60,11 @@ def import_devtools(ver):
5460 # because cdp has been updated but selenium python has not been released yet.
5561 devtools_path = pathlib .Path (__file__ ).parents [1 ].joinpath ("devtools" )
5662 versions = tuple (f .name for f in devtools_path .iterdir () if f .is_dir ())
57- available_versions = tuple (x for x in versions if x == "latest" or (x .startswith ("v" ) and x [1 :].isdigit ()))
63+ available_versions = tuple (
64+ x
65+ for x in versions
66+ if x == "latest" or (x .startswith ("v" ) and x [1 :].isdigit ())
67+ )
5868 numeric_versions = tuple (x [1 :] for x in available_versions if x .startswith ("v" ))
5969 if not numeric_versions :
6070 raise
@@ -65,7 +75,9 @@ def import_devtools(ver):
6575 return devtools
6676
6777
68- _connection_context : contextvars .ContextVar = contextvars .ContextVar ("connection_context" )
78+ _connection_context : contextvars .ContextVar = contextvars .ContextVar (
79+ "connection_context"
80+ )
6981_session_context : contextvars .ContextVar = contextvars .ContextVar ("session_context" )
7082
7183
@@ -120,7 +132,9 @@ def set_global_connection(connection):
120132 certain use cases such as running inside Jupyter notebook.
121133 """
122134 global _connection_context
123- _connection_context = contextvars .ContextVar ("_connection_context" , default = connection )
135+ _connection_context = contextvars .ContextVar (
136+ "_connection_context" , default = connection
137+ )
124138
125139
126140def set_global_session (session ):
@@ -217,7 +231,9 @@ async def execute(self, cmd: Generator[dict, T, Any]) -> T:
217231 logger .debug (f"Received CDP message: { response } " )
218232 if isinstance (response , Exception ):
219233 if logger .isEnabledFor (logging .DEBUG ):
220- logger .debug (f"Exception raised by { cmd_event } message: { type (response ).__name__ } " )
234+ logger .debug (
235+ f"Exception raised by { cmd_event } message: { type (response ).__name__ } "
236+ )
221237 raise response
222238 return response
223239
@@ -233,7 +249,9 @@ def listen(self, *event_types, buffer_size=10):
233249 return receiver
234250
235251 @asynccontextmanager
236- async def wait_for (self , event_type : type [T ], buffer_size = 10 ) -> AsyncGenerator [CmEventProxy , None ]:
252+ async def wait_for (
253+ self , event_type : type [T ], buffer_size = 10
254+ ) -> AsyncGenerator [CmEventProxy , None ]:
237255 """Wait for an event of the given type and return it.
238256
239257 This is an async context manager, so you should open it inside
@@ -274,7 +292,9 @@ def _handle_cmd_response(self, data: dict):
274292 try :
275293 cmd , event = self .inflight_cmd .pop (cmd_id )
276294 except KeyError :
277- logger .warning ("Got a message with a command ID that does not exist: %s" , data )
295+ logger .warning (
296+ "Got a message with a command ID that does not exist: %s" , data
297+ )
278298 return
279299 if "error" in data :
280300 # If the server reported an error, convert it to an exception and do
@@ -285,7 +305,9 @@ def _handle_cmd_response(self, data: dict):
285305 # into a CDP object.
286306 try :
287307 _ = cmd .send (data ["result" ])
288- raise InternalError ("The command's generator function did not exit when expected!" )
308+ raise InternalError (
309+ "The command's generator function did not exit when expected!"
310+ )
289311 except StopIteration as exit :
290312 return_ = exit .value
291313 self .inflight_result [cmd_id ] = return_
@@ -299,15 +321,19 @@ def _handle_event(self, data: dict):
299321 """
300322 global devtools
301323 if devtools is None :
302- raise RuntimeError ("CDP devtools module not loaded. Call import_devtools() first." )
324+ raise RuntimeError (
325+ "CDP devtools module not loaded. Call import_devtools() first."
326+ )
303327 event = devtools .util .parse_json_event (data )
304328 logger .debug ("Received event: %s" , event )
305329 to_remove = set ()
306330 for sender in self .channels [type (event )]:
307331 try :
308332 sender .send_nowait (event )
309333 except trio .WouldBlock :
310- logger .error ('Unable to send event "%r" due to full channel %s' , event , sender )
334+ logger .error (
335+ 'Unable to send event "%r" due to full channel %s' , event , sender
336+ )
311337 except trio .BrokenResourceError :
312338 to_remove .add (sender )
313339 if to_remove :
@@ -425,8 +451,12 @@ async def connect_session(self, target_id) -> "CdpSession":
425451 """Returns a new :class:`CdpSession` connected to the specified target."""
426452 global devtools
427453 if devtools is None :
428- raise RuntimeError ("CDP devtools module not loaded. Call import_devtools() first." )
429- session_id = await self .execute (devtools .target .attach_to_target (target_id , True ))
454+ raise RuntimeError (
455+ "CDP devtools module not loaded. Call import_devtools() first."
456+ )
457+ session_id = await self .execute (
458+ devtools .target .attach_to_target (target_id , True )
459+ )
430460 session = CdpSession (self .ws , session_id , target_id )
431461 self .sessions [session_id ] = session
432462 return session
@@ -438,7 +468,9 @@ async def _reader_task(self):
438468 """
439469 global devtools
440470 if devtools is None :
441- raise RuntimeError ("CDP devtools module not loaded. Call import_devtools() first." )
471+ raise RuntimeError (
472+ "CDP devtools module not loaded. Call import_devtools() first."
473+ )
442474 while True :
443475 try :
444476 message = await self .ws .get_message ()
@@ -451,7 +483,13 @@ async def _reader_task(self):
451483 try :
452484 data = json .loads (message )
453485 except json .JSONDecodeError :
454- raise BrowserError ({"code" : - 32700 , "message" : "Client received invalid JSON" , "data" : message })
486+ raise BrowserError (
487+ {
488+ "code" : - 32700 ,
489+ "message" : "Client received invalid JSON" ,
490+ "data" : message ,
491+ }
492+ )
455493 logger .debug ("Received message %r" , data )
456494 if "sessionId" in data :
457495 session_id = devtools .target .SessionID (data ["sessionId" ])
0 commit comments