Skip to content

[py] fix selenium-manager binary selection on FreeBSD#17263

Closed
obiwac wants to merge 1 commit intoSeleniumHQ:trunkfrom
obiwac:trunk
Closed

[py] fix selenium-manager binary selection on FreeBSD#17263
obiwac wants to merge 1 commit intoSeleniumHQ:trunkfrom
obiwac:trunk

Conversation

@obiwac
Copy link
Copy Markdown

@obiwac obiwac commented Mar 27, 2026

Previously, sys.platform was checked to match "freebsd". However,
Py_GetPlatform on FreeBSD returns the version number along with it (e.g.
"freebsd15") [1]. So check sys.platform starts with "freebsd" instead.

Also, platform.machine() gives "amd64" on FreeBSD, not "x86_64", so fix
that.

Do the same with OpenBSD, and only allow Windows binary to be selected
if arch is correct ("AMD64" on Windows).

Update warning about Selenium Manager binary on FreeBSD to hint at user
what they need to do to get the Linux binary working on FreeBSD.

Fixes: 5a7a2ac ("[py] allow bsd operating systems to use the linux binary")

[1] https://python.readthedocs.io/fr/stable/c-api/init.html#c.Py_GetPlatform

💡 Additional Considerations

OpenBSD probably needs a similar change, but I have not investigated that.

This patch is a little ugly, but I'm not sure how to make this more elegant.

🔄 Types of changes

  • Bug fix (backwards compatible)

@qodo-code-review
Copy link
Copy Markdown
Contributor

Review Summary by Qodo

Fix Selenium Manager binary selection on FreeBSD

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Fix FreeBSD platform detection by checking sys.platform prefix instead of exact match
• Correct architecture mapping from x86_64 to amd64 for FreeBSD
• Improve warning messages with actionable guidance for FreeBSD users
• Refactor platform detection logic for better clarity and maintainability

Grey Divider

File Changes

1. py/selenium/webdriver/common/selenium_manager.py 🐞 Bug fix +14/-5

Fix FreeBSD platform and architecture detection

• Changed FreeBSD platform detection from exact match to prefix check (startswith("freebsd")) to
 handle version numbers in sys.platform
• Updated architecture mapping from x86_64 to amd64 for FreeBSD
• Enhanced warning message with specific instructions to run brandelf -t linux and load
 linux64.ko
• Refactored platform detection logic to use platform_name variable and conditional branches for
 clearer code flow

py/selenium/webdriver/common/selenium_manager.py


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown
Contributor

qodo-code-review Bot commented Mar 27, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (2) 📎 Requirement gaps (0) 📐 Spec deviations (0)

Grey Divider


Action required

1. FreeBSD warning line too long 📘 Rule violation ⚙ Maintainability
Description
The new logger.warning(...) line for FreeBSD exceeds the configured Ruff line-length of 120,
which is likely to cause lint/format CI failures. This should be wrapped or split into multiple
strings and the unnecessary f-string removed.
Code

py/selenium/webdriver/common/selenium_manager.py[103]

+                logger.warning(f"Selenium Manager binary may not be compatible with FreeBSD; you may need to run 'brandelf -t linux' on it and load linux64.ko")
Evidence
Repository linting is configured with Ruff line-length = 120, but the newly added FreeBSD warning
message is a single very long line, making it likely to violate E501/format checks.

AGENTS.md
py/pyproject.toml[140-145]
py/selenium/webdriver/common/selenium_manager.py[102-104]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The FreeBSD `logger.warning(...)` message was added as a single long line and is likely to exceed the configured Ruff `line-length = 120`, causing lint/format CI failures.

## Issue Context
The warning string does not interpolate variables, so the `f` prefix is unnecessary. The message can be wrapped using implicit string concatenation inside parentheses to satisfy line-length.

