22from __future__ import annotations
33import asyncio
44import atexit
5+ import fasteners
56import http .cookiejar
67import json
78import logging
1516import urllib .request
1617import warnings
1718from collections import defaultdict
19+ from contextlib import suppress
1820from seleniumbase import config as sb_config
21+ from seleniumbase .fixtures import constants
22+ from seleniumbase .fixtures import shared_utils
1923from typing import List , Optional , Set , Tuple , Union
2024import mycdp as cdp
2125from . import cdp_util as util
@@ -34,7 +38,7 @@ def get_registered_instances():
3438def deconstruct_browser ():
3539 for _ in __registered__instances__ :
3640 if not _ .stopped :
37- _ .stop ()
41+ _ .stop (deconstruct = True )
3842 for attempt in range (5 ):
3943 try :
4044 if _ .config and not _ .config .uses_custom_data_dir :
@@ -732,8 +736,11 @@ async def tile_windows(self, windows=None, max_columns: int = 0):
732736 try :
733737 import mss
734738 except Exception :
735- from seleniumbase .fixtures import shared_utils
736- shared_utils .pip_install ("mss" )
739+ pip_find_lock = fasteners .InterProcessLock (
740+ constants .PipInstall .FINDLOCK
741+ )
742+ with pip_find_lock : # Prevent issues with multiple processes
743+ shared_utils .pip_install ("mss" )
737744 import mss
738745 m = mss .mss ()
739746 screen , screen_width , screen_height = 3 * (None ,)
@@ -842,11 +849,17 @@ def __next__(self):
842849 else :
843850 del self ._i
844851
845- def stop (self ):
852+ def stop (self , deconstruct = False ):
853+ if (
854+ not hasattr (sb_config , "_closed_connection_ids" )
855+ or not isinstance (sb_config ._closed_connection_ids , list )
856+ ):
857+ sb_config ._closed_connection_ids = []
858+ connection_id = None
859+ with suppress (Exception ):
860+ connection_id = self .connection .websocket .id .hex
861+ close_success = False
846862 try :
847- # asyncio.get_running_loop().create_task(
848- # self.connection.send(cdp.browser.close())
849- # )
850863 if self .connection :
851864 asyncio .get_event_loop ().create_task (self .connection .aclose ())
852865 logger .debug (
@@ -855,19 +868,22 @@ def stop(self):
855868 except RuntimeError :
856869 if self .connection :
857870 try :
858- # asyncio.run(self.connection.send(cdp.browser.close()))
859871 asyncio .run (self .connection .aclose ())
860872 logger .debug ("Closed the connection using asyncio.run()" )
861873 except Exception :
862874 pass
863875 for _ in range (3 ):
864876 try :
865- self ._process .terminate ()
866- logger .debug (
867- "Terminated browser with pid %d successfully."
868- % self ._process .pid
869- )
870- break
877+ if connection_id not in sb_config ._closed_connection_ids :
878+ self ._process .terminate ()
879+ logger .debug (
880+ "Terminated browser with pid %d successfully."
881+ % self ._process .pid
882+ )
883+ if connection_id :
884+ sb_config ._closed_connection_ids .append (connection_id )
885+ close_success = True
886+ break
871887 except (Exception ,):
872888 try :
873889 self ._process .kill ()
@@ -902,6 +918,39 @@ def stop(self):
902918 raise
903919 self ._process = None
904920 self ._process_pid = None
921+ if (
922+ hasattr (sb_config , "_xvfb_users" )
923+ and isinstance (sb_config ._xvfb_users , int )
924+ and close_success
925+ and hasattr (sb_config , "_virtual_display" )
926+ and sb_config ._virtual_display
927+ ):
928+ sb_config ._xvfb_users -= 1
929+ if sb_config ._xvfb_users < 0 :
930+ sb_config ._xvfb_users = 0
931+ if (
932+ shared_utils .is_linux ()
933+ and (
934+ hasattr (sb_config , "_virtual_display" )
935+ and sb_config ._virtual_display
936+ and hasattr (sb_config ._virtual_display , "stop" )
937+ )
938+ and sb_config ._xvfb_users == 0
939+ ):
940+ try :
941+ sb_config ._virtual_display .stop ()
942+ sb_config ._virtual_display = None
943+ sb_config .headless_active = False
944+ except AttributeError :
945+ pass
946+ except Exception :
947+ pass
948+ if (
949+ deconstruct
950+ and connection_id
951+ and connection_id in sb_config ._closed_connection_ids
952+ ):
953+ sb_config ._closed_connection_ids .remove (connection_id )
905954
906955 def quit (self ):
907956 self .stop ()
0 commit comments