Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ jobs:
os: [ windows-latest ]
wdm-log: ['']
include:
- python-version: '3.12'
- python-version: '3.13'
selenium-version: '4.10.0'
os: ubuntu-latest
- python-version: '3.12'
- python-version: '3.14'
selenium-version: '4.10.0'
os: macos-latest
wdm-log: '0'
Expand Down
25 changes: 25 additions & 0 deletions tests/test_file_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import zipfile

from webdriver_manager.core.file_manager import FileManager
from webdriver_manager.core.os_manager import OperationSystemManager


def test_extract_zip_removes_file_dir_conflict(tmp_path):
target_dir = tmp_path / "target"
target_dir.mkdir()
conflict_path = target_dir / "operadriver"
conflict_path.write_text("stale file")

zip_path = tmp_path / "driver.zip"
with zipfile.ZipFile(zip_path, "w") as zf:
zf.writestr("operadriver/operadriver", "binary")

class ArchiveMock:
def __init__(self, file_path):
self.file_path = str(file_path)

file_manager = FileManager(OperationSystemManager())
extracted = file_manager.unpack_archive(ArchiveMock(zip_path), str(target_dir))

assert "operadriver/operadriver" in extracted
assert (target_dir / "operadriver" / "operadriver").exists()
12 changes: 12 additions & 0 deletions tests/test_opera_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,15 @@ def test_can_get_driver_from_cache(os_type, delete_drivers_dir, opera_release_da
OperaDriverManager(os_system_manager=OperationSystemManager(os_type)).install()
driver_path = OperaDriverManager(os_system_manager=OperationSystemManager(os_type)).install()
assert os.path.exists(driver_path)


def test_opera_install_keeps_file_path_without_listdir(monkeypatch, tmp_path):
binary_path = tmp_path / "operadriver"
binary_path.write_text("bin")

manager = OperaDriverManager()
monkeypatch.setattr(manager, "_get_driver_binary_path", lambda _driver: str(binary_path))

resolved_path = manager.install()

assert resolved_path == str(binary_path)
14 changes: 14 additions & 0 deletions webdriver_manager/core/file_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ def unpack_archive(self, archive_file: Archive, target_dir):
def __extract_zip(self, archive_file, to_directory):
zip_class = (LinuxZipFileWithPermissions if self._os_system_manager.get_os_name() == "linux" else zipfile.ZipFile)
archive = zip_class(archive_file.file_path)
self.__remove_file_dir_conflicts(archive.namelist(), to_directory)
try:
archive.extractall(to_directory)
except Exception as e:
Expand All @@ -88,6 +89,19 @@ def __extract_zip(self, archive_file, to_directory):
return sorted(file_names, key=lambda x: x.lower())
return archive.namelist()

def __remove_file_dir_conflicts(self, names, to_directory):
"""Remove stale files that conflict with directory entries in archive.

Example: if cache contains `<to_directory>/operadriver` as a file, and
archive now contains `operadriver/<binary>`, extraction would fail with
NotADirectoryError.
"""
top_level_dirs = {name.split("/", 1)[0] for name in names if "/" in name}
for dir_name in top_level_dirs:
path = os.path.join(to_directory, dir_name)
if os.path.isfile(path):
os.remove(path)

def __extract_tar_file(self, archive_file, to_directory):
try:
tar = tarfile.open(archive_file.file_path, mode="r:gz")
Expand Down
22 changes: 16 additions & 6 deletions webdriver_manager/opera.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,22 @@ def __init__(

def install(self) -> str:
driver_path = self._get_driver_binary_path(self.driver)
if not os.path.isfile(driver_path):
for name in os.listdir(driver_path):
if "sha512_sum" in name:
os.remove(os.path.join(driver_path, name))
break
driver_path = os.path.join(driver_path, os.listdir(driver_path)[0])
if os.path.isfile(driver_path):
os.chmod(driver_path, 0o755)
return driver_path

for name in os.listdir(driver_path):
if "sha512_sum" in name:
os.remove(os.path.join(driver_path, name))

candidates = [
name for name in os.listdir(driver_path)
if os.path.isfile(os.path.join(driver_path, name))
]
if not candidates:
raise FileNotFoundError(f"No OperaDriver binary found in {driver_path}")

driver_path = os.path.join(driver_path, candidates[0])
os.chmod(driver_path, 0o755)
return driver_path

Expand Down
Loading