## Fix Focus Areas
- py/selenium/webdriver/common/selenium_manager.py[102-105]
- py/pyproject.toml[140-145]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. No tests for freebsd* 📘 Rule violation ⛯ Reliability
Description
The PR changes platform/arch selection logic for FreeBSD (e.g., sys.platform prefix handling and
amd64 arch), but no unit tests were added/updated to validate the new behavior. This increases the
risk of regressions for BSD platform selection.
Code

py/selenium/webdriver/common/selenium_manager.py[R99-114]

+            platform_name = sys.platform
+            arch = "any"

-            location = allowed.get((sys.platform, arch))
+            if platform_name.startswith("freebsd"):
+                logger.warning(f"Selenium Manager binary may not be compatible with FreeBSD; you may need to run 'brandelf -t linux' on it and load linux64.ko")
+                platform_name = "freebsd"
+                arch = platform.machine()
+            elif sys.platform == "openbsd":
+                logger.warning(f"Selenium Manager binary may not be compatible with OpenBSD; verify settings")
+                arch = platform.machine()
+            elif sys.platform == "linux":
+                arch = platform.machine()
+
+            location = allowed.get((platform_name, arch))
            if location is None:
                raise WebDriverException(f"Unsupported platform/architecture combination: {sys.platform}/{arch}")
Evidence
The modified code now depends on sys.platform.startswith("freebsd") and uses platform.machine()
for BSD arch selection, but existing unit tests only cover Windows/Linux/macOS paths and do not
exercise FreeBSD/OpenBSD cases.

AGENTS.md
py/selenium/webdriver/common/selenium_manager.py[99-114]
py/test/unit/selenium/webdriver/common/selenium_manager_tests.py[55-103]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Platform/architecture selection logic for FreeBSD was changed (prefix match and `amd64` handling), but unit tests were not updated to cover the new cases.

## Issue Context
These behaviors can be tested deterministically without requiring a BSD runtime by monkeypatching `sys.platform` (e.g., `freebsd15`) and `platform.machine()` (e.g., `amd64`) and asserting that `_get_binary()` selects `linux/selenium-manager`.

## Fix Focus Areas
- py/selenium/webdriver/common/selenium_manager.py[99-114]
- py/test/unit/selenium/webdriver/common/selenium_manager_tests.py[55-103]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Arch alias not normalized 🐞 Bug ✓ Correctness
Description
_get_binary() uses platform.machine() verbatim and performs an exact tuple lookup (e.g., only
("freebsd","amd64")), so any casing/alias differences (e.g., x86_64 vs amd64) will fail lookup
and raise Unsupported platform/architecture even though the Linux binary path exists. Other parts
of this repo already treat amd64/x86_64 as equivalent, so the Python binding is currently more
fragile than the rest of the project.
Code

py/selenium/webdriver/common/selenium_manager.py[R95-114]

+                ("freebsd", "amd64"): "linux/selenium-manager",
                ("openbsd", "x86_64"): "linux/selenium-manager",
            }

-            arch = platform.machine() if sys.platform in ("linux", "freebsd", "openbsd") else "any"
-            if sys.platform in ["freebsd", "openbsd"]:
-                logger.warning(f"Selenium Manager binary may not be compatible with {sys.platform}; verify settings")
+            platform_name = sys.platform
+            arch = "any"

-            location = allowed.get((sys.platform, arch))
+            if platform_name.startswith("freebsd"):
+                logger.warning(f"Selenium Manager binary may not be compatible with FreeBSD; you may need to run 'brandelf -t linux' on it and load linux64.ko")
+                platform_name = "freebsd"
+                arch = platform.machine()
+            elif sys.platform == "openbsd":
+                logger.warning(f"Selenium Manager binary may not be compatible with OpenBSD; verify settings")
+                arch = platform.machine()
+            elif sys.platform == "linux":
+                arch = platform.machine()
+
+            location = allowed.get((platform_name, arch))
            if location is None:
                raise WebDriverException(f"Unsupported platform/architecture combination: {sys.platform}/{arch}")
