diff --git a/py/BUILD.bazel b/py/BUILD.bazel index 0a4d5228d518d..763b9eb78ad32 100644 --- a/py/BUILD.bazel +++ b/py/BUILD.bazel @@ -8,7 +8,7 @@ load("@rules_python//python:packaging.bzl", "py_package", "py_wheel") load("@rules_python//python:pip.bzl", "compile_pip_requirements") load("@rules_python//sphinxdocs:sphinx.bzl", "sphinx_build_binary", "sphinx_docs") load("//common:defs.bzl", "copy_file") -load("//py:defs.bzl", "generate_devtools", "py_test_suite") +load("//py:defs.bzl", "generate_devtools", "generate_devtools_latest", "py_test_suite") load("//py/private:browsers.bzl", "BROWSERS") load("//py/private:import.bzl", "py_import") @@ -291,11 +291,20 @@ py_library( deps = [ ":bidi", ":exceptions", + ":latest", ":remote", requirement("typing_extensions"), ], ) +# Module that points to the latest devtools module +py_library( + name = "latest", + srcs = [":create-latest-devtools"], + imports = ["selenium.webdriver.common.devtools"], + visibility = ["//visibility:public"], +) + # Support utilities (wait conditions, event listeners, etc.) py_library( name = "support", @@ -438,6 +447,7 @@ py_package( "py.selenium.webdriver.common", "py.selenium.webdriver.common.bidi", "py.selenium.webdriver.common.devtools", + "py.selenium.webdriver.common.devtools.latest", "py.selenium.webdriver.edge", "py.selenium.webdriver.firefox", "py.selenium.webdriver.remote", @@ -583,6 +593,11 @@ py_binary( protocol_version = devtools_version, ) for devtools_version in BROWSER_VERSIONS] +generate_devtools_latest( + name = "create-latest-devtools", + browser_versions = BROWSER_VERSIONS, +) + py_test_suite( name = "unit", size = "small", diff --git a/py/defs.bzl b/py/defs.bzl index 8f8b4ff94b5ac..7979bfe4c1d52 100644 --- a/py/defs.bzl +++ b/py/defs.bzl @@ -1,9 +1,10 @@ -load("//py/private:generate_devtools.bzl", _generate_devtools = "generate_devtools") +load("//py/private:generate_devtools.bzl", _generate_devtools = "generate_devtools", _generate_devtools_latest = "generate_devtools_latest") load("//py/private:import.bzl", _py_import = "py_import") load("//py/private:pytest.bzl", _pytest_test = "pytest_test") load("//py/private:suite.bzl", _py_test_suite = "py_test_suite") generate_devtools = _generate_devtools +generate_devtools_latest = _generate_devtools_latest pytest_test = _pytest_test py_import = _py_import py_test_suite = _py_test_suite diff --git a/py/private/generate_devtools.bzl b/py/private/generate_devtools.bzl index 5fea436ec40f8..ab1664e7fd1d3 100644 --- a/py/private/generate_devtools.bzl +++ b/py/private/generate_devtools.bzl @@ -48,3 +48,23 @@ generate_devtools = rule( "deps": attr.label_list(), }, ) + +def _generate_latest_impl(ctx): + versions = ctx.attr.browser_versions + latest = "v%s" % max([int(v[1:]) for v in versions]) + output_file = ctx.actions.declare_file("selenium/webdriver/common/devtools/latest/__init__.py") + ctx.actions.write( + output = output_file, + content = "from ..%s import *\n" % latest, + ) + return [DefaultInfo( + files = depset([output_file]), + runfiles = ctx.runfiles(files = [output_file]), + )] + +generate_devtools_latest = rule( + implementation = _generate_latest_impl, + attrs = { + "browser_versions": attr.string_list(mandatory = True), + }, +) diff --git a/py/selenium/webdriver/common/bidi/cdp.py b/py/selenium/webdriver/common/bidi/cdp.py index b097762fe50cd..38dcf8d803ea3 100644 --- a/py/selenium/webdriver/common/bidi/cdp.py +++ b/py/selenium/webdriver/common/bidi/cdp.py @@ -59,7 +59,7 @@ def import_devtools(ver): # Attempt to parse and load the 'most recent' devtools module. This is likely # because cdp has been updated but selenium python has not been released yet. devtools_path = pathlib.Path(__file__).parents[1].joinpath("devtools") - versions = tuple(f.name for f in devtools_path.iterdir() if f.is_dir()) + versions = tuple(f.name for f in devtools_path.iterdir() if f.is_dir() and f.name != "latest") latest = max(int(x[1:]) for x in versions) selenium_logger = logging.getLogger(__name__) selenium_logger.debug("Falling back to loading `devtools`: v%s", latest) diff --git a/py/test/unit/selenium/webdriver/common/cdp_module_fallback_tests.py b/py/test/unit/selenium/webdriver/common/devtools_import_tests.py similarity index 60% rename from py/test/unit/selenium/webdriver/common/cdp_module_fallback_tests.py rename to py/test/unit/selenium/webdriver/common/devtools_import_tests.py index 5becf19a97875..f6a72b209fbdb 100644 --- a/py/test/unit/selenium/webdriver/common/cdp_module_fallback_tests.py +++ b/py/test/unit/selenium/webdriver/common/devtools_import_tests.py @@ -15,15 +15,30 @@ # specific language governing permissions and limitations # under the License. +import importlib import logging import re -import types +from types import ModuleType from selenium.webdriver.common.bidi.cdp import import_devtools def test_missing_cdp_devtools_version_falls_back(caplog): + """This test verifies the most recent devtools module is imported if an unknown devtools version is requested.""" with caplog.at_level(logging.DEBUG, logger="selenium"): - assert isinstance(import_devtools("will_never_exist"), types.ModuleType) + devtools_module = import_devtools("will_never_exist") + assert isinstance(devtools_module, ModuleType) # assert the fallback occurred successfully offered up a v{n} option. assert re.match(r"Falling back to loading `devtools`: v\d+", caplog.records[-1].getMessage()) is not None + + +def test_import_latest_cdp_devtools(): + """This test verifies the `latest` devtools module can be imported and it contains submodules.""" + latest_module = importlib.import_module("selenium.webdriver.common.devtools.latest") + assert isinstance(latest_module, ModuleType) + devtools_submodules = [ + getattr(latest_module, name) + for name in dir(latest_module) + if isinstance(getattr(latest_module, name), ModuleType) + ] + assert len(devtools_submodules) > 1