Skip to content

[py] do not use global var for devtools, allows multiple devtools to run #15881

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 10, 2025

Conversation

Delta456
Copy link
Member

@Delta456 Delta456 commented Jun 9, 2025

User description

🔗 Related Issues

💥 What does this PR do?

Fixes #15816

🔧 Implementation Notes

Removes global devtools entirely and use devtool member in WebDriver for whatever use

💡 Additional Considerations

🔄 Types of changes

  • Bug fix (backwards compatible)

PR Type

Bug fix, Tests


Description

  • Refactored devtools from global to WebDriver instance member

  • Fixed bug allowing multiple devtools sessions per driver

  • Added test for starting devtools on multiple drivers


Changes walkthrough 📝

Relevant files
Bug fix
webdriver.py
Refactor devtools to instance member and fix multi-driver support

py/selenium/webdriver/remote/webdriver.py

  • Removed global devtools variable and logic
  • Made devtools an instance member (_devtools) of WebDriver
  • Refactored start_devtools to use instance member and support multiple
    drivers
  • Improved error handling and code clarity in devtools startup
  • Minor docstring formatting improvements
  • +26/-31 
    Tests
    devtools_tests.py
    Add test for multiple devtools sessions per driver             

    py/test/selenium/webdriver/common/devtools_tests.py

  • Added test to verify start_devtools works on multiple drivers
  • Ensured test covers regression for global devtools bug
  • +13/-1   

    Need help?
  • Type /help how to ... in the comments thread for any questions about Qodo Merge usage.
  • Check out the documentation for more information.
  • @selenium-ci selenium-ci added the C-py Python Bindings label Jun 9, 2025
    Copy link
    Contributor

    qodo-merge-pro bot commented Jun 9, 2025

    PR Reviewer Guide 🔍

    Here are some key observations to aid the review process:

    🎫 Ticket compliance analysis ✅

    15816 - Fully compliant

    Compliant requirements:

    • Fix bug where calling start_devtools() in 2 different drivers doesn't work
    • Resolve "local variable 'ws_url' referenced before assignment" error
    • Remove global devtools variable that outlives individual WebDrivers
    • Make devtools a WebDriver instance member instead of global
    • Allow multiple devtools sessions to work properly

    ⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
    🧪 PR contains tests
    🔒 No security concerns identified
    ⚡ Recommended focus areas for review

    Logic Flow

    The refactored start_devtools method has complex conditional logic that should be verified for all execution paths, especially the early return condition and websocket connection reuse.

    def start_devtools(self):
        global cdp
        import_cdp()
        if self.caps.get("se:cdp"):
            ws_url = self.caps.get("se:cdp")
            version = self.caps.get("se:cdpVersion").split(".")[0]
        else:
            version, ws_url = self._get_cdp_details()
    
        if not ws_url:
            raise WebDriverException("Unable to find url to connect to from capabilities")
    
        self._devtools = cdp.import_devtools(version)
        if self._websocket_connection:
            return self._devtools, self._websocket_connection
        if self.caps["browserName"].lower() == "firefox":
            raise RuntimeError("CDP support for Firefox has been removed. Please switch to WebDriver BiDi.")
        self._websocket_connection = WebSocketConnection(ws_url)
        targets = self._websocket_connection.execute(self._devtools.target.get_targets())
        target_id = targets[0].target_id
        session = self._websocket_connection.execute(self._devtools.target.attach_to_target(target_id, True))
        self._websocket_connection.session_id = session
        return self._devtools, self._websocket_connection
    Test Coverage

    The new test only verifies that start_devtools can be called on multiple drivers sequentially, but doesn't test concurrent usage or verify that each driver gets its own devtools instance.

    def test_check_start_twice(clean_driver, clean_options, clean_service):
        driver1 = clean_driver(options=clean_options, service=clean_service)
        devtools1, connection1 = driver1.start_devtools()
        driver1.quit()
    
        driver2 = clean_driver(options=clean_options, service=clean_service)
        devtools2, connection2 = driver2.start_devtools()
        driver2.quit()

    Copy link
    Contributor

    qodo-merge-pro bot commented Jun 9, 2025

    PR Code Suggestions ✨

    No code suggestions found for the PR.

    @cgoldberg cgoldberg self-requested a review June 9, 2025 13:38
    Copy link
    Contributor

    @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.

    nice work. Thanks for fixing this.

    Copy link
    Member

    @navin772 navin772 left a comment

    Choose a reason for hiding this comment

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

    @Delta456 The tests fail because the clean_driver fixture does not follows the xfail rules as the driver fixture does and launches test against firefox even if we mention xfail.
    You will need to modify the clean_driver fixture in conftest.py to include the xfail logic similar to this:

    selenium/py/conftest.py

    Lines 327 to 337 in cc3ea7b

    # conditionally mark tests as expected to fail based on driver
    marker = request.node.get_closest_marker(f"xfail_{driver_class.lower()}")
    if marker is not None:
    if "run" in marker.kwargs:
    if marker.kwargs["run"] is False:
    pytest.skip()
    yield
    return
    if "raises" in marker.kwargs:
    marker.kwargs.pop("raises")
    pytest.xfail(**marker.kwargs)

    Copy link
    Member

    @navin772 navin772 left a comment

    Choose a reason for hiding this comment

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

    LGTM!

    @Delta456 Delta456 requested a review from p0deje June 10, 2025 06:03
    @cgoldberg
    Copy link
    Contributor

    @Delta456 looks good to merge. Let me know if you don't have access and I'll merge it.

    @Delta456
    Copy link
    Member Author

    @Delta456 looks good to merge. Let me know if you don't have access and I'll merge it.

    I now have access. I will merge it in few hours :)

    @Delta456 Delta456 merged commit d942194 into SeleniumHQ:trunk Jun 10, 2025
    16 checks passed
    @Delta456 Delta456 deleted the devtools branch June 10, 2025 18:39
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    Projects
    None yet
    Development

    Successfully merging this pull request may close these issues.

    [🐛 Bug]: Calling start_devtools() in 2 different drivers doesn't work
    5 participants