Evidence
The Python selection code keys the binary location by exact (platform_name, arch) tuples and
raises if the key isn’t found; arch is taken directly from platform.machine() for Linux/BSD,
with no lowercasing or alias mapping. In contrast, the Rust and Java components in this repo
explicitly include amd64 and x86_64 as the same architecture and normalize casing, demonstrating
that arch-string variance is expected within this codebase.

py/selenium/webdriver/common/selenium_manager.py[90-114]
py/test/unit/selenium/webdriver/common/selenium_manager_tests.py[72-78]
rust/src/config.rs[187-201]
java/src/org/openqa/selenium/Architecture.java[53-56]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`SeleniumManager._get_binary()` uses `platform.machine()` directly and does an exact lookup in `allowed`. This is fragile because architecture strings commonly have aliases and casing differences (e.g., `x86_64` vs `amd64`, `AMD64`), causing false “Unsupported platform/architecture” errors.

### Issue Context
This PR already adjusts FreeBSD to use `amd64`, but the lookup still depends on the raw `platform.machine()` output. Elsewhere in this repo, architecture detection treats `amd64`/`x86_64` as the same arch and normalizes casing.

### Fix Focus Areas
- py/selenium/webdriver/common/selenium_manager.py[90-114]

### Suggested implementation notes
- Normalize `arch = platform.machine().lower()` for Linux/BSD paths.
- Add a small alias map for common synonyms (at least `x86_64` <-> `amd64`) before the `allowed.get(...)` lookup, or add multiple keys to `allowed` to accept both.
- Keep the raised exception message aligned with the normalized value so users see what was actually matched/used.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Advisory comments

4. Inconsistent platform variable usage 🐞 Bug ⚙ Maintainability
Description
The new code introduces platform_name = sys.platform but still branches on sys.platform for
Linux/OpenBSD, which makes the control flow harder to reason about and easier to break when further
normalization is added. This is especially relevant since FreeBSD already normalizes platform_name
but Linux/OpenBSD do not follow the same pattern.
Code

py/selenium/webdriver/common/selenium_manager.py[R99-111]

+            platform_name = sys.platform
+            arch = "any"

-            location = allowed.get((sys.platform, arch))
+            if platform_name.startswith("freebsd"):
+                logger.warning(f"Selenium Manager binary may not be compatible with FreeBSD; you may need to run 'brandelf -t linux' on it and load linux64.ko")
+                platform_name = "freebsd"
+                arch = platform.machine()
+            elif sys.platform == "openbsd":
+                logger.warning(f"Selenium Manager binary may not be compatible with OpenBSD; verify settings")
+                arch = platform.machine()
+            elif sys.platform == "linux":
+                arch = platform.machine()
+
Evidence
platform_name is introduced and used for the final lookup, but the subsequent OS checks mix
platform_name (FreeBSD) with direct sys.platform comparisons (Linux/OpenBSD), creating
inconsistent patterns inside a small, platform-sensitive decision tree.

py/selenium/webdriver/common/selenium_manager.py[99-112]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`platform_name` is introduced to support normalization (e.g., FreeBSD), but Linux/OpenBSD logic still checks `sys.platform` directly. This inconsistency increases the chance of subtle mistakes when extending/maintaining platform normalization.

### Issue Context
The final lookup uses `(platform_name, arch)`, so branching should ideally also rely on `platform_name` (after any normalization) to keep the selection logic coherent.

### Fix Focus Areas
- py/selenium/webdriver/common/selenium_manager.py[99-111]

### Suggested implementation notes
- Replace `elif sys.platform == "openbsd"` / `elif sys.platform == "linux"` with checks against `platform_name`.
- Optionally normalize OpenBSD the same way as FreeBSD (e.g., set `platform_name = "openbsd"` in its branch) for symmetry/clarity.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@selenium-ci selenium-ci added the C-py Python Bindings label Mar 27, 2026
@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Mar 27, 2026

