|
32 | 32 | from selenium.common.exceptions import WebDriverException |
33 | 33 | from selenium.types import SubprocessStdAlias |
34 | 34 | from selenium.webdriver.common import utils |
| 35 | +from selenium.webdriver.common.selenium_manager import SeleniumManager |
35 | 36 |
|
36 | | -log = logging.getLogger(__name__) |
| 37 | +logger = logging.getLogger(__name__) |
37 | 38 |
|
38 | 39 |
|
39 | 40 | _HAS_NATIVE_DEVNULL = True |
@@ -87,35 +88,21 @@ def start(self) -> None: |
87 | 88 | or when it can't connect to the service |
88 | 89 | """ |
89 | 90 | try: |
90 | | - cmd = [self.path] |
91 | | - cmd.extend(self.command_line_args()) |
92 | | - self.process = subprocess.Popen( |
93 | | - cmd, |
94 | | - env=self.env, |
95 | | - close_fds=system() != "Windows", |
96 | | - stdout=self.log_file, |
97 | | - stderr=self.log_file, |
98 | | - stdin=PIPE, |
99 | | - creationflags=self.creation_flags, |
100 | | - ) |
101 | | - log.debug(f"Started executable: `{self.path}` in a child process with pid: {self.process.pid}") |
102 | | - except TypeError: |
103 | | - raise |
104 | | - except OSError as err: |
105 | | - if err.errno == errno.ENOENT: |
106 | | - raise WebDriverException( |
107 | | - f"'{os.path.basename(self.path)}' executable needs to be in PATH. {self.start_error_message}" |
108 | | - ) |
109 | | - elif err.errno == errno.EACCES: |
110 | | - raise WebDriverException( |
111 | | - f"'{os.path.basename(self.path)}' executable may have wrong permissions. {self.start_error_message}" |
112 | | - ) |
113 | | - else: |
114 | | - raise |
115 | | - except Exception as e: |
116 | | - raise WebDriverException( |
117 | | - f"The executable {os.path.basename(self.path)} needs to be available in the path. {self.start_error_message}\n{str(e)}" |
118 | | - ) |
| 91 | + self._start_process(self.path) |
| 92 | + except WebDriverException as err: |
| 93 | + if "executable needs to be in PATH" in err.msg: |
| 94 | + logger.info("driver not found in PATH, trying Selenium Manager") |
| 95 | + browser = self.__class__.__module__.split('.')[-2] |
| 96 | + try: |
| 97 | + path = SeleniumManager.driver_location(browser) |
| 98 | + except OSError as new_err: |
| 99 | + if new_err.errno == errno.ENOENT: |
| 100 | + raise err |
| 101 | + else: |
| 102 | + raise new_err |
| 103 | + |
| 104 | + self._start_process(path) |
| 105 | + |
119 | 106 | count = 0 |
120 | 107 | while True: |
121 | 108 | self.assert_process_still_running() |
@@ -183,11 +170,43 @@ def _terminate_process(self) -> None: |
183 | 170 | # Todo: only SIGKILL if necessary; the process may be cleanly exited by now. |
184 | 171 | self.process.kill() |
185 | 172 | except OSError: |
186 | | - log.error("Error terminating service process.", exc_info=True) |
| 173 | + logger.error("Error terminating service process.", exc_info=True) |
187 | 174 |
|
188 | 175 | def __del__(self) -> None: |
189 | 176 | # `subprocess.Popen` doesn't send signal on `__del__`; |
190 | 177 | # so we attempt to close the launched process when `__del__` |
191 | 178 | # is triggered. |
192 | 179 | with contextlib.suppress(Exception): |
193 | 180 | self.stop() |
| 181 | + |
| 182 | + def _start_process(self, path: str): |
| 183 | + try: |
| 184 | + cmd = [path] |
| 185 | + cmd.extend(self.command_line_args()) |
| 186 | + self.process = subprocess.Popen( |
| 187 | + cmd, |
| 188 | + env=self.env, |
| 189 | + close_fds=system() != "Windows", |
| 190 | + stdout=self.log_file, |
| 191 | + stderr=self.log_file, |
| 192 | + stdin=PIPE, |
| 193 | + creationflags=self.creation_flags, |
| 194 | + ) |
| 195 | + logger.debug(f"Started executable: `{self.path}` in a child process with pid: {self.process.pid}") |
| 196 | + except TypeError: |
| 197 | + raise |
| 198 | + except OSError as err: |
| 199 | + if err.errno == errno.ENOENT: |
| 200 | + raise WebDriverException( |
| 201 | + f"'{os.path.basename(self.path)}' executable needs to be in PATH. {self.start_error_message}" |
| 202 | + ) |
| 203 | + elif err.errno == errno.EACCES: |
| 204 | + raise WebDriverException( |
| 205 | + f"'{os.path.basename(self.path)}' executable may have wrong permissions. {self.start_error_message}" |
| 206 | + ) |
| 207 | + else: |
| 208 | + raise |
| 209 | + except Exception as e: |
| 210 | + raise WebDriverException( |
| 211 | + f"The executable {os.path.basename(self.path)} needs to be available in the path. {self.start_error_message}\n{str(e)}" |
| 212 | + ) |
0 commit comments