CLA assistant check
All committers have signed the CLA.

Comment thread py/selenium/webdriver/common/selenium_manager.py Outdated
@obiwac obiwac force-pushed the trunk branch 4 times, most recently from 369c2e0 to a3debee Compare March 27, 2026 04:25
Copy link
Copy Markdown
Member

@cgoldberg cgoldberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. We don't have many FreeBSD users...

In Python 3.14+, they fixed this, so sys.platform won't include version... but I guess this is useful for older versions.

There is also another subtle bug in the current code. We only ship a Windows version for x86-64, but the code allows "any", so that is being skipped. Also, Windows reports platform.machine() as AMD64.

What do you think of this small tweak instead... it should handle the amd64/AMD64 cases correctly for all platforms:

            allowed = {
                ("darwin", "any"): "macos/selenium-manager",
                ("win32", "x86_64"): "windows/selenium-manager.exe",
                ("cygwin", "x86_64"): "windows/selenium-manager.exe",
                ("linux", "x86_64"): "linux/selenium-manager",
                ("freebsd", "x86_64"): "linux/selenium-manager",
                ("openbsd", "x86_64"): "linux/selenium-manager",
            }

            platform_name = sys.platform
            arch = "any" if platform_name == "darwin" else platform.machine().lower()
            arch = "x86_64" if arch == "amd64" else arch

            if platform_name.startswith("freebsd"):
                logger.warning(
                    "Selenium Manager binary may not be compatible with FreeBSD; you may need to run "
                    "'brandelf -t linux' on it and load linux64.ko"
                )
                platform_name = "freebsd"
            elif platform_name.startswith("openbsd"):
                logger.warning("Selenium Manager binary may not be compatible with OpenBSD; verify settings")
                platform_name = "openbsd"

            location = allowed.get((platform_name, arch))

Previously, sys.platform was checked to match "freebsd". However,
Py_GetPlatform on FreeBSD returns the version number along with it (e.g.
"freebsd15") [1]. So check sys.platform starts with "freebsd" instead.

Also, platform.machine() gives "amd64" on FreeBSD, not "x86_64", so fix
that.

Do the same with OpenBSD, and only allow Windows binary to be selected
if arch is correct ("AMD64" on Windows).

Update warning about Selenium Manager binary on FreeBSD to hint at user
what they need to do to get the Linux binary working on FreeBSD.

Fixes: 5a7a2ac ("[py] allow bsd operating systems to use the linux binary")

[1] https://python.readthedocs.io/fr/stable/c-api/init.html#c.Py_GetPlatform
@obiwac
Copy link
Copy Markdown
Author

obiwac commented Mar 28, 2026

@cgoldberg I think at that point the logic is complex enough that we shouldn't try to be smart with it. See my updated diff - what do you think of it? I can also confirm OpenBSD returns amd64, not x86_64, too. Also included the Windows thing but maybe that should be its own commit.

@cgoldberg
Copy link
Copy Markdown
Member

See my updated diff

We still want the dictionary of allowed platforms because we will soon be shipping ARM64 binaries and we need to select the correct binary on those platforms.

I just submitted #17271 instead of this PR.

@cgoldberg cgoldberg closed this Mar 29, 2026
@obiwac
Copy link
Copy Markdown
Author

obiwac commented Mar 30, 2026

We still want the dictionary of allowed platforms because we will soon be shipping ARM64 binaries and we need to select the correct binary on those platforms.

still think my solution was better

@cgoldberg
Copy link
Copy Markdown
Member

still think my solution was better

Yours would have to be refactored soon if I used it. There are already Pull Requests open that add more platforms/architectures to the dictionary, and the dictionary dispatch is nicer (IMO) than a long if/else chain... sorry if you don't agree.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C-py Python Bindings

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants