diff --git a/.github/workflows/ci-python.yml b/.github/workflows/ci-python.yml index 7115e7c93836c..2053b1c41ff9b 100644 --- a/.github/workflows/ci-python.yml +++ b/.github/workflows/ci-python.yml @@ -33,28 +33,6 @@ jobs: env: TOXENV: docs - lint: - name: Lint - needs: build - runs-on: ubuntu-latest - steps: - - name: Checkout source tree - uses: actions/checkout@v4 - - name: Set up Python 3.9 - uses: actions/setup-python@v4 - with: - python-version: 3.9 - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install tox==4.25.0 - - name: Test with tox - run: tox -c py/tox.ini - env: - # If this fails, it will exit. Local work should be using `tox -e linting` prior to committing. - # the linting-ci recipe exists solely for CI and will not attempt to rewrite any files in-place etc. - TOXENV: linting-ci - mypy: name: Mypy needs: build diff --git a/MODULE.bazel b/MODULE.bazel index 3d1997c2d869d..ffa1e9ba9ccaf 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,6 +1,7 @@ module(name = "selenium") bazel_dep(name = "apple_rules_lint", version = "0.4.0") +bazel_dep(name = "aspect_rules_lint", version = "1.4.2") bazel_dep(name = "aspect_bazel_lib", version = "2.13.0") bazel_dep(name = "aspect_rules_esbuild", version = "0.21.0") bazel_dep(name = "aspect_rules_js", version = "2.1.3") diff --git a/README.md b/README.md index 91dc9b67e720f..3ca69b1ad1936 100644 --- a/README.md +++ b/README.md @@ -217,19 +217,11 @@ To automatically update and pin new dependencies, run: ### Python -#### Linting +#### Linting and Formatting We follow the [PEP8 Style Guide for Python Code](https://peps.python.org/pep-0008) (except we use a 120 character line length). -This is checked and enforced with several linting tools, including -[black](https://pypi.org/project/black), -[docformatter](https://pypi.org/project/docformatter), -[flake8](https://flake8.pycqa.org), -and [isort](https://pycqa.github.io/isort). - -To run all of the linting tools: -```shell -./go py:lint -``` +This is checked and enforced with [ruff](https://docs.astral.sh/ruff/), a linting/formatting tool. +There is also an auto-formatting script that can be run: `./scripts/format.sh` #### Local Installation diff --git a/Rakefile b/Rakefile index fc327ad5f7c5b..b852a2b813a49 100644 --- a/Rakefile +++ b/Rakefile @@ -669,11 +669,6 @@ namespace :py do @git.add(conf) end - desc 'Update Python Syntax' - task :lint do - sh 'tox -c py/tox.ini -e linting' - end - namespace :test do desc 'Python unit tests' task :unit do @@ -1165,7 +1160,6 @@ namespace :all do task :lint do ext = /mswin|msys|mingw|cygwin|bccwin|wince|emc/.match?(RbConfig::CONFIG['host_os']) ? 'ps1' : 'sh' sh "./scripts/format.#{ext}", verbose: true - Rake::Task['py:lint'].invoke end # Example: `./go all:prepare 4.31.0 early-stable` diff --git a/common/devtools/convert_protocol_to_json.py b/common/devtools/convert_protocol_to_json.py index cfea7867d4ef0..de17844be0a93 100644 --- a/common/devtools/convert_protocol_to_json.py +++ b/common/devtools/convert_protocol_to_json.py @@ -10,13 +10,20 @@ import pdl + def main(argv): - parser = argparse.ArgumentParser(description=( - "Converts from .pdl to .json by invoking the pdl Python module.")) - parser.add_argument('--map_binary_to_string', type=bool, - help=('If set, binary in the .pdl is mapped to a ' - 'string in .json. Client code will have to ' - 'base64 decode the string to get the payload.')) + parser = argparse.ArgumentParser( + description=("Converts from .pdl to .json by invoking the pdl Python module.") + ) + parser.add_argument( + "--map_binary_to_string", + type=bool, + help=( + "If set, binary in the .pdl is mapped to a " + "string in .json. Client code will have to " + "base64 decode the string to get the payload." + ), + ) parser.add_argument("pdl_file", help="The .pdl input file to parse.") parser.add_argument("json_file", help="The .json output file write.") args = parser.parse_args(argv) @@ -26,10 +33,10 @@ def main(argv): protocol = pdl.loads(pdl_string, file_name, args.map_binary_to_string) input_file.close() - output_file = open(os.path.normpath(args.json_file), 'w') - json.dump(protocol, output_file, indent=4, separators=(',', ': ')) + output_file = open(os.path.normpath(args.json_file), "w") + json.dump(protocol, output_file, indent=4, separators=(",", ": ")) output_file.close() -if __name__ == '__main__': +if __name__ == "__main__": sys.exit(main(sys.argv[1:])) diff --git a/common/devtools/pdl.py b/common/devtools/pdl.py index 132615b6835e1..75fa2abb794d8 100644 --- a/common/devtools/pdl.py +++ b/common/devtools/pdl.py @@ -8,64 +8,72 @@ import re import sys -description = '' +description = "" -primitiveTypes = ['integer', 'number', 'boolean', 'string', 'object', - 'any', 'array', 'binary'] +primitiveTypes = [ + "integer", + "number", + "boolean", + "string", + "object", + "any", + "array", + "binary", +] def assignType(item, type, is_array=False, map_binary_to_string=False): if is_array: - item['type'] = 'array' - item['items'] = collections.OrderedDict() - assignType(item['items'], type, False, map_binary_to_string) + item["type"] = "array" + item["items"] = collections.OrderedDict() + assignType(item["items"], type, False, map_binary_to_string) return - if type == 'enum': - type = 'string' - if map_binary_to_string and type == 'binary': - type = 'string' + if type == "enum": + type = "string" + if map_binary_to_string and type == "binary": + type = "string" if type in primitiveTypes: - item['type'] = type + item["type"] = type else: - item['$ref'] = type + item["$ref"] = type def createItem(d, experimental, deprecated, name=None): result = collections.OrderedDict(d) if name: - result['name'] = name + result["name"] = name global description if description: - result['description'] = description.strip() + result["description"] = description.strip() if experimental: - result['experimental'] = True + result["experimental"] = True if deprecated: - result['deprecated'] = True + result["deprecated"] = True return result def parse(data, file_name, map_binary_to_string=False): protocol = collections.OrderedDict() - protocol['version'] = collections.OrderedDict() - protocol['domains'] = [] + protocol["version"] = collections.OrderedDict() + protocol["domains"] = [] domain = None item = None subitems = None nukeDescription = False global description - lines = data.split('\n') + lines = data.split("\n") for i in range(0, len(lines)): if nukeDescription: - description = '' + description = "" nukeDescription = False line = lines[i] trimLine = line.strip() - if trimLine.startswith('#'): + if trimLine.startswith("#"): if len(description): - description += '\n' + description += "\n" description += trimLine[2:] continue else: @@ -74,99 +82,103 @@ def parse(data, file_name, map_binary_to_string=False): if len(trimLine) == 0: continue - match = re.compile( - r'^(experimental )?(deprecated )?domain (.*)').match(line) + match = re.compile(r"^(experimental )?(deprecated )?domain (.*)").match(line) if match: - domain = createItem({'domain' : match.group(3)}, match.group(1), - match.group(2)) - protocol['domains'].append(domain) + domain = createItem( + {"domain": match.group(3)}, match.group(1), match.group(2) + ) + protocol["domains"].append(domain) continue - match = re.compile(r'^ depends on ([^\s]+)').match(line) + match = re.compile(r"^ depends on ([^\s]+)").match(line) if match: - if 'dependencies' not in domain: - domain['dependencies'] = [] - domain['dependencies'].append(match.group(1)) + if "dependencies" not in domain: + domain["dependencies"] = [] + domain["dependencies"].append(match.group(1)) continue - match = re.compile(r'^ (experimental )?(deprecated )?type (.*) ' - r'extends (array of )?([^\s]+)').match(line) + match = re.compile( + r"^ (experimental )?(deprecated )?type (.*) " + r"extends (array of )?([^\s]+)" + ).match(line) if match: - if 'types' not in domain: - domain['types'] = [] - item = createItem({'id': match.group(3)}, match.group(1), match.group(2)) + if "types" not in domain: + domain["types"] = [] + item = createItem({"id": match.group(3)}, match.group(1), match.group(2)) assignType(item, match.group(5), match.group(4), map_binary_to_string) - domain['types'].append(item) + domain["types"].append(item) continue match = re.compile( - r'^ (experimental )?(deprecated )?(command|event) (.*)').match(line) + r"^ (experimental )?(deprecated )?(command|event) (.*)" + ).match(line) if match: list = [] - if match.group(3) == 'command': - if 'commands' in domain: - list = domain['commands'] + if match.group(3) == "command": + if "commands" in domain: + list = domain["commands"] else: - list = domain['commands'] = [] + list = domain["commands"] = [] else: - if 'events' in domain: - list = domain['events'] + if "events" in domain: + list = domain["events"] else: - list = domain['events'] = [] + list = domain["events"] = [] item = createItem({}, match.group(1), match.group(2), match.group(4)) list.append(item) continue match = re.compile( - r'^ (experimental )?(deprecated )?(optional )?' - r'(array of )?([^\s]+) ([^\s]+)').match(line) + r"^ (experimental )?(deprecated )?(optional )?" + r"(array of )?([^\s]+) ([^\s]+)" + ).match(line) if match: param = createItem({}, match.group(1), match.group(2), match.group(6)) if match.group(3): - param['optional'] = True + param["optional"] = True assignType(param, match.group(5), match.group(4), map_binary_to_string) - if match.group(5) == 'enum': - enumliterals = param['enum'] = [] + if match.group(5) == "enum": + enumliterals = param["enum"] = [] subitems.append(param) continue - match = re.compile(r'^ (parameters|returns|properties)').match(line) + match = re.compile(r"^ (parameters|returns|properties)").match(line) if match: subitems = item[match.group(1)] = [] continue - match = re.compile(r'^ enum').match(line) + match = re.compile(r"^ enum").match(line) if match: - enumliterals = item['enum'] = [] + enumliterals = item["enum"] = [] continue - match = re.compile(r'^version').match(line) + match = re.compile(r"^version").match(line) if match: continue - match = re.compile(r'^ major (\d+)').match(line) + match = re.compile(r"^ major (\d+)").match(line) if match: - protocol['version']['major'] = match.group(1) + protocol["version"]["major"] = match.group(1) continue - match = re.compile(r'^ minor (\d+)').match(line) + match = re.compile(r"^ minor (\d+)").match(line) if match: - protocol['version']['minor'] = match.group(1) + protocol["version"]["minor"] = match.group(1) continue - match = re.compile(r'^ redirect ([^\s]+)').match(line) + match = re.compile(r"^ redirect ([^\s]+)").match(line) if match: - item['redirect'] = match.group(1) + item["redirect"] = match.group(1) continue - match = re.compile(r'^ ( )?[^\s]+$').match(line) + match = re.compile(r"^ ( )?[^\s]+$").match(line) if match: # enum literal enumliterals.append(trimLine) continue - print('Error in %s:%s, illegal token: \t%s' % (file_name, i, line)) + print("Error in %s:%s, illegal token: \t%s" % (file_name, i, line)) sys.exit(1) return protocol diff --git a/javascript/grid-ui/scripts/rmSourcemaps.py b/javascript/grid-ui/scripts/rmSourcemaps.py index 7f383d5818073..a423a2f65a0d0 100644 --- a/javascript/grid-ui/scripts/rmSourcemaps.py +++ b/javascript/grid-ui/scripts/rmSourcemaps.py @@ -3,7 +3,7 @@ BUILD_DIR = "build" for current, dirs, files in os.walk(BUILD_DIR): - for file in files: - if file.endswith('.map'): - # remove the source map - os.remove(os.path.join(current, file)) + for file in files: + if file.endswith(".map"): + # remove the source map + os.remove(os.path.join(current, file)) diff --git a/javascript/private/gen_file.py b/javascript/private/gen_file.py index 19ddb611b053c..a6f906a2bd952 100644 --- a/javascript/private/gen_file.py +++ b/javascript/private/gen_file.py @@ -18,12 +18,14 @@ */ """ + def get_atom_name(name): # We had a todo here to convert camelCase and snake_case to BIG_SNAKE_CASE, but this code # will be removed when BiDi is the default, so we're not going to bother with that. name = os.path.basename(name) return name.upper() + def write_atom_literal(out, name, contents, lang, utf8): # Escape the contents of the file so it can be stored as a literal. contents = contents.replace("\\", "\\\\") @@ -34,12 +36,12 @@ def write_atom_literal(out, name, contents, lang, utf8): contents = contents.replace('"', '\\"') if "cc" == lang or "hh" == lang: - if utf8: - line_format = " \"{}\",\n" - else: - line_format = " L\"{}\",\n" + if utf8: + line_format = ' "{}",\n' + else: + line_format = ' L"{}",\n' elif "java" == lang: - line_format = " .append\(\"{}\")\n" + line_format = ' .append\("{}")\n' else: raise RuntimeError("Unknown language: %s " % lang) @@ -59,8 +61,8 @@ def write_atom_literal(out, name, contents, lang, utf8): # of an escape sequence. while len(contents) > 70: diff = 70 - while contents[diff-1] == "\\": - diff = diff -1 + while contents[diff - 1] == "\\": + diff = diff - 1 line = contents[0:diff] contents = contents[diff:] @@ -73,10 +75,14 @@ def write_atom_literal(out, name, contents, lang, utf8): elif "java" == lang: out.write(" .toString()),\n") + def generate_header(file_name, out, js_map, just_declare, utf8): - define_guard = "WEBDRIVER_%s" % os.path.basename(file_name.upper()).replace(".", "_") + define_guard = "WEBDRIVER_%s" % os.path.basename(file_name.upper()).replace( + ".", "_" + ) include_stddef = "" if utf8 else "\n#include // For wchar_t." - out.write("""%s + out.write( + """%s /* AUTO GENERATED - DO NOT EDIT BY HAND */ #ifndef %s @@ -87,19 +93,22 @@ def generate_header(file_name, out, js_map, just_declare, utf8): namespace webdriver { namespace atoms { -""" % (_copyright, define_guard, define_guard, include_stddef)) +""" + % (_copyright, define_guard, define_guard, include_stddef) + ) string_type = "std::string" if utf8 else "std::wstring" char_type = "char" if utf8 else "wchar_t" - for (name, file) in js_map.items(): + for name, file in js_map.items(): if just_declare: out.write("extern const %s* const %s[];\n" % (char_type, name.upper())) else: contents = open(file, "r").read() write_atom_literal(out, name, contents, "hh", utf8) - out.write(""" + out.write( + """ static inline %s asString(const %s* const atom[]) { %s source; for (int i = 0; atom[i] != NULL; i++) { @@ -112,10 +121,14 @@ def generate_header(file_name, out, js_map, just_declare, utf8): } // namespace webdriver #endif // %s -""" % (string_type, char_type, string_type, define_guard)) +""" + % (string_type, char_type, string_type, define_guard) + ) + def generate_cc_source(out, js_map, utf8): - out.write("""%s + out.write( + """%s /* AUTO GENERATED - DO NOT EDIT BY HAND */ @@ -125,9 +138,11 @@ def generate_cc_source(out, js_map, utf8): namespace webdriver { namespace atoms { -""" % _copyright) +""" + % _copyright + ) - for (name, file) in js_map.items(): + for name, file in js_map.items(): contents = open(file, "r").read() write_atom_literal(out, name, contents, "cc", utf8) @@ -137,6 +152,7 @@ def generate_cc_source(out, js_map, utf8): """) + def generate_java_source(file_name, out, preamble, js_map): if not file_name.endswith(".java"): raise RuntimeError("File name must end in .java") @@ -146,17 +162,21 @@ def generate_java_source(file_name, out, preamble, js_map): out.write("\n") out.write(preamble) out.write("") - out.write(""" + out.write( + """ public enum %s { // AUTO GENERATED - DO NOT EDIT BY HAND -""" % class_name) +""" + % class_name + ) - for (name, file) in js_map.items(): + for name, file in js_map.items(): contents = open(file, "r").read() write_atom_literal(out, name, contents, "java", True) - out.write(""" + out.write( + """ ; private final String value; @@ -172,14 +192,16 @@ def generate_java_source(file_name, out, preamble, js_map): this.value = value; } } -""" % class_name) +""" + % class_name + ) def main(argv=[]): lang = argv[1] file_name = argv[2] preamble = argv[3] - utf8 = (argv[4] == "true") + utf8 = argv[4] == "true" js_map = {} for i in range(5, len(argv), 2): @@ -197,5 +219,6 @@ def main(argv=[]): else: raise RuntimeError("Unknown lang: %s" % lang) + if __name__ == "__main__": main(sys.argv) diff --git a/py/BUILD.bazel b/py/BUILD.bazel index 5c0e1671614c5..46438431de732 100644 --- a/py/BUILD.bazel +++ b/py/BUILD.bazel @@ -1,3 +1,4 @@ +load("@aspect_rules_lint//format:defs.bzl", "format_multirun") load("@bazel_skylib//rules:select_file.bzl", "select_file") load("@py_dev_requirements//:requirements.bzl", "requirement") load("@rules_pkg//pkg:mappings.bzl", "pkg_files", "strip_prefix") @@ -10,6 +11,11 @@ load("//py:defs.bzl", "generate_devtools", "py_test_suite") load("//py/private:browsers.bzl", "BROWSERS") load("//py/private:import.bzl", "py_import") +format_multirun( + name = "format", + python = "@aspect_rules_lint//format:ruff", +) + py_binary( name = "selenium-release", srcs = [ diff --git a/py/docs/source/conf.py b/py/docs/source/conf.py index a8e2853edfba3..f30b1f44d7a09 100644 --- a/py/docs/source/conf.py +++ b/py/docs/source/conf.py @@ -29,100 +29,108 @@ # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +# needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.autosummary', 'sphinx.ext.doctest', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.imgmath', 'sphinx.ext.viewcode'] +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.autosummary", + "sphinx.ext.doctest", + "sphinx.ext.todo", + "sphinx.ext.coverage", + "sphinx.ext.imgmath", + "sphinx.ext.viewcode", +] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. -#source_encoding = 'utf-8-sig' +# source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = 'Selenium' -copyright = '2009-2025 Software Freedom Conservancy' +project = "Selenium" +copyright = "2009-2025 Software Freedom Conservancy" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = '4.33' +version = "4.33" # The full version, including alpha/beta/rc tags. -release = '4.33.0.202505022255' +release = "4.33.0.202505022255" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -#language = None +# language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: -#today = '' +# today = '' # Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' +# today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None +# default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +# add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +# add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -#show_authors = False +# show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +# modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages -html_theme = 'sphinx_material' +html_theme = "sphinx_material" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -#html_theme_options = {} +# html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] +# html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -#html_title = None +# html_title = None # A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None +# html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = '' +# html_logo = '' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None +# html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -131,18 +139,18 @@ # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' +# html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -#html_use_smartypants = True +# html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. -#html_additional_pages = {} +# html_additional_pages = {} # If false, no module index is generated. html_domain_indices = True @@ -160,57 +168,62 @@ html_show_sphinx = False # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True +# html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. -#html_use_opensearch = '' +# html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None +# html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'Seleniumdoc' +htmlhelp_basename = "Seleniumdoc" # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). -#latex_paper_size = 'letter' +# latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). -#latex_font_size = '10pt' +# latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', 'Selenium.tex', 'Selenium Documentation', - 'plightbo, simon.m.stewart, hbchai, jrhuggins, et al.', 'manual'), + ( + "index", + "Selenium.tex", + "Selenium Documentation", + "plightbo, simon.m.stewart, hbchai, jrhuggins, et al.", + "manual", + ), ] # The name of an image file (relative to this directory) to place at the top of # the title page. -#latex_logo = None +# latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -#latex_use_parts = False +# latex_use_parts = False # If true, show page references after internal links. -#latex_show_pagerefs = False +# latex_show_pagerefs = False # If true, show URL addresses after external links. -#latex_show_urls = False +# latex_show_urls = False # Additional stuff for the LaTeX preamble. -#latex_preamble = '' +# latex_preamble = '' # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# latex_appendices = [] # If false, no module index is generated. -#latex_domain_indices = True +# latex_domain_indices = True # -- Options for manual page output -------------------------------------------- @@ -218,64 +231,63 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'selenium', 'Selenium Documentation', - ['plightbo, simon.m.stewart, hbchai, jrhuggins, et al.'], 1) + ("index", "selenium", "Selenium Documentation", ["plightbo, simon.m.stewart, hbchai, jrhuggins, et al."], 1) ] # -- Options for Epub output --------------------------------------------------- # Bibliographic Dublin Core info. -epub_title = 'Selenium' -epub_author = 'The Selenium Project' -epub_publisher = 'The Selenium Project' -epub_copyright = '2009-2024 Software Freedom Conservancy' +epub_title = "Selenium" +epub_author = "The Selenium Project" +epub_publisher = "The Selenium Project" +epub_copyright = "2009-2024 Software Freedom Conservancy" # The language of the text. It defaults to the language option # or en if the language is not set. -#epub_language = '' +# epub_language = '' # The scheme of the identifier. Typical schemes are ISBN or URL. -#epub_scheme = '' +# epub_scheme = '' # The unique identifier of the text. This can be a ISBN number # or the project homepage. -#epub_identifier = '' +# epub_identifier = '' # A unique identification for the text. -#epub_uid = '' +# epub_uid = '' # HTML files that should be inserted before the pages created by sphinx. # The format is a list of tuples containing the path and title. -#epub_pre_files = [] +# epub_pre_files = [] # HTML files that should be inserted after the pages created by sphinx. # The format is a list of tuples containing the path and title. -#epub_post_files = [] +# epub_post_files = [] # A list of files that should not be packed into the epub file. -#epub_exclude_files = [] +# epub_exclude_files = [] # The depth of the table of contents in toc.ncx. -#epub_tocdepth = 3 +# epub_tocdepth = 3 # Allow duplicate toc entries. -#epub_tocdup = True +# epub_tocdup = True # Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'http://docs.python.org/': None} +intersphinx_mapping = {"http://docs.python.org/": None} # 'members' includes anything that has a docstring, 'undoc-members' includes # functions without docstrings. -autodoc_default_flags = ['members', 'undoc-members'] +autodoc_default_flags = ["members", "undoc-members"] # configuration for keeping the methods that can be invoked on said classes autodoc_default_options = { - 'members': True, - 'member-order': 'bysource', - 'undoc-members': True, - 'inherited-members': True, + "members": True, + "member-order": "bysource", + "undoc-members": True, + "inherited-members": True, } # Include __init__ comments diff --git a/py/private/untar.py b/py/private/untar.py index 6fcaf04c2e26e..8cead171688ca 100644 --- a/py/private/untar.py +++ b/py/private/untar.py @@ -19,7 +19,7 @@ import sys import tarfile -if __name__ == '__main__': +if __name__ == "__main__": outdir = sys.argv[2] if not os.path.exists(outdir): os.makedirs(outdir) diff --git a/py/pyproject.toml b/py/pyproject.toml index 7301cc2ed70f5..c33d41e6494d3 100644 --- a/py/pyproject.toml +++ b/py/pyproject.toml @@ -131,41 +131,19 @@ ignore_missing_imports = true # suppress error messages about imports that cannot be resolved. ignore_missing_imports = true -[tool.isort] -# isort is a common python tool for keeping imports nicely formatted. -# Automatically keep imports alphabetically sorted, on single lines in -# PEP recommended sections (https://peps.python.org/pep-0008/#imports) -# files or individual lines can be ignored via `# isort:skip|# isort:skip_file`. -force_single_line = true -profile = "black" -py_version = 39 -quiet = true -skip = "selenium/webdriver/common/devtools" - -[tool.black] -extend-exclude = "selenium/webdriver/common/devtools" +[tool.ruff] +extend-exclude = [ + "selenium/webdriver/common/devtools/", + "generate.py", +] line-length = 120 -target-version = ["py39"] - -[tool.autoflake] -exclude = "selenium/webdriver/common/devtools" -ignore-pass-after-docstring = true -in-place = true -quiet = true -recursive = true -remove-all-unused-imports = true -remove-duplicate-keys = true -remove-unused-variables = true +respect-gitignore = true +target-version = "py39" -[tool.flake8] -exclude = "selenium/webdriver/common/devtools" -# Disable E501 once line length is better handled -extend-ignore = ["E501", "E203"] -# This does nothing for now as E501 is ignored -max-line-length = 120 -min-python-version = "3.9" +[tool.ruff.lint] +extend-select = ["E4", "E7", "E9", "F", "I", "E501", "RUF022"] +fixable = ["ALL"] -[tool.docformatter] -exclude = "selenium/webdriver/common/devtools" -in-place = true -recursive = true +[tool.ruff.format] +docstring-code-format = true +docstring-code-line-length = 120 diff --git a/py/release-selenium.py b/py/release-selenium.py index 48d8180cd6e56..d0d558393046f 100644 --- a/py/release-selenium.py +++ b/py/release-selenium.py @@ -19,9 +19,11 @@ import sys from twine import cli + def main(): cli.configure_output() return cli.dispatch(sys.argv[1:]) + if __name__ == "__main__": sys.exit(main()) diff --git a/py/selenium/common/__init__.py b/py/selenium/common/__init__.py index 88269940125d9..88a124e31d4ef 100644 --- a/py/selenium/common/__init__.py +++ b/py/selenium/common/__init__.py @@ -15,74 +15,76 @@ # specific language governing permissions and limitations # under the License. -from .exceptions import DetachedShadowRootException -from .exceptions import ElementClickInterceptedException -from .exceptions import ElementNotInteractableException -from .exceptions import ElementNotSelectableException -from .exceptions import ElementNotVisibleException -from .exceptions import ImeActivationFailedException -from .exceptions import ImeNotAvailableException -from .exceptions import InsecureCertificateException -from .exceptions import InvalidArgumentException -from .exceptions import InvalidCookieDomainException -from .exceptions import InvalidCoordinatesException -from .exceptions import InvalidElementStateException -from .exceptions import InvalidSelectorException -from .exceptions import InvalidSessionIdException -from .exceptions import InvalidSwitchToTargetException -from .exceptions import JavascriptException -from .exceptions import MoveTargetOutOfBoundsException -from .exceptions import NoAlertPresentException -from .exceptions import NoSuchAttributeException -from .exceptions import NoSuchCookieException -from .exceptions import NoSuchDriverException -from .exceptions import NoSuchElementException -from .exceptions import NoSuchFrameException -from .exceptions import NoSuchShadowRootException -from .exceptions import NoSuchWindowException -from .exceptions import ScreenshotException -from .exceptions import SessionNotCreatedException -from .exceptions import StaleElementReferenceException -from .exceptions import TimeoutException -from .exceptions import UnableToSetCookieException -from .exceptions import UnexpectedAlertPresentException -from .exceptions import UnexpectedTagNameException -from .exceptions import UnknownMethodException -from .exceptions import WebDriverException +from .exceptions import ( + DetachedShadowRootException, + ElementClickInterceptedException, + ElementNotInteractableException, + ElementNotSelectableException, + ElementNotVisibleException, + ImeActivationFailedException, + ImeNotAvailableException, + InsecureCertificateException, + InvalidArgumentException, + InvalidCookieDomainException, + InvalidCoordinatesException, + InvalidElementStateException, + InvalidSelectorException, + InvalidSessionIdException, + InvalidSwitchToTargetException, + JavascriptException, + MoveTargetOutOfBoundsException, + NoAlertPresentException, + NoSuchAttributeException, + NoSuchCookieException, + NoSuchDriverException, + NoSuchElementException, + NoSuchFrameException, + NoSuchShadowRootException, + NoSuchWindowException, + ScreenshotException, + SessionNotCreatedException, + StaleElementReferenceException, + TimeoutException, + UnableToSetCookieException, + UnexpectedAlertPresentException, + UnexpectedTagNameException, + UnknownMethodException, + WebDriverException, +) __all__ = [ - "WebDriverException", - "InvalidSwitchToTargetException", - "NoSuchFrameException", - "NoSuchWindowException", - "NoSuchElementException", - "NoSuchAttributeException", - "NoSuchDriverException", - "NoSuchShadowRootException", - "StaleElementReferenceException", - "InvalidElementStateException", - "UnexpectedAlertPresentException", - "NoAlertPresentException", - "ElementNotVisibleException", + "DetachedShadowRootException", + "ElementClickInterceptedException", "ElementNotInteractableException", "ElementNotSelectableException", - "InvalidCookieDomainException", - "UnableToSetCookieException", - "TimeoutException", - "MoveTargetOutOfBoundsException", - "UnexpectedTagNameException", - "InvalidSelectorException", - "ImeNotAvailableException", + "ElementNotVisibleException", "ImeActivationFailedException", + "ImeNotAvailableException", + "InsecureCertificateException", "InvalidArgumentException", + "InvalidCookieDomainException", + "InvalidCoordinatesException", + "InvalidElementStateException", + "InvalidSelectorException", + "InvalidSessionIdException", + "InvalidSwitchToTargetException", "JavascriptException", + "MoveTargetOutOfBoundsException", + "NoAlertPresentException", + "NoSuchAttributeException", "NoSuchCookieException", + "NoSuchDriverException", + "NoSuchElementException", + "NoSuchFrameException", + "NoSuchShadowRootException", + "NoSuchWindowException", "ScreenshotException", - "ElementClickInterceptedException", - "InsecureCertificateException", - "InvalidCoordinatesException", - "InvalidSessionIdException", "SessionNotCreatedException", + "StaleElementReferenceException", + "TimeoutException", + "UnableToSetCookieException", + "UnexpectedAlertPresentException", + "UnexpectedTagNameException", "UnknownMethodException", - "DetachedShadowRootException", + "WebDriverException", ] diff --git a/py/selenium/common/exceptions.py b/py/selenium/common/exceptions.py index d1d7efdd1f0bd..645e81bdc24d3 100644 --- a/py/selenium/common/exceptions.py +++ b/py/selenium/common/exceptions.py @@ -16,8 +16,7 @@ # under the License. """Exceptions that may happen in all the webdriver code.""" -from typing import Optional -from typing import Sequence +from typing import Optional, Sequence SUPPORT_MSG = "For documentation on this error, please visit:" ERROR_URL = "https://www.selenium.dev/documentation/webdriver/troubleshooting/errors" diff --git a/py/selenium/types.py b/py/selenium/types.py index f055ea1452fff..b6af1d57e60e8 100644 --- a/py/selenium/types.py +++ b/py/selenium/types.py @@ -16,11 +16,7 @@ # under the License. """Selenium type definitions.""" -from typing import IO -from typing import Any -from typing import Iterable -from typing import Type -from typing import Union +from typing import IO, Any, Iterable, Type, Union AnyKey = Union[str, int, float] WaitExcTypes = Iterable[Type[Exception]] diff --git a/py/selenium/webdriver/__init__.py b/py/selenium/webdriver/__init__.py index 0c1f2902cce93..868c557ab9d40 100644 --- a/py/selenium/webdriver/__init__.py +++ b/py/selenium/webdriver/__init__.py @@ -48,32 +48,32 @@ # We need an explicit __all__ because the above won't otherwise be exported. __all__ = [ - "Firefox", - "FirefoxProfile", - "FirefoxOptions", - "FirefoxService", + "ActionChains", "Chrome", "ChromeOptions", "ChromeService", - "Ie", - "IeOptions", - "IeService", - "Edge", "ChromiumEdge", + "DesiredCapabilities", + "Edge", "EdgeOptions", "EdgeService", + "Firefox", + "FirefoxOptions", + "FirefoxProfile", + "FirefoxService", + "Ie", + "IeOptions", + "IeService", + "Keys", + "Proxy", + "Remote", "Safari", "SafariOptions", "SafariService", - "WebKitGTK", - "WebKitGTKOptions", - "WebKitGTKService", "WPEWebKit", "WPEWebKitOptions", "WPEWebKitService", - "Remote", - "DesiredCapabilities", - "ActionChains", - "Proxy", - "Keys", + "WebKitGTK", + "WebKitGTKOptions", + "WebKitGTKService", ] diff --git a/py/selenium/webdriver/chrome/service.py b/py/selenium/webdriver/chrome/service.py index 7c4074021caba..ff90b95eac651 100644 --- a/py/selenium/webdriver/chrome/service.py +++ b/py/selenium/webdriver/chrome/service.py @@ -16,9 +16,7 @@ # under the License. -from typing import List -from typing import Mapping -from typing import Optional +from typing import List, Mapping, Optional from selenium.types import SubprocessStdAlias from selenium.webdriver.chromium import service diff --git a/py/selenium/webdriver/chromium/options.py b/py/selenium/webdriver/chromium/options.py index 733641cea4430..a2f55ec1a5534 100644 --- a/py/selenium/webdriver/chromium/options.py +++ b/py/selenium/webdriver/chromium/options.py @@ -17,11 +17,7 @@ import base64 import os -from typing import BinaryIO -from typing import Dict -from typing import List -from typing import Optional -from typing import Union +from typing import BinaryIO, Dict, List, Optional, Union from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.common.options import ArgOptions diff --git a/py/selenium/webdriver/chromium/service.py b/py/selenium/webdriver/chromium/service.py index f520d1d86db89..897b6d1e7395d 100644 --- a/py/selenium/webdriver/chromium/service.py +++ b/py/selenium/webdriver/chromium/service.py @@ -15,9 +15,7 @@ # specific language governing permissions and limitations # under the License. from io import IOBase -from typing import List -from typing import Mapping -from typing import Optional +from typing import List, Mapping, Optional from selenium.types import SubprocessStdAlias from selenium.webdriver.common import service diff --git a/py/selenium/webdriver/chromium/webdriver.py b/py/selenium/webdriver/chromium/webdriver.py index 0ec4ec61e4574..5dd01e7677dfa 100644 --- a/py/selenium/webdriver/chromium/webdriver.py +++ b/py/selenium/webdriver/chromium/webdriver.py @@ -99,7 +99,8 @@ def set_network_conditions(self, **network_conditions) -> None: offline=False, latency=5, # additional latency (ms) download_throughput=500 * 1024, # maximal throughput - upload_throughput=500 * 1024) # maximal throughput + upload_throughput=500 * 1024, + ) # maximal throughput Note: 'throughput' can be used to set both (for download and upload). """ @@ -119,7 +120,7 @@ def set_permissions(self, name: str, value: str) -> None: :Usage: :: - driver.set_permissions('clipboard-read', 'denied') + driver.set_permissions("clipboard-read", "denied") """ self.execute("setPermissions", {"descriptor": {"name": name}, "state": value}) @@ -172,10 +173,10 @@ def get_log(self, log_type): Example: -------- - >>> driver.get_log('browser') - >>> driver.get_log('driver') - >>> driver.get_log('client') - >>> driver.get_log('server') + >>> driver.get_log("browser") + >>> driver.get_log("driver") + >>> driver.get_log("client") + >>> driver.get_log("server") """ return self.execute(Command.GET_LOG, {"type": log_type})["value"] diff --git a/py/selenium/webdriver/common/action_chains.py b/py/selenium/webdriver/common/action_chains.py index a0a0f2cd2d5ce..7dcf5cae7f143 100644 --- a/py/selenium/webdriver/common/action_chains.py +++ b/py/selenium/webdriver/common/action_chains.py @@ -15,18 +15,17 @@ # specific language governing permissions and limitations # under the License. """The ActionChains implementation.""" + from __future__ import annotations -from typing import TYPE_CHECKING -from typing import Union +from typing import TYPE_CHECKING, Union from selenium.webdriver.remote.webelement import WebElement from .actions.action_builder import ActionBuilder from .actions.key_input import KeyInput from .actions.pointer_input import PointerInput -from .actions.wheel_input import ScrollOrigin -from .actions.wheel_input import WheelInput +from .actions.wheel_input import ScrollOrigin, WheelInput from .utils import keys_to_typing if TYPE_CHECKING: @@ -200,7 +199,7 @@ def key_down(self, value: str, element: WebElement | None = None) -> ActionChain Example, pressing ctrl+c:: - ActionChains(driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform() + ActionChains(driver).key_down(Keys.CONTROL).send_keys("c").key_up(Keys.CONTROL).perform() """ if element: self.click(element) @@ -220,7 +219,7 @@ def key_up(self, value: str, element: WebElement | None = None) -> ActionChains: Example, pressing ctrl+c:: - ActionChains(driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform() + ActionChains(driver).key_down(Keys.CONTROL).send_keys("c").key_up(Keys.CONTROL).perform() """ if element: self.click(element) diff --git a/py/selenium/webdriver/common/actions/action_builder.py b/py/selenium/webdriver/common/actions/action_builder.py index f959fbff6fd10..5cbb1c7f1aad0 100644 --- a/py/selenium/webdriver/common/actions/action_builder.py +++ b/py/selenium/webdriver/common/actions/action_builder.py @@ -15,9 +15,7 @@ # specific language governing permissions and limitations # under the License. -from typing import List -from typing import Optional -from typing import Union +from typing import List, Optional, Union from selenium.webdriver.remote.command import Command @@ -159,7 +157,7 @@ def perform(self) -> None: >>> action_builder = ActionBuilder(driver) >>> keyboard = action_builder.key_input >>> el = driver.find_element(id: "some_id") - >>> action_builder.click(el).pause(keyboard).pause(keyboard).pause(keyboard).send_keys('keys').perform() + >>> action_builder.click(el).pause(keyboard).pause(keyboard).pause(keyboard).send_keys("keys").perform() """ enc = {"actions": []} for device in self.devices: @@ -177,7 +175,7 @@ def clear_actions(self) -> None: >>> action_builder = ActionBuilder(driver) >>> keyboard = action_builder.key_input >>> el = driver.find_element(By.ID, "some_id") - >>> action_builder.click(el).pause(keyboard).pause(keyboard).pause(keyboard).send_keys('keys') + >>> action_builder.click(el).pause(keyboard).pause(keyboard).pause(keyboard).send_keys("keys") >>> action_builder.clear_actions() """ self.driver.execute(Command.W3C_CLEAR_ACTIONS) diff --git a/py/selenium/webdriver/common/actions/input_device.py b/py/selenium/webdriver/common/actions/input_device.py index d9b2eee2739ac..70b4caacb55f2 100644 --- a/py/selenium/webdriver/common/actions/input_device.py +++ b/py/selenium/webdriver/common/actions/input_device.py @@ -16,9 +16,7 @@ # under the License. import uuid -from typing import Any -from typing import List -from typing import Optional +from typing import Any, List, Optional class InputDevice: diff --git a/py/selenium/webdriver/common/actions/interaction.py b/py/selenium/webdriver/common/actions/interaction.py index 05b66270cb2ae..2af9318173b8e 100644 --- a/py/selenium/webdriver/common/actions/interaction.py +++ b/py/selenium/webdriver/common/actions/interaction.py @@ -14,8 +14,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -from typing import Dict -from typing import Union +from typing import Dict, Union KEY = "key" POINTER = "pointer" diff --git a/py/selenium/webdriver/common/actions/key_actions.py b/py/selenium/webdriver/common/actions/key_actions.py index 94caed9bdd192..1c1278e6ba5d5 100644 --- a/py/selenium/webdriver/common/actions/key_actions.py +++ b/py/selenium/webdriver/common/actions/key_actions.py @@ -17,8 +17,7 @@ from __future__ import annotations from ..utils import keys_to_typing -from .interaction import KEY -from .interaction import Interaction +from .interaction import KEY, Interaction from .key_input import KeyInput from .pointer_input import PointerInput from .wheel_input import WheelInput diff --git a/py/selenium/webdriver/common/actions/key_input.py b/py/selenium/webdriver/common/actions/key_input.py index b578eebad0f38..d9a4b278ae246 100644 --- a/py/selenium/webdriver/common/actions/key_input.py +++ b/py/selenium/webdriver/common/actions/key_input.py @@ -16,8 +16,7 @@ # under the License. from . import interaction from .input_device import InputDevice -from .interaction import Interaction -from .interaction import Pause +from .interaction import Interaction, Pause class KeyInput(InputDevice): diff --git a/py/selenium/webdriver/common/actions/pointer_input.py b/py/selenium/webdriver/common/actions/pointer_input.py index 0d7e7a87188c1..d7296bd35f5de 100644 --- a/py/selenium/webdriver/common/actions/pointer_input.py +++ b/py/selenium/webdriver/common/actions/pointer_input.py @@ -15,17 +15,13 @@ # specific language governing permissions and limitations # under the License. -from typing import Any -from typing import Dict -from typing import Optional -from typing import Union +from typing import Any, Dict, Optional, Union from selenium.common.exceptions import InvalidArgumentException from selenium.webdriver.remote.webelement import WebElement from .input_device import InputDevice -from .interaction import POINTER -from .interaction import POINTER_KINDS +from .interaction import POINTER, POINTER_KINDS class PointerInput(InputDevice): diff --git a/py/selenium/webdriver/common/alert.py b/py/selenium/webdriver/common/alert.py index e7fd64b72786b..ef26de858def1 100644 --- a/py/selenium/webdriver/common/alert.py +++ b/py/selenium/webdriver/common/alert.py @@ -67,7 +67,7 @@ def accept(self) -> None: :Usage: :: - Alert(driver).accept() # Confirm a alert dialog. + Alert(driver).accept() # Confirm a alert dialog. """ self.driver.execute(Command.W3C_ACCEPT_ALERT) diff --git a/py/selenium/webdriver/common/bidi/browser.py b/py/selenium/webdriver/common/bidi/browser.py index a32c29847372d..261987619e08d 100644 --- a/py/selenium/webdriver/common/bidi/browser.py +++ b/py/selenium/webdriver/common/bidi/browser.py @@ -15,8 +15,7 @@ # specific language governing permissions and limitations # under the License. -from typing import Dict -from typing import List +from typing import Dict, List from selenium.webdriver.common.bidi.common import command_builder diff --git a/py/selenium/webdriver/common/bidi/browsing_context.py b/py/selenium/webdriver/common/bidi/browsing_context.py index 8faa814d6f966..b2ea4e152abe4 100644 --- a/py/selenium/webdriver/common/bidi/browsing_context.py +++ b/py/selenium/webdriver/common/bidi/browsing_context.py @@ -15,10 +15,7 @@ # specific language governing permissions and limitations # under the License. -from typing import Dict -from typing import List -from typing import Optional -from typing import Union +from typing import Dict, List, Optional, Union from selenium.webdriver.common.bidi.common import command_builder @@ -402,7 +399,8 @@ def get_tree( max_depth: Optional[int] = None, root: Optional[str] = None, ) -> List[BrowsingContextInfo]: - """Returns a tree of all descendent navigables including the given parent itself, or all top-level contexts when no parent is provided. + """Returns a tree of all descendent navigables including the given parent itself, or all top-level contexts + when no parent is provided. Parameters: ----------- @@ -513,7 +511,8 @@ def print( scale: float = 1.0, shrink_to_fit: bool = True, ) -> str: - """Creates a paginated representation of a document, and returns it as a PDF document represented as a Base64-encoded string. + """Creates a paginated representation of a document, and returns it as a PDF document represented as a + Base64-encoded string. Parameters: ----------- diff --git a/py/selenium/webdriver/common/bidi/session.py b/py/selenium/webdriver/common/bidi/session.py index 693f2b4931ba4..064be34b26b7c 100644 --- a/py/selenium/webdriver/common/bidi/session.py +++ b/py/selenium/webdriver/common/bidi/session.py @@ -19,7 +19,6 @@ class Session: - def __init__(self, conn): self.conn = conn diff --git a/py/selenium/webdriver/common/bidi/storage.py b/py/selenium/webdriver/common/bidi/storage.py index b531054ea689e..02211f05e68a3 100644 --- a/py/selenium/webdriver/common/bidi/storage.py +++ b/py/selenium/webdriver/common/bidi/storage.py @@ -15,10 +15,7 @@ # specific language governing permissions and limitations # under the License. -from typing import Dict -from typing import List -from typing import Optional -from typing import Union +from typing import Dict, List, Optional, Union from selenium.webdriver.common.bidi.common import command_builder diff --git a/py/selenium/webdriver/common/by.py b/py/selenium/webdriver/common/by.py index dab351ff55dd2..45d2c3eff6237 100644 --- a/py/selenium/webdriver/common/by.py +++ b/py/selenium/webdriver/common/by.py @@ -16,9 +16,7 @@ # under the License. """The By implementation.""" -from typing import Dict -from typing import Literal -from typing import Optional +from typing import Dict, Literal, Optional class By: @@ -28,7 +26,7 @@ class By: -- Select the element by its ID. - >>> element = driver.find_element(By.ID, 'myElement') + >>> element = driver.find_element(By.ID, "myElement") XPATH: ------ @@ -36,43 +34,43 @@ class By: - absolute path - relative path - >>> element = driver.find_element(By.XPATH, '//html/body/div') + >>> element = driver.find_element(By.XPATH, "//html/body/div") LINK_TEXT: ---------- Select the link element having the exact text. - >>> element = driver.find_element(By.LINK_TEXT, 'myLink') + >>> element = driver.find_element(By.LINK_TEXT, "myLink") PARTIAL_LINK_TEXT: ------------------ Select the link element having the partial text. - >>> element = driver.find_element(By.PARTIAL_LINK_TEXT, 'my') + >>> element = driver.find_element(By.PARTIAL_LINK_TEXT, "my") NAME: ---- Select the element by its name attribute. - >>> element = driver.find_element(By.NAME, 'myElement') + >>> element = driver.find_element(By.NAME, "myElement") TAG_NAME: -------- Select the element by its tag name. - >>> element = driver.find_element(By.TAG_NAME, 'div') + >>> element = driver.find_element(By.TAG_NAME, "div") CLASS_NAME: ----------- Select the element by its class name. - >>> element = driver.find_element(By.CLASS_NAME, 'myElement') + >>> element = driver.find_element(By.CLASS_NAME, "myElement") CSS_SELECTOR: ------------- Select the element by its CSS selector. - >>> element = driver.find_element(By.CSS_SELECTOR, 'div.myElement') + >>> element = driver.find_element(By.CSS_SELECTOR, "div.myElement") """ ID = "id" diff --git a/py/selenium/webdriver/common/desired_capabilities.py b/py/selenium/webdriver/common/desired_capabilities.py index 1d78019165f9d..89d7168436315 100644 --- a/py/selenium/webdriver/common/desired_capabilities.py +++ b/py/selenium/webdriver/common/desired_capabilities.py @@ -31,12 +31,11 @@ class DesiredCapabilities: # Create a desired capabilities object as a starting point. capabilities = DesiredCapabilities.FIREFOX.copy() - capabilities['platform'] = "WINDOWS" - capabilities['version'] = "10" + capabilities["platform"] = "WINDOWS" + capabilities["version"] = "10" # Instantiate an instance of Remote WebDriver with the desired capabilities. - driver = webdriver.Remote(desired_capabilities=capabilities, - command_executor=selenium_grid_url) + driver = webdriver.Remote(desired_capabilities=capabilities, command_executor=selenium_grid_url) Note: Always use '.copy()' on the DesiredCapabilities object to avoid the side effects of altering the Global class instance. diff --git a/py/selenium/webdriver/common/driver_finder.py b/py/selenium/webdriver/common/driver_finder.py index 5a5cb01c5db7f..2c8aeb365706c 100644 --- a/py/selenium/webdriver/common/driver_finder.py +++ b/py/selenium/webdriver/common/driver_finder.py @@ -68,11 +68,11 @@ def _binary_paths(self) -> dict: if Path(output["driver_path"]).is_file(): self._paths["driver_path"] = output["driver_path"] else: - raise ValueError(f'The driver path is not a valid file: {output["driver_path"]}') + raise ValueError(f"The driver path is not a valid file: {output['driver_path']}") if Path(output["browser_path"]).is_file(): self._paths["browser_path"] = output["browser_path"] else: - raise ValueError(f'The browser path is not a valid file: {output["browser_path"]}') + raise ValueError(f"The browser path is not a valid file: {output['browser_path']}") except Exception as err: msg = f"Unable to obtain driver for {browser}" raise NoSuchDriverException(msg) from err diff --git a/py/selenium/webdriver/common/fedcm/dialog.py b/py/selenium/webdriver/common/fedcm/dialog.py index fce069d00d767..86bca67c79fcf 100644 --- a/py/selenium/webdriver/common/fedcm/dialog.py +++ b/py/selenium/webdriver/common/fedcm/dialog.py @@ -15,8 +15,7 @@ # specific language governing permissions and limitations # under the License. -from typing import List -from typing import Optional +from typing import List, Optional from .account import Account diff --git a/py/selenium/webdriver/common/log.py b/py/selenium/webdriver/common/log.py index f881ca614b838..c65f770dfff3f 100644 --- a/py/selenium/webdriver/common/log.py +++ b/py/selenium/webdriver/common/log.py @@ -19,10 +19,7 @@ import pkgutil from contextlib import asynccontextmanager from importlib import import_module -from typing import Any -from typing import AsyncGenerator -from typing import Dict -from typing import Optional +from typing import Any, AsyncGenerator, Dict, Optional from selenium.webdriver.common.by import By @@ -90,7 +87,7 @@ async def mutation_events(self) -> AsyncGenerator[Dict[str, Any], None]: yield event payload = json.loads(evnt.value.payload) - elements: list = self.driver.find_elements(By.CSS_SELECTOR, f"*[data-__webdriver_id=\"{payload['target']}\"]") + elements: list = self.driver.find_elements(By.CSS_SELECTOR, f'*[data-__webdriver_id="{payload["target"]}"]') if not elements: elements.append(None) event["element"] = elements[0] diff --git a/py/selenium/webdriver/common/options.py b/py/selenium/webdriver/common/options.py index c43e0fb0a912e..673cc4a140c69 100644 --- a/py/selenium/webdriver/common/options.py +++ b/py/selenium/webdriver/common/options.py @@ -16,11 +16,9 @@ # under the License. import warnings -from abc import ABCMeta -from abc import abstractmethod +from abc import ABCMeta, abstractmethod from enum import Enum -from typing import List -from typing import Optional +from typing import List, Optional from selenium.common.exceptions import InvalidArgumentException from selenium.webdriver.common.proxy import Proxy diff --git a/py/selenium/webdriver/common/print_page_options.py b/py/selenium/webdriver/common/print_page_options.py index 6a532aae78ae3..500b6cfc5ce75 100644 --- a/py/selenium/webdriver/common/print_page_options.py +++ b/py/selenium/webdriver/common/print_page_options.py @@ -16,14 +16,10 @@ # under the License. -from typing import TYPE_CHECKING -from typing import List -from typing import Optional -from typing import Type +from typing import TYPE_CHECKING, List, Optional, Type if TYPE_CHECKING: - from typing import Literal - from typing import TypedDict + from typing import Literal, TypedDict Orientation = Literal["portrait", "landscape"] @@ -47,8 +43,7 @@ class _PrintOpts(TypedDict, total=False): pageRanges: List[str] else: - from typing import Any - from typing import Dict + from typing import Any, Dict Orientation = str _MarginOpts = _PageOpts = _PrintOpts = Dict[str, Any] diff --git a/py/selenium/webdriver/common/selenium_manager.py b/py/selenium/webdriver/common/selenium_manager.py index 469965fef45b0..0e20de5373441 100644 --- a/py/selenium/webdriver/common/selenium_manager.py +++ b/py/selenium/webdriver/common/selenium_manager.py @@ -22,8 +22,7 @@ import sys import sysconfig from pathlib import Path -from typing import List -from typing import Optional +from typing import List, Optional from selenium.common import WebDriverException diff --git a/py/selenium/webdriver/common/service.py b/py/selenium/webdriver/common/service.py index 5d60aba6bd75a..b26d20c95cafa 100644 --- a/py/selenium/webdriver/common/service.py +++ b/py/selenium/webdriver/common/service.py @@ -18,19 +18,12 @@ import logging import os import subprocess -from abc import ABC -from abc import abstractmethod +from abc import ABC, abstractmethod from io import IOBase from platform import system from subprocess import PIPE from time import sleep -from typing import IO -from typing import Any -from typing import List -from typing import Mapping -from typing import Optional -from typing import Union -from typing import cast +from typing import IO, Any, List, Mapping, Optional, Union, cast from urllib import request from urllib.error import URLError diff --git a/py/selenium/webdriver/common/utils.py b/py/selenium/webdriver/common/utils.py index 766dd1b53b370..483fe415eca0f 100644 --- a/py/selenium/webdriver/common/utils.py +++ b/py/selenium/webdriver/common/utils.py @@ -17,10 +17,7 @@ """The Utils methods.""" import socket -from typing import Iterable -from typing import List -from typing import Optional -from typing import Union +from typing import Iterable, List, Optional, Union from selenium.types import AnyKey from selenium.webdriver.common.keys import Keys diff --git a/py/selenium/webdriver/common/virtual_authenticator.py b/py/selenium/webdriver/common/virtual_authenticator.py index 6e1deb684c898..631b619dc76d6 100644 --- a/py/selenium/webdriver/common/virtual_authenticator.py +++ b/py/selenium/webdriver/common/virtual_authenticator.py @@ -16,13 +16,9 @@ # under the License. import functools -from base64 import urlsafe_b64decode -from base64 import urlsafe_b64encode +from base64 import urlsafe_b64decode, urlsafe_b64encode from enum import Enum -from typing import Any -from typing import Dict -from typing import Optional -from typing import Union +from typing import Any, Dict, Optional, Union class Protocol(str, Enum): diff --git a/py/selenium/webdriver/edge/service.py b/py/selenium/webdriver/edge/service.py index 8834a63d50846..fcdb4f37d1dbf 100644 --- a/py/selenium/webdriver/edge/service.py +++ b/py/selenium/webdriver/edge/service.py @@ -15,9 +15,7 @@ # specific language governing permissions and limitations # under the License. -from typing import List -from typing import Mapping -from typing import Optional +from typing import List, Mapping, Optional from selenium.types import SubprocessStdAlias from selenium.webdriver.chromium import service diff --git a/py/selenium/webdriver/firefox/firefox_binary.py b/py/selenium/webdriver/firefox/firefox_binary.py index d4cea3368858e..6490c1f9db621 100644 --- a/py/selenium/webdriver/firefox/firefox_binary.py +++ b/py/selenium/webdriver/firefox/firefox_binary.py @@ -19,9 +19,7 @@ import os import time from platform import system -from subprocess import DEVNULL -from subprocess import STDOUT -from subprocess import Popen +from subprocess import DEVNULL, STDOUT, Popen from typing_extensions import deprecated @@ -124,12 +122,9 @@ def _wait_until_connectable(self, timeout=30): def _find_exe_in_registry(self): try: - from _winreg import HKEY_CURRENT_USER - from _winreg import HKEY_LOCAL_MACHINE - from _winreg import OpenKey - from _winreg import QueryValue + from _winreg import HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, OpenKey, QueryValue except ImportError: - from winreg import OpenKey, QueryValue, HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER + from winreg import HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, OpenKey, QueryValue import shlex keys = ( diff --git a/py/selenium/webdriver/firefox/firefox_profile.py b/py/selenium/webdriver/firefox/firefox_profile.py index 6b1dce381b387..41bb9a4ba91f5 100644 --- a/py/selenium/webdriver/firefox/firefox_profile.py +++ b/py/selenium/webdriver/firefox/firefox_profile.py @@ -229,10 +229,12 @@ def _addon_details(self, addon_path): Returns:: - {'id': u'rainbow@colors.org', # id of the addon - 'version': u'1.4', # version of the addon - 'name': u'Rainbow', # name of the addon - 'unpack': False } # whether to unpack the addon + { + "id": "rainbow@colors.org", # id of the addon + "version": "1.4", # version of the addon + "name": "Rainbow", # name of the addon + "unpack": False, + } # whether to unpack the addon """ details = {"id": None, "unpack": False, "name": None, "version": None} diff --git a/py/selenium/webdriver/firefox/options.py b/py/selenium/webdriver/firefox/options.py index 81c4f28257b4c..0a2fb13031e62 100644 --- a/py/selenium/webdriver/firefox/options.py +++ b/py/selenium/webdriver/firefox/options.py @@ -14,10 +14,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -from typing import Any -from typing import Dict -from typing import Optional -from typing import Union +from typing import Any, Dict, Optional, Union from typing_extensions import deprecated diff --git a/py/selenium/webdriver/firefox/service.py b/py/selenium/webdriver/firefox/service.py index 9f45e74699ede..b957df8ed8b3b 100644 --- a/py/selenium/webdriver/firefox/service.py +++ b/py/selenium/webdriver/firefox/service.py @@ -14,13 +14,10 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -from typing import List -from typing import Mapping -from typing import Optional +from typing import List, Mapping, Optional from selenium.types import SubprocessStdAlias -from selenium.webdriver.common import service -from selenium.webdriver.common import utils +from selenium.webdriver.common import service, utils class Service(service.Service): diff --git a/py/selenium/webdriver/firefox/webdriver.py b/py/selenium/webdriver/firefox/webdriver.py index 8167b30d3d573..643a330f306c2 100644 --- a/py/selenium/webdriver/firefox/webdriver.py +++ b/py/selenium/webdriver/firefox/webdriver.py @@ -123,7 +123,7 @@ def install_addon(self, path, temporary=False) -> str: :Usage: :: - driver.install_addon('/path/to/firebug.xpi') + driver.install_addon("/path/to/firebug.xpi") """ if os.path.isdir(path): @@ -151,7 +151,7 @@ def uninstall_addon(self, identifier) -> None: :Usage: :: - driver.uninstall_addon('addon@foo.com') + driver.uninstall_addon("addon@foo.com") """ self.execute("UNINSTALL_ADDON", {"id": identifier}) @@ -167,7 +167,7 @@ def get_full_page_screenshot_as_file(self, filename) -> bool: :Usage: :: - driver.get_full_page_screenshot_as_file('/Screenshots/foo.png') + driver.get_full_page_screenshot_as_file("/Screenshots/foo.png") """ if not filename.lower().endswith(".png"): warnings.warn( @@ -196,7 +196,7 @@ def save_full_page_screenshot(self, filename) -> bool: :Usage: :: - driver.save_full_page_screenshot('/Screenshots/foo.png') + driver.save_full_page_screenshot("/Screenshots/foo.png") """ return self.get_full_page_screenshot_as_file(filename) diff --git a/py/selenium/webdriver/ie/options.py b/py/selenium/webdriver/ie/options.py index 3e4dcbed9b4f3..404bc1ad5aa48 100644 --- a/py/selenium/webdriver/ie/options.py +++ b/py/selenium/webdriver/ie/options.py @@ -15,8 +15,7 @@ # specific language governing permissions and limitations # under the License. from enum import Enum -from typing import Any -from typing import Dict +from typing import Any, Dict from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.common.options import ArgOptions diff --git a/py/selenium/webdriver/ie/service.py b/py/selenium/webdriver/ie/service.py index 537c42138b5f7..083590c5751aa 100644 --- a/py/selenium/webdriver/ie/service.py +++ b/py/selenium/webdriver/ie/service.py @@ -14,8 +14,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -from typing import List -from typing import Optional +from typing import List, Optional from selenium.types import SubprocessStdAlias from selenium.webdriver.common import service diff --git a/py/selenium/webdriver/remote/client_config.py b/py/selenium/webdriver/remote/client_config.py index 3157e63b6cf70..050dd18e05482 100644 --- a/py/selenium/webdriver/remote/client_config.py +++ b/py/selenium/webdriver/remote/client_config.py @@ -24,8 +24,7 @@ import certifi -from selenium.webdriver.common.proxy import Proxy -from selenium.webdriver.common.proxy import ProxyType +from selenium.webdriver.common.proxy import Proxy, ProxyType class AuthType(Enum): diff --git a/py/selenium/webdriver/remote/errorhandler.py b/py/selenium/webdriver/remote/errorhandler.py index d2df3b1b8e241..f734283292977 100644 --- a/py/selenium/webdriver/remote/errorhandler.py +++ b/py/selenium/webdriver/remote/errorhandler.py @@ -15,40 +15,40 @@ # specific language governing permissions and limitations # under the License. -from typing import Any -from typing import Dict -from typing import Type - -from selenium.common.exceptions import DetachedShadowRootException -from selenium.common.exceptions import ElementClickInterceptedException -from selenium.common.exceptions import ElementNotInteractableException -from selenium.common.exceptions import ElementNotSelectableException -from selenium.common.exceptions import ElementNotVisibleException -from selenium.common.exceptions import ImeActivationFailedException -from selenium.common.exceptions import ImeNotAvailableException -from selenium.common.exceptions import InsecureCertificateException -from selenium.common.exceptions import InvalidArgumentException -from selenium.common.exceptions import InvalidCookieDomainException -from selenium.common.exceptions import InvalidCoordinatesException -from selenium.common.exceptions import InvalidElementStateException -from selenium.common.exceptions import InvalidSelectorException -from selenium.common.exceptions import InvalidSessionIdException -from selenium.common.exceptions import JavascriptException -from selenium.common.exceptions import MoveTargetOutOfBoundsException -from selenium.common.exceptions import NoAlertPresentException -from selenium.common.exceptions import NoSuchCookieException -from selenium.common.exceptions import NoSuchElementException -from selenium.common.exceptions import NoSuchFrameException -from selenium.common.exceptions import NoSuchShadowRootException -from selenium.common.exceptions import NoSuchWindowException -from selenium.common.exceptions import ScreenshotException -from selenium.common.exceptions import SessionNotCreatedException -from selenium.common.exceptions import StaleElementReferenceException -from selenium.common.exceptions import TimeoutException -from selenium.common.exceptions import UnableToSetCookieException -from selenium.common.exceptions import UnexpectedAlertPresentException -from selenium.common.exceptions import UnknownMethodException -from selenium.common.exceptions import WebDriverException +from typing import Any, Dict, Type + +from selenium.common.exceptions import ( + DetachedShadowRootException, + ElementClickInterceptedException, + ElementNotInteractableException, + ElementNotSelectableException, + ElementNotVisibleException, + ImeActivationFailedException, + ImeNotAvailableException, + InsecureCertificateException, + InvalidArgumentException, + InvalidCookieDomainException, + InvalidCoordinatesException, + InvalidElementStateException, + InvalidSelectorException, + InvalidSessionIdException, + JavascriptException, + MoveTargetOutOfBoundsException, + NoAlertPresentException, + NoSuchCookieException, + NoSuchElementException, + NoSuchFrameException, + NoSuchShadowRootException, + NoSuchWindowException, + ScreenshotException, + SessionNotCreatedException, + StaleElementReferenceException, + TimeoutException, + UnableToSetCookieException, + UnexpectedAlertPresentException, + UnknownMethodException, + WebDriverException, +) class ExceptionMapping: diff --git a/py/selenium/webdriver/remote/fedcm.py b/py/selenium/webdriver/remote/fedcm.py index eb2331923c2d5..cf877789d3964 100644 --- a/py/selenium/webdriver/remote/fedcm.py +++ b/py/selenium/webdriver/remote/fedcm.py @@ -15,8 +15,7 @@ # specific language governing permissions and limitations # under the License. -from typing import List -from typing import Optional +from typing import List, Optional from .command import Command diff --git a/py/selenium/webdriver/remote/file_detector.py b/py/selenium/webdriver/remote/file_detector.py index 77ce2a546dcfa..87944fdb9d93b 100644 --- a/py/selenium/webdriver/remote/file_detector.py +++ b/py/selenium/webdriver/remote/file_detector.py @@ -15,8 +15,7 @@ # specific language governing permissions and limitations # under the License. -from abc import ABCMeta -from abc import abstractmethod +from abc import ABCMeta, abstractmethod from contextlib import suppress from pathlib import Path from typing import Optional diff --git a/py/selenium/webdriver/remote/switch_to.py b/py/selenium/webdriver/remote/switch_to.py index 8da7563113189..1fad0f74a0d68 100644 --- a/py/selenium/webdriver/remote/switch_to.py +++ b/py/selenium/webdriver/remote/switch_to.py @@ -15,12 +15,9 @@ # specific language governing permissions and limitations # under the License. -from typing import Optional -from typing import Union +from typing import Optional, Union -from selenium.common.exceptions import NoSuchElementException -from selenium.common.exceptions import NoSuchFrameException -from selenium.common.exceptions import NoSuchWindowException +from selenium.common.exceptions import NoSuchElementException, NoSuchFrameException, NoSuchWindowException from selenium.webdriver.common.alert import Alert from selenium.webdriver.common.by import By from selenium.webdriver.remote.webelement import WebElement @@ -79,7 +76,7 @@ def frame(self, frame_reference: Union[str, int, WebElement]) -> None: :Usage: :: - driver.switch_to.frame('frame_name') + driver.switch_to.frame("frame_name") driver.switch_to.frame(1) driver.switch_to.frame(driver.find_elements(By.TAG_NAME, "iframe")[0]) """ @@ -103,7 +100,7 @@ def new_window(self, type_hint: Optional[str] = None) -> None: :Usage: :: - driver.switch_to.new_window('tab') + driver.switch_to.new_window("tab") """ value = self._driver.execute(Command.NEW_WINDOW, {"type": type_hint})["value"] self._w3c_window(value["handle"]) @@ -128,7 +125,7 @@ def window(self, window_name: str) -> None: :Usage: :: - driver.switch_to.window('main') + driver.switch_to.window("main") """ self._w3c_window(window_name) diff --git a/py/selenium/webdriver/remote/utils.py b/py/selenium/webdriver/remote/utils.py index ec849b2ea2fd5..8e440e0e1246e 100644 --- a/py/selenium/webdriver/remote/utils.py +++ b/py/selenium/webdriver/remote/utils.py @@ -16,8 +16,7 @@ # under the License. import json -from typing import Any -from typing import Union +from typing import Any, Union def dump_json(json_struct: Any) -> str: diff --git a/py/selenium/webdriver/remote/webdriver.py b/py/selenium/webdriver/remote/webdriver.py index 336b05ea0107f..01530a05b1708 100644 --- a/py/selenium/webdriver/remote/webdriver.py +++ b/py/selenium/webdriver/remote/webdriver.py @@ -27,23 +27,18 @@ import warnings import zipfile from abc import ABCMeta -from base64 import b64decode -from base64 import urlsafe_b64encode -from contextlib import asynccontextmanager -from contextlib import contextmanager +from base64 import b64decode, urlsafe_b64encode +from contextlib import asynccontextmanager, contextmanager from importlib import import_module -from typing import Any -from typing import Dict -from typing import List -from typing import Optional -from typing import Type -from typing import Union - -from selenium.common.exceptions import InvalidArgumentException -from selenium.common.exceptions import JavascriptException -from selenium.common.exceptions import NoSuchCookieException -from selenium.common.exceptions import NoSuchElementException -from selenium.common.exceptions import WebDriverException +from typing import Any, Dict, List, Optional, Type, Union + +from selenium.common.exceptions import ( + InvalidArgumentException, + JavascriptException, + NoSuchCookieException, + NoSuchElementException, + WebDriverException, +) from selenium.webdriver.common.bidi.browser import Browser from selenium.webdriver.common.bidi.browsing_context import BrowsingContext from selenium.webdriver.common.bidi.network import Network @@ -51,13 +46,12 @@ from selenium.webdriver.common.bidi.session import Session from selenium.webdriver.common.bidi.storage import Storage from selenium.webdriver.common.by import By -from selenium.webdriver.common.options import ArgOptions -from selenium.webdriver.common.options import BaseOptions +from selenium.webdriver.common.options import ArgOptions, BaseOptions from selenium.webdriver.common.print_page_options import PrintOptions from selenium.webdriver.common.timeouts import Timeouts -from selenium.webdriver.common.virtual_authenticator import Credential -from selenium.webdriver.common.virtual_authenticator import VirtualAuthenticatorOptions from selenium.webdriver.common.virtual_authenticator import ( + Credential, + VirtualAuthenticatorOptions, required_virtual_authenticator, ) from selenium.webdriver.support.relative_locator import RelativeBy @@ -68,8 +62,7 @@ from .command import Command from .errorhandler import ErrorHandler from .fedcm import FedCM -from .file_detector import FileDetector -from .file_detector import LocalFileDetector +from .file_detector import FileDetector, LocalFileDetector from .locator_converter import LocatorConverter from .mobile import Mobile from .remote_connection import RemoteConnection @@ -217,7 +210,8 @@ def __init__( keep_alive : bool (Deprecated) - Whether to configure remote_connection.RemoteConnection to use HTTP keep-alive. Defaults to True. file_detector : object or None - - Pass a custom file detector object during instantiation. If None, the default LocalFileDetector() will be used. + - Pass a custom file detector object during instantiation. If None, the default + LocalFileDetector() will be used. options : options.Options - Instance of a driver options.Options class. locator_converter : object or None @@ -418,7 +412,7 @@ def execute_cdp_cmd(self, cmd: str, cmd_args: dict): Example: -------- - >>> driver.execute_cdp_cmd('Network.getResponseBody', {'requestId': requestId}) + >>> driver.execute_cdp_cmd("Network.getResponseBody", {"requestId": requestId}) """ return self.execute("executeCdpCommand", {"cmd": cmd, "params": cmd_args})["value"] @@ -481,7 +475,7 @@ def title(self) -> str: Example: -------- - >>> element = driver.find_element(By.ID, 'foo') + >>> element = driver.find_element(By.ID, "foo") >>> print(element.title()) """ return self.execute(Command.GET_TITLE).get("value", "") @@ -534,9 +528,7 @@ def execute_script(self, script: str, *args): -------- >>> input_id = "username" >>> input_value = "test_user" - >>> driver.execute_script( - ... "document.getElementById(arguments[0]).value = arguments[1];", input_id, input_value - ... ) + >>> driver.execute_script("document.getElementById(arguments[0]).value = arguments[1];", input_id, input_value) """ if isinstance(script, ScriptKey): try: @@ -685,11 +677,11 @@ def switch_to(self) -> SwitchTo: >>> element = driver.switch_to.active_element >>> alert = driver.switch_to.alert >>> driver.switch_to.default_content() - >>> driver.switch_to.frame('frame_name') + >>> driver.switch_to.frame("frame_name") >>> driver.switch_to.frame(1) >>> driver.switch_to.frame(driver.find_elements(By.TAG_NAME, "iframe")[0]) >>> driver.switch_to.parent_frame() - >>> driver.switch_to.window('main') + >>> driver.switch_to.window("main") """ return self._switch_to @@ -742,7 +734,7 @@ def get_cookie(self, name) -> Optional[Dict]: Example: -------- - >>> cookie = driver.get_cookie('my_cookie') + >>> cookie = driver.get_cookie("my_cookie") """ if not name or name.isspace(): raise ValueError("Cookie name cannot be empty") @@ -758,7 +750,7 @@ def delete_cookie(self, name) -> None: Example: -------- - >>> driver.delete_cookie('my_cookie') + >>> driver.delete_cookie("my_cookie") """ # firefox deletes all cookies when "" is passed as name @@ -787,10 +779,10 @@ def add_cookie(self, cookie_dict) -> None: Examples: -------- - >>> driver.add_cookie({'name' : 'foo', 'value' : 'bar'}) - >>> driver.add_cookie({'name' : 'foo', 'value' : 'bar', 'path' : '/'}) - >>> driver.add_cookie({'name' : 'foo', 'value' : 'bar', 'path' : '/', 'secure' : True}) - >>> driver.add_cookie({'name' : 'foo', 'value' : 'bar', 'sameSite' : 'Strict'}) + >>> driver.add_cookie({"name": "foo", "value": "bar"}) + >>> driver.add_cookie({"name": "foo", "value": "bar", "path": "/"}) + >>> driver.add_cookie({"name": "foo", "value": "bar", "path": "/", "secure": True}) + >>> driver.add_cookie({"name": "foo", "value": "bar", "sameSite": "Strict"}) """ if "sameSite" in cookie_dict: assert cookie_dict["sameSite"] in ["Strict", "Lax", "None"] @@ -980,7 +972,7 @@ def get_screenshot_as_file(self, filename) -> bool: Example: -------- - >>> driver.get_screenshot_as_file('/Screenshots/foo.png') + >>> driver.get_screenshot_as_file("/Screenshots/foo.png") """ if not str(filename).lower().endswith(".png"): warnings.warn( @@ -1011,7 +1003,7 @@ def save_screenshot(self, filename) -> bool: Example: -------- - >>> driver.save_screenshot('/Screenshots/foo.png') + >>> driver.save_screenshot("/Screenshots/foo.png") """ return self.get_screenshot_as_file(filename) @@ -1047,7 +1039,7 @@ def set_window_size(self, width, height, windowHandle: str = "current") -> None: Example: -------- - >>> driver.set_window_size(800,600) + >>> driver.set_window_size(800, 600) """ self._check_if_window_handle_is_current(windowHandle) self.set_window_rect(width=int(width), height=int(height)) @@ -1081,7 +1073,7 @@ def set_window_position(self, x: float, y: float, windowHandle: str = "current") Example: -------- - >>> driver.set_window_position(0,0) + >>> driver.set_window_position(0, 0) """ self._check_if_window_handle_is_current(windowHandle) return self.set_window_rect(x=int(x), y=int(y)) @@ -1177,7 +1169,7 @@ def orientation(self, value) -> None: Example: -------- - >>> driver.orientation = 'landscape' + >>> driver.orientation = "landscape" """ allowed_values = ["LANDSCAPE", "PORTRAIT"] if value.upper() in allowed_values: @@ -1332,7 +1324,9 @@ def storage(self): --------- >>> cookie_filter = CookieFilter(name="example") >>> result = driver.storage.get_cookies(filter=cookie_filter) - >>> driver.storage.set_cookie(cookie=PartialCookie("name", BytesValue(BytesValue.TYPE_STRING, "value"), "domain")) + >>> driver.storage.set_cookie(cookie=PartialCookie( + "name", BytesValue(BytesValue.TYPE_STRING, "value"), "domain") + ) >>> driver.storage.delete_cookies(filter=CookieFilter(name="example")) """ if not self._websocket_connection: diff --git a/py/selenium/webdriver/remote/webelement.py b/py/selenium/webdriver/remote/webelement.py index b8d8a32c3f285..b6d085cb6932c 100644 --- a/py/selenium/webdriver/remote/webelement.py +++ b/py/selenium/webdriver/remote/webelement.py @@ -21,14 +21,12 @@ import warnings import zipfile from abc import ABCMeta -from base64 import b64decode -from base64 import encodebytes +from base64 import b64decode, encodebytes from hashlib import md5 as md5_hash from io import BytesIO from typing import List -from selenium.common.exceptions import JavascriptException -from selenium.common.exceptions import WebDriverException +from selenium.common.exceptions import JavascriptException, WebDriverException from selenium.webdriver.common.by import By from selenium.webdriver.common.utils import keys_to_typing @@ -93,7 +91,7 @@ def tag_name(self) -> str: Example: -------- - >>> element = driver.find_element(By.ID, 'foo') + >>> element = driver.find_element(By.ID, "foo") """ return self._execute(Command.GET_ELEMENT_TAG_NAME)["value"] @@ -107,7 +105,7 @@ def text(self) -> str: Example: -------- - >>> element = driver.find_element(By.ID, 'foo') + >>> element = driver.find_element(By.ID, "foo") >>> print(element.text) """ return self._execute(Command.GET_ELEMENT_TEXT)["value"] @@ -117,7 +115,7 @@ def click(self) -> None: Example: -------- - >>> element = driver.find_element(By.ID, 'foo') + >>> element = driver.find_element(By.ID, "foo") >>> element.click() """ self._execute(Command.CLICK_ELEMENT) @@ -127,7 +125,7 @@ def submit(self) -> None: Example: -------- - >>> form = driver.find_element(By.NAME, 'login') + >>> form = driver.find_element(By.NAME, "login") >>> form.submit() """ script = ( @@ -152,7 +150,7 @@ def clear(self) -> None: Example: -------- - >>> text_field = driver.find_element(By.NAME, 'username') + >>> text_field = driver.find_element(By.NAME, "username") >>> text_field.clear() """ self._execute(Command.CLEAR_ELEMENT) @@ -277,11 +275,11 @@ def send_keys(self, *value: str) -> None: Examples: -------- To send a simple key event:: - >>> form_textfield = driver.find_element(By.NAME, 'username') + >>> form_textfield = driver.find_element(By.NAME, "username") >>> form_textfield.send_keys("admin") or to set a file input field:: - >>> file_input = driver.find_element(By.NAME, 'profilePic') + >>> file_input = driver.find_element(By.NAME, "profilePic") >>> file_input.send_keys("path/to/profilepic.gif") >>> # Generally it's better to wrap the file path in one of the methods >>> # in os.path to return the actual path to support cross OS testing. @@ -397,7 +395,7 @@ def value_of_css_property(self, property_name) -> str: Example: -------- - >>> value = element.value_of_css_property('color') + >>> value = element.value_of_css_property("color") """ return self._execute(Command.GET_ELEMENT_VALUE_OF_CSS_PROPERTY, {"propertyName": property_name})["value"] @@ -505,7 +503,7 @@ def screenshot(self, filename) -> bool: Element: -------- - >>> element.screenshot('/Screenshots/foo.png') + >>> element.screenshot("/Screenshots/foo.png") """ if not filename.lower().endswith(".png"): warnings.warn( @@ -529,7 +527,7 @@ def parent(self): Example: -------- - >>> element = driver.find_element(By.ID, 'foo') + >>> element = driver.find_element(By.ID, "foo") >>> parent_element = element.parent """ return self._parent @@ -623,7 +621,7 @@ def find_elements(self, by=By.ID, value=None) -> List[WebElement]: Example: -------- - >>> element = driver.find_elements(By.ID, 'foo') + >>> element = driver.find_elements(By.ID, "foo") Returns: ------- diff --git a/py/selenium/webdriver/safari/service.py b/py/selenium/webdriver/safari/service.py index c6132aaddafad..d1ff0f86b4211 100644 --- a/py/selenium/webdriver/safari/service.py +++ b/py/selenium/webdriver/safari/service.py @@ -16,9 +16,7 @@ # under the License. -from typing import List -from typing import Mapping -from typing import Optional +from typing import List, Mapping, Optional from selenium.webdriver.common import service @@ -31,7 +29,8 @@ class Service(service.Service): :param port: Port for the service to run on, defaults to 0 where the operating system will decide. :param service_args: (Optional) List of args to be passed to the subprocess when launching the executable. :param env: (Optional) Mapping of environment variables for the new process, defaults to `os.environ`. - :param enable_logging: (Optional) Enable logging of the service. Logs can be located at `~/Library/Logs/com.apple.WebDriver/` + :param enable_logging: (Optional) Enable logging of the service. Logs can be located at + `~/Library/Logs/com.apple.WebDriver/` :param driver_path_env_key: (Optional) Environment variable to use to get the path to the driver executable. """ diff --git a/py/selenium/webdriver/support/color.py b/py/selenium/webdriver/support/color.py index f6c31578c4b5b..ae28371667e6a 100644 --- a/py/selenium/webdriver/support/color.py +++ b/py/selenium/webdriver/support/color.py @@ -17,9 +17,7 @@ from __future__ import annotations import sys -from typing import TYPE_CHECKING -from typing import Any -from typing import Sequence +from typing import TYPE_CHECKING, Any, Sequence if sys.version_info >= (3, 9): from re import Match @@ -27,10 +25,7 @@ from typing import Match if TYPE_CHECKING: - from typing import SupportsFloat - from typing import SupportsIndex - from typing import SupportsInt - from typing import Union + from typing import SupportsFloat, SupportsIndex, SupportsInt, Union ParseableFloat = Union[SupportsFloat, SupportsIndex, str, bytes, bytearray] ParseableInt = Union[SupportsInt, SupportsIndex, str, bytes] @@ -43,7 +38,10 @@ r"^\s*rgb\(\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(\d{1,3}|\d{1,2}\.\d+)%\s*\)\s*$" ) RGBA_PATTERN = r"^\s*rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0|1|0\.\d+)\s*\)\s*$" -RGBA_PCT_PATTERN = r"^\s*rgba\(\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(0|1|0\.\d+)\s*\)\s*$" +RGBA_PCT_PATTERN = ( + r"^\s*rgba\(\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(\d{1,3}|\d{1,2}\.\d+)%\s*," + + r"\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(0|1|0\.\d+)\s*\)\s*$" +) HEX_PATTERN = r"#([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})" HEX3_PATTERN = r"#([A-Fa-f0-9])([A-Fa-f0-9])([A-Fa-f0-9])" HSL_PATTERN = r"^\s*hsl\(\s*(\d{1,3})\s*,\s*(\d{1,3})%\s*,\s*(\d{1,3})%\s*\)\s*$" @@ -59,9 +57,9 @@ class Color: from selenium.webdriver.support.color import Color - print(Color.from_string('#00ff33').rgba) - print(Color.from_string('rgb(1, 255, 3)').hex) - print(Color.from_string('blue').rgba) + print(Color.from_string("#00ff33").rgba) + print(Color.from_string("rgb(1, 255, 3)").hex) + print(Color.from_string("blue").rgba) """ @classmethod diff --git a/py/selenium/webdriver/support/event_firing_webdriver.py b/py/selenium/webdriver/support/event_firing_webdriver.py index 1118bb7c19727..e79be65576640 100644 --- a/py/selenium/webdriver/support/event_firing_webdriver.py +++ b/py/selenium/webdriver/support/event_firing_webdriver.py @@ -15,9 +15,7 @@ # specific language governing permissions and limitations # under the License. -from typing import Any -from typing import List -from typing import Tuple +from typing import Any, List, Tuple from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By @@ -47,7 +45,8 @@ def __init__(self, driver: WebDriver, event_listener: AbstractEventListener) -> :Args: - driver : A WebDriver instance - - event_listener : Instance of a class that subclasses AbstractEventListener and implements it fully or partially + - event_listener : Instance of a class that subclasses AbstractEventListener and implements it fully + or partially Example: @@ -56,12 +55,15 @@ def __init__(self, driver: WebDriver, event_listener: AbstractEventListener) -> from selenium.webdriver import Firefox from selenium.webdriver.support.events import EventFiringWebDriver, AbstractEventListener + class MyListener(AbstractEventListener): def before_navigate_to(self, url, driver): print("Before navigate to %s" % url) + def after_navigate_to(self, url, driver): print("After navigate to %s" % url) + driver = Firefox() ef_driver = EventFiringWebDriver(driver, MyListener()) ef_driver.get("http://www.google.co.in/") diff --git a/py/selenium/webdriver/support/expected_conditions.py b/py/selenium/webdriver/support/expected_conditions.py index 99fcf7ad571eb..fb39aa9d72d31 100644 --- a/py/selenium/webdriver/support/expected_conditions.py +++ b/py/selenium/webdriver/support/expected_conditions.py @@ -17,22 +17,17 @@ import re from collections.abc import Iterable -from typing import Any -from typing import Callable -from typing import List -from typing import Literal -from typing import Tuple -from typing import TypeVar -from typing import Union - -from selenium.common.exceptions import NoAlertPresentException -from selenium.common.exceptions import NoSuchElementException -from selenium.common.exceptions import NoSuchFrameException -from selenium.common.exceptions import StaleElementReferenceException -from selenium.common.exceptions import WebDriverException +from typing import Any, Callable, List, Literal, Tuple, TypeVar, Union + +from selenium.common.exceptions import ( + NoAlertPresentException, + NoSuchElementException, + NoSuchFrameException, + StaleElementReferenceException, + WebDriverException, +) from selenium.webdriver.common.alert import Alert -from selenium.webdriver.remote.webdriver import WebDriver -from selenium.webdriver.remote.webdriver import WebElement +from selenium.webdriver.remote.webdriver import WebDriver, WebElement """ * Canned "Expected Conditions" which are generally useful within webdriver @@ -102,8 +97,7 @@ def presence_of_element_located(locator: Tuple[str, str]) -> Callable[[WebDriver >>> from selenium.webdriver.common.by import By >>> from selenium.webdriver.support.ui import WebDriverWait >>> from selenium.webdriver.support import expected_conditions as EC - >>> element = WebDriverWait(driver, 10).until( - ... EC.presence_of_element_located((By.NAME, "q"))) + >>> element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.NAME, "q"))) """ def _predicate(driver: WebDriverOrWebElement): @@ -215,8 +209,7 @@ def visibility_of_element_located( >>> from selenium.webdriver.common.by import By >>> from selenium.webdriver.support.ui import WebDriverWait >>> from selenium.webdriver.support import expected_conditions as EC - >>> element = WebDriverWait(driver, 10).until( - ... EC.visibility_of_element_located((By.NAME, "q"))) + >>> element = WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.NAME, "q"))) """ def _predicate(driver: WebDriverOrWebElement): @@ -246,8 +239,7 @@ def visibility_of(element: WebElement) -> Callable[[Any], Union[Literal[False], >>> from selenium.webdriver.common.by import By >>> from selenium.webdriver.support.ui import WebDriverWait >>> from selenium.webdriver.support import expected_conditions as EC - >>> element = WebDriverWait(driver, 10).until( - ... EC.visibility_of(driver.find_element(By.NAME, "q"))) + >>> element = WebDriverWait(driver, 10).until(EC.visibility_of(driver.find_element(By.NAME, "q"))) Notes: ------ @@ -298,8 +290,7 @@ def presence_of_all_elements_located(locator: Tuple[str, str]) -> Callable[[WebD >>> from selenium.webdriver.common.by import By >>> from selenium.webdriver.support.ui import WebDriverWait >>> from selenium.webdriver.support import expected_conditions as EC - >>> elements = WebDriverWait(driver, 10).until( - ... EC.presence_of_all_elements_located((By.CLASS_NAME, "foo"))) + >>> elements = WebDriverWait(driver, 10).until(EC.presence_of_all_elements_located((By.CLASS_NAME, "foo"))) """ def _predicate(driver: WebDriverOrWebElement): @@ -326,8 +317,7 @@ def visibility_of_any_elements_located(locator: Tuple[str, str]) -> Callable[[We >>> from selenium.webdriver.common.by import By >>> from selenium.webdriver.support.ui import WebDriverWait >>> from selenium.webdriver.support import expected_conditions as EC - >>> elements = WebDriverWait(driver, 10).until( - ... EC.visibility_of_any_elements_located((By.CLASS_NAME, "foo"))) + >>> elements = WebDriverWait(driver, 10).until(EC.visibility_of_any_elements_located((By.CLASS_NAME, "foo"))) """ def _predicate(driver: WebDriverOrWebElement): @@ -357,8 +347,7 @@ def visibility_of_all_elements_located( >>> from selenium.webdriver.common.by import By >>> from selenium.webdriver.support.ui import WebDriverWait >>> from selenium.webdriver.support import expected_conditions as EC - >>> elements = WebDriverWait(driver, 10).until( - ... EC.visibility_of_all_elements_located((By.CLASS_NAME, "foo"))) + >>> elements = WebDriverWait(driver, 10).until(EC.visibility_of_all_elements_located((By.CLASS_NAME, "foo"))) """ def _predicate(driver: WebDriverOrWebElement): @@ -395,7 +384,8 @@ def text_to_be_present_in_element(locator: Tuple[str, str], text_: str) -> Calla >>> from selenium.webdriver.support.ui import WebDriverWait >>> from selenium.webdriver.support import expected_conditions as EC >>> is_text_in_element = WebDriverWait(driver, 10).until( - ... EC.text_to_be_present_in_element((By.CLASS_NAME, "foo"), "bar")) + EC.text_to_be_present_in_element((By.CLASS_NAME, "foo"), "bar") + ) """ def _predicate(driver: WebDriverOrWebElement): @@ -431,7 +421,8 @@ def text_to_be_present_in_element_value( >>> from selenium.webdriver.support.ui import WebDriverWait >>> from selenium.webdriver.support import expected_conditions as EC >>> is_text_in_element_value = WebDriverWait(driver, 10).until( - ... EC.text_to_be_present_in_element_value((By.CLASS_NAME, "foo"), "bar")) + ... EC.text_to_be_present_in_element_value((By.CLASS_NAME, "foo"), "bar") + ... ) """ def _predicate(driver: WebDriverOrWebElement): @@ -469,8 +460,8 @@ def text_to_be_present_in_element_attribute( >>> from selenium.webdriver.support.ui import WebDriverWait >>> from selenium.webdriver.support import expected_conditions as EC >>> is_text_in_element_attribute = WebDriverWait(driver, 10).until( - ... EC.text_to_be_present_in_element_attribute((By.CLASS_NAME, "foo"), - ... "bar", "baz")) + ... EC.text_to_be_present_in_element_attribute((By.CLASS_NAME, "foo"), "bar", "baz") + ... ) """ def _predicate(driver: WebDriverOrWebElement): @@ -504,8 +495,7 @@ def frame_to_be_available_and_switch_to_it( -------- >>> from selenium.webdriver.support.ui import WebDriverWait >>> from selenium.webdriver.support import expected_conditions as EC - >>> WebDriverWait(driver, 10).until( - ... EC.frame_to_be_available_and_switch_to_it("frame_name")) + >>> WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it("frame_name")) Notes: ------ @@ -546,8 +536,7 @@ def invisibility_of_element_located( >>> from selenium.webdriver.common.by import By >>> from selenium.webdriver.support.ui import WebDriverWait >>> from selenium.webdriver.support import expected_conditions as EC - >>> is_invisible = WebDriverWait(driver, 10).until( - ... EC.invisibility_of_element_located((By.CLASS_NAME, "foo"))) + >>> is_invisible = WebDriverWait(driver, 10).until(EC.invisibility_of_element_located((By.CLASS_NAME, "foo"))) Notes: ------ @@ -596,7 +585,8 @@ def invisibility_of_element( >>> from selenium.webdriver.support.ui import WebDriverWait >>> from selenium.webdriver.support import expected_conditions as EC >>> is_invisible_or_not_present = WebDriverWait(driver, 10).until( - ... EC.invisibility_of_element(driver.find_element(By.CLASS_NAME, "foo"))) + ... EC.invisibility_of_element(driver.find_element(By.CLASS_NAME, "foo")) + ... ) """ return invisibility_of_element_located(element) @@ -621,8 +611,7 @@ def element_to_be_clickable( >>> from selenium.webdriver.common.by import By >>> from selenium.webdriver.support.ui import WebDriverWait >>> from selenium.webdriver.support import expected_conditions as EC - >>> element = WebDriverWait(driver, 10).until( - ... EC.element_to_be_clickable((By.CLASS_NAME, "foo"))) + >>> element = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CLASS_NAME, "foo"))) """ # renamed argument to 'mark', to indicate that both locator @@ -656,8 +645,7 @@ def staleness_of(element: WebElement) -> Callable[[Any], bool]: >>> from selenium.webdriver.common.by import By >>> from selenium.webdriver.support.ui import WebDriverWait >>> from selenium.webdriver.support import expected_conditions as EC - >>> is_element_stale = WebDriverWait(driver, 10).until( - ... EC.staleness_of(driver.find_element(By.CLASS_NAME, "foo"))) + >>> is_element_stale = WebDriverWait(driver, 10).until(EC.staleness_of(driver.find_element(By.CLASS_NAME, "foo"))) """ def _predicate(_): @@ -688,8 +676,9 @@ def element_to_be_selected(element: WebElement) -> Callable[[Any], bool]: >>> from selenium.webdriver.common.by import By >>> from selenium.webdriver.support.ui import WebDriverWait >>> from selenium.webdriver.support import expected_conditions as EC - >>> is_selected = WebDriverWait(driver, 10).until( - ... EC.element_to_be_selected(driver.find_element(By.CLASS_NAME, "foo"))) + >>> is_selected = WebDriverWait(driver, 10).until(EC.element_to_be_selected(driver.find_element( + By.CLASS_NAME, "foo")) + ) """ def _predicate(_): @@ -715,8 +704,7 @@ def element_located_to_be_selected(locator: Tuple[str, str]) -> Callable[[WebDri >>> from selenium.webdriver.common.by import By >>> from selenium.webdriver.support.ui import WebDriverWait >>> from selenium.webdriver.support import expected_conditions as EC - >>> is_selected = WebDriverWait(driver, 10).until( - ... EC.element_located_to_be_selected((By.CLASS_NAME, "foo"))) + >>> is_selected = WebDriverWait(driver, 10).until(EC.element_located_to_be_selected((By.CLASS_NAME, "foo"))) """ def _predicate(driver: WebDriverOrWebElement): @@ -744,7 +732,8 @@ def element_selection_state_to_be(element: WebElement, is_selected: bool) -> Cal >>> from selenium.webdriver.support.ui import WebDriverWait >>> from selenium.webdriver.support import expected_conditions as EC >>> is_selected = WebDriverWait(driver, 10).until( - ... EC.element_selection_state_to_be(driver.find_element(By.CLASS_NAME, "foo"), True)) + ... EC.element_selection_state_to_be(driver.find_element(By.CLASS_NAME, "foo"), True) + ... ) """ def _predicate(_): @@ -774,8 +763,9 @@ def element_located_selection_state_to_be( >>> from selenium.webdriver.common.by import By >>> from selenium.webdriver.support.ui import WebDriverWait >>> from selenium.webdriver.support import expected_conditions as EC - >>> is_selected = WebDriverWait(driver, 10).until( - ... EC.element_located_selection_state_to_be((By.CLASS_NAME, "foo"), True)) + >>> is_selected = WebDriverWait(driver, 10).until(EC.element_located_selection_state_to_be( + (By.CLASS_NAME, "foo"), True) + ) """ def _predicate(driver: WebDriverOrWebElement): @@ -804,8 +794,7 @@ def number_of_windows_to_be(num_windows: int) -> Callable[[WebDriver], bool]: -------- >>> from selenium.webdriver.support.ui import WebDriverWait >>> from selenium.webdriver.support import expected_conditions as EC - >>> is_number_of_windows = WebDriverWait(driver, 10).until( - ... EC.number_of_windows_to_be(2)) + >>> is_number_of_windows = WebDriverWait(driver, 10).until(EC.number_of_windows_to_be(2)) """ def _predicate(driver: WebDriver): @@ -832,8 +821,7 @@ def new_window_is_opened(current_handles: List[str]) -> Callable[[WebDriver], bo >>> from selenium.webdriver.support.ui import By >>> from selenium.webdriver.support.ui import WebDriverWait >>> from selenium.webdriver.support import expected_conditions as EC - >>> is_new_window_opened = WebDriverWait(driver, 10).until( - ... EC.new_window_is_opened(driver.window_handles)) + >>> is_new_window_opened = WebDriverWait(driver, 10).until(EC.new_window_is_opened(driver.window_handles)) """ def _predicate(driver: WebDriver): @@ -891,7 +879,8 @@ def element_attribute_to_include(locator: Tuple[str, str], attribute_: str) -> C >>> from selenium.webdriver.support.ui import WebDriverWait >>> from selenium.webdriver.support import expected_conditions as EC >>> is_attribute_in_element = WebDriverWait(driver, 10).until( - ... EC.element_attribute_to_include((By.CLASS_NAME, "foo"), "bar")) + ... EC.element_attribute_to_include((By.CLASS_NAME, "foo"), "bar") + ... ) """ def _predicate(driver: WebDriverOrWebElement): @@ -945,7 +934,7 @@ def any_of_condition(driver: D): def all_of( - *expected_conditions: Callable[[D], Union[T, Literal[False]]] + *expected_conditions: Callable[[D], Union[T, Literal[False]]], ) -> Callable[[D], Union[List[T], Literal[False]]]: """An expectation that all of multiple expected conditions is true. diff --git a/py/selenium/webdriver/support/relative_locator.py b/py/selenium/webdriver/support/relative_locator.py index 409a31ab0a291..53cd066c20b3f 100644 --- a/py/selenium/webdriver/support/relative_locator.py +++ b/py/selenium/webdriver/support/relative_locator.py @@ -15,16 +15,10 @@ # specific language governing permissions and limitations # under the License. import warnings -from typing import Dict -from typing import List -from typing import NoReturn -from typing import Optional -from typing import Union -from typing import overload +from typing import Dict, List, NoReturn, Optional, Union, overload from selenium.common.exceptions import WebDriverException -from selenium.webdriver.common.by import By -from selenium.webdriver.common.by import ByType +from selenium.webdriver.common.by import By, ByType from selenium.webdriver.remote.webelement import WebElement @@ -51,9 +45,7 @@ def with_tag_name(tag_name: str) -> "RelativeBy": - This method is deprecated and may be removed in future versions. - Please use `locate_with` instead. """ - warnings.warn( - "This method is deprecated and may be removed in future versions. " "Please use `locate_with` instead." - ) + warnings.warn("This method is deprecated and may be removed in future versions. Please use `locate_with` instead.") if not tag_name: raise WebDriverException("tag_name can not be null") return RelativeBy({By.CSS_SELECTOR: tag_name}) @@ -94,7 +86,7 @@ class RelativeBy: -------- >>> lowest = driver.find_element(By.ID, "below") >>> elements = driver.find_elements(locate_with(By.CSS_SELECTOR, "p").above(lowest)) - >>> ids = [el.get_attribute('id') for el in elements] + >>> ids = [el.get_attribute("id") for el in elements] >>> assert "above" in ids >>> assert "mid" in ids """ diff --git a/py/selenium/webdriver/support/select.py b/py/selenium/webdriver/support/select.py index 31f68825682d7..4874fcac151e7 100644 --- a/py/selenium/webdriver/support/select.py +++ b/py/selenium/webdriver/support/select.py @@ -17,8 +17,7 @@ from typing import List -from selenium.common.exceptions import NoSuchElementException -from selenium.common.exceptions import UnexpectedTagNameException +from selenium.common.exceptions import NoSuchElementException, UnexpectedTagNameException from selenium.webdriver.common.by import By from selenium.webdriver.remote.webelement import WebElement diff --git a/py/selenium/webdriver/support/wait.py b/py/selenium/webdriver/support/wait.py index 0f452ca752b97..19fcf60f05922 100644 --- a/py/selenium/webdriver/support/wait.py +++ b/py/selenium/webdriver/support/wait.py @@ -16,17 +16,9 @@ # under the License. import time -from typing import Callable -from typing import Generic -from typing import Literal -from typing import Optional -from typing import Tuple -from typing import Type -from typing import TypeVar -from typing import Union - -from selenium.common.exceptions import NoSuchElementException -from selenium.common.exceptions import TimeoutException +from typing import Callable, Generic, Literal, Optional, Tuple, Type, TypeVar, Union + +from selenium.common.exceptions import NoSuchElementException, TimeoutException from selenium.types import WaitExcTypes from selenium.webdriver.remote.webdriver import WebDriver from selenium.webdriver.remote.webelement import WebElement @@ -178,8 +170,7 @@ def until_not(self, method: Callable[[D], T], message: str = "") -> Union[T, Lit # Wait until an element is visible on the page >>> wait = WebDriverWait(driver, 10) - >>> is_disappeared = wait.until_not(EC.visibility_of_element_located( - ... (By.ID, "exampleId"))) + >>> is_disappeared = wait.until_not(EC.visibility_of_element_located((By.ID, "exampleId"))) """ end_time = time.monotonic() + self._timeout while True: diff --git a/py/selenium/webdriver/webkitgtk/service.py b/py/selenium/webdriver/webkitgtk/service.py index defb3b3ae0684..ed15cdf83ddda 100644 --- a/py/selenium/webdriver/webkitgtk/service.py +++ b/py/selenium/webdriver/webkitgtk/service.py @@ -16,9 +16,7 @@ # under the License. import shutil import warnings -from typing import List -from typing import Mapping -from typing import Optional +from typing import List, Mapping, Optional from selenium.webdriver.common import service @@ -29,10 +27,12 @@ class Service(service.Service): """A Service class that is responsible for the starting and stopping of `WebKitWebDriver`. - :param executable_path: install path of the WebKitWebDriver executable, defaults to the first `WebKitWebDriver` in `$PATH`. + :param executable_path: install path of the WebKitWebDriver executable, defaults to the first + `WebKitWebDriver` in `$PATH`. :param port: Port for the service to run on, defaults to 0 where the operating system will decide. :param service_args: (Optional) List of args to be passed to the subprocess when launching the executable. - :param log_output: (Optional) File path for the file to be opened and passed as the subprocess stdout/stderr handler. + :param log_output: (Optional) File path for the file to be opened and passed as the subprocess + stdout/stderr handler. :param env: (Optional) Mapping of environment variables for the new process, defaults to `os.environ`. """ diff --git a/py/selenium/webdriver/wpewebkit/service.py b/py/selenium/webdriver/wpewebkit/service.py index 8f392cf522706..552438818b4a9 100644 --- a/py/selenium/webdriver/wpewebkit/service.py +++ b/py/selenium/webdriver/wpewebkit/service.py @@ -15,9 +15,7 @@ # specific language governing permissions and limitations # under the License. import shutil -from typing import List -from typing import Mapping -from typing import Optional +from typing import List, Mapping, Optional from selenium.webdriver.common import service @@ -28,10 +26,12 @@ class Service(service.Service): """A Service class that is responsible for the starting and stopping of `WPEWebDriver`. - :param executable_path: install path of the WPEWebDriver executable, defaults to the first `WPEWebDriver` in `$PATH`. + :param executable_path: install path of the WPEWebDriver executable, defaults to the first + `WPEWebDriver` in `$PATH`. :param port: Port for the service to run on, defaults to 0 where the operating system will decide. :param service_args: (Optional) List of args to be passed to the subprocess when launching the executable. - :param log_output: (Optional) File path for the file to be opened and passed as the subprocess stdout/stderr handler. + :param log_output: (Optional) File path for the file to be opened and passed as the subprocess + stdout/stderr handler. :param env: (Optional) Mapping of environment variables for the new process, defaults to `os.environ`. """ diff --git a/py/test/selenium/webdriver/common/alerts_tests.py b/py/test/selenium/webdriver/common/alerts_tests.py index e47a9b788c80e..9143974cb9463 100644 --- a/py/test/selenium/webdriver/common/alerts_tests.py +++ b/py/test/selenium/webdriver/common/alerts_tests.py @@ -19,9 +19,11 @@ import pytest -from selenium.common.exceptions import InvalidElementStateException -from selenium.common.exceptions import NoAlertPresentException -from selenium.common.exceptions import UnexpectedAlertPresentException +from selenium.common.exceptions import ( + InvalidElementStateException, + NoAlertPresentException, + UnexpectedAlertPresentException, +) from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.wait import WebDriverWait diff --git a/py/test/selenium/webdriver/common/bidi_browser_tests.py b/py/test/selenium/webdriver/common/bidi_browser_tests.py index 1391e5f8c951d..2fec55c1e4f48 100644 --- a/py/test/selenium/webdriver/common/bidi_browser_tests.py +++ b/py/test/selenium/webdriver/common/bidi_browser_tests.py @@ -17,8 +17,7 @@ import pytest -from selenium.webdriver.common.bidi.browser import ClientWindowInfo -from selenium.webdriver.common.bidi.browser import ClientWindowState +from selenium.webdriver.common.bidi.browser import ClientWindowInfo, ClientWindowState def test_browser_initialized(driver): diff --git a/py/test/selenium/webdriver/common/bidi_network_tests.py b/py/test/selenium/webdriver/common/bidi_network_tests.py index a894a1a0db310..5fc168a36503a 100644 --- a/py/test/selenium/webdriver/common/bidi_network_tests.py +++ b/py/test/selenium/webdriver/common/bidi_network_tests.py @@ -37,7 +37,6 @@ def test_remove_intercept(driver): def test_add_and_remove_request_handler(driver, pages): - requests = [] def callback(request: Request): @@ -72,7 +71,6 @@ def callback(request: Request): @pytest.mark.xfail_chrome @pytest.mark.xfail_edge def test_continue_request(driver, pages): - def callback(request: Request): request.continue_request() @@ -85,7 +83,6 @@ def callback(request: Request): @pytest.mark.xfail_chrome @pytest.mark.xfail_edge def test_continue_with_auth(driver): - callback_id = driver.network.add_auth_handler("user", "passwd") assert callback_id is not None, "Request handler not added" driver.get("https://httpbin.org/basic-auth/user/passwd") diff --git a/py/test/selenium/webdriver/common/bidi_storage_tests.py b/py/test/selenium/webdriver/common/bidi_storage_tests.py index bc07b76d7ac85..abb67431e0a5f 100644 --- a/py/test/selenium/webdriver/common/bidi_storage_tests.py +++ b/py/test/selenium/webdriver/common/bidi_storage_tests.py @@ -20,12 +20,14 @@ import pytest -from selenium.webdriver.common.bidi.storage import BrowsingContextPartitionDescriptor -from selenium.webdriver.common.bidi.storage import BytesValue -from selenium.webdriver.common.bidi.storage import CookieFilter -from selenium.webdriver.common.bidi.storage import PartialCookie -from selenium.webdriver.common.bidi.storage import SameSite -from selenium.webdriver.common.bidi.storage import StorageKeyPartitionDescriptor +from selenium.webdriver.common.bidi.storage import ( + BrowsingContextPartitionDescriptor, + BytesValue, + CookieFilter, + PartialCookie, + SameSite, + StorageKeyPartitionDescriptor, +) from selenium.webdriver.common.window import WindowTypes @@ -76,7 +78,6 @@ def get_document_cookie_or_none(driver): class TestBidiStorage: - @pytest.fixture(autouse=True) def setup(self, driver, pages): driver.get(pages.url("simpleTest.html")) diff --git a/py/test/selenium/webdriver/common/children_finding_tests.py b/py/test/selenium/webdriver/common/children_finding_tests.py index ec1a65b44a65d..ab4c5cd47927c 100644 --- a/py/test/selenium/webdriver/common/children_finding_tests.py +++ b/py/test/selenium/webdriver/common/children_finding_tests.py @@ -17,8 +17,7 @@ import pytest -from selenium.common.exceptions import NoSuchElementException -from selenium.common.exceptions import WebDriverException +from selenium.common.exceptions import NoSuchElementException, WebDriverException from selenium.webdriver.common.by import By diff --git a/py/test/selenium/webdriver/common/driver_element_finding_tests.py b/py/test/selenium/webdriver/common/driver_element_finding_tests.py index 205edb92e1f88..6d1d78bea2ca2 100644 --- a/py/test/selenium/webdriver/common/driver_element_finding_tests.py +++ b/py/test/selenium/webdriver/common/driver_element_finding_tests.py @@ -17,8 +17,7 @@ import pytest -from selenium.common.exceptions import InvalidSelectorException -from selenium.common.exceptions import NoSuchElementException +from selenium.common.exceptions import InvalidSelectorException, NoSuchElementException from selenium.webdriver.common.by import By # By.id positive diff --git a/py/test/selenium/webdriver/common/executing_async_javascript_tests.py b/py/test/selenium/webdriver/common/executing_async_javascript_tests.py index 9ca2477e70b1f..2fed0af2b67c1 100644 --- a/py/test/selenium/webdriver/common/executing_async_javascript_tests.py +++ b/py/test/selenium/webdriver/common/executing_async_javascript_tests.py @@ -17,8 +17,7 @@ import pytest -from selenium.common.exceptions import TimeoutException -from selenium.common.exceptions import WebDriverException +from selenium.common.exceptions import TimeoutException, WebDriverException from selenium.webdriver.common.by import By from selenium.webdriver.remote.webelement import WebElement @@ -162,9 +161,9 @@ def test_should_be_able_to_execute_asynchronous_scripts(driver, pages): driver.find_element(by=By.ID, value="red").click() driver.find_element(by=By.NAME, value="submit").click() - assert 1 == len( - driver.find_elements(by=By.TAG_NAME, value="div") - ), "There should only be 1 DIV at this point, which is used for the butter message" + assert 1 == len(driver.find_elements(by=By.TAG_NAME, value="div")), ( + "There should only be 1 DIV at this point, which is used for the butter message" + ) driver.set_script_timeout(10) text = driver.execute_async_script( """var callback = arguments[arguments.length - 1]; @@ -173,9 +172,9 @@ def test_should_be_able_to_execute_asynchronous_scripts(driver, pages): assert "bob" == text assert "" == typer.get_attribute("value") - assert 2 == len( - driver.find_elements(by=By.TAG_NAME, value="div") - ), "There should be 1 DIV (for the butter message) + 1 DIV (for the new label)" + assert 2 == len(driver.find_elements(by=By.TAG_NAME, value="div")), ( + "There should be 1 DIV (for the butter message) + 1 DIV (for the new label)" + ) def test_should_be_able_to_pass_multiple_arguments_to_async_scripts(driver, pages): diff --git a/py/test/selenium/webdriver/common/executing_javascript_tests.py b/py/test/selenium/webdriver/common/executing_javascript_tests.py index d94b759e54121..7c718616ae6b4 100644 --- a/py/test/selenium/webdriver/common/executing_javascript_tests.py +++ b/py/test/selenium/webdriver/common/executing_javascript_tests.py @@ -99,7 +99,7 @@ def test_should_be_able_to_execute_simple_javascript_and_return_web_elements_ins def test_should_be_able_to_execute_simple_javascript_and_return_web_elements_inside_anested_dict(driver, pages): pages.load("xhtmlTest.html") - result = driver.execute_script("return {el1: document.body, " "nested: {el2: document.getElementById('id1')}}") + result = driver.execute_script("return {el1: document.body, nested: {el2: document.getElementById('id1')}}") assert result is not None assert isinstance(result, dict) diff --git a/py/test/selenium/webdriver/common/frame_switching_tests.py b/py/test/selenium/webdriver/common/frame_switching_tests.py index 47cc58b2d7dd5..08d3aca088d27 100644 --- a/py/test/selenium/webdriver/common/frame_switching_tests.py +++ b/py/test/selenium/webdriver/common/frame_switching_tests.py @@ -17,9 +17,7 @@ import pytest -from selenium.common.exceptions import NoSuchElementException -from selenium.common.exceptions import NoSuchFrameException -from selenium.common.exceptions import WebDriverException +from selenium.common.exceptions import NoSuchElementException, NoSuchFrameException, WebDriverException from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait diff --git a/py/test/selenium/webdriver/common/interactions_tests.py b/py/test/selenium/webdriver/common/interactions_tests.py index 7ffe0e9dc4e0b..a560b36669ef8 100644 --- a/py/test/selenium/webdriver/common/interactions_tests.py +++ b/py/test/selenium/webdriver/common/interactions_tests.py @@ -16,6 +16,7 @@ # under the License. """Tests for advanced user interactions.""" + import pytest from selenium.common.exceptions import MoveTargetOutOfBoundsException diff --git a/py/test/selenium/webdriver/common/interactions_with_device_tests.py b/py/test/selenium/webdriver/common/interactions_with_device_tests.py index f82f3967a0776..194e7fda76270 100644 --- a/py/test/selenium/webdriver/common/interactions_with_device_tests.py +++ b/py/test/selenium/webdriver/common/interactions_with_device_tests.py @@ -16,6 +16,7 @@ # under the License. """Tests for advanced user interactions.""" + import pytest from selenium.common.exceptions import MoveTargetOutOfBoundsException @@ -23,8 +24,7 @@ from selenium.webdriver.common.actions import interaction from selenium.webdriver.common.actions.key_input import KeyInput from selenium.webdriver.common.actions.pointer_input import PointerInput -from selenium.webdriver.common.actions.wheel_input import ScrollOrigin -from selenium.webdriver.common.actions.wheel_input import WheelInput +from selenium.webdriver.common.actions.wheel_input import ScrollOrigin, WheelInput from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.support.ui import WebDriverWait diff --git a/py/test/selenium/webdriver/common/proxy_tests.py b/py/test/selenium/webdriver/common/proxy_tests.py index 3ec0946c874a1..6654b5b6c1cbd 100644 --- a/py/test/selenium/webdriver/common/proxy_tests.py +++ b/py/test/selenium/webdriver/common/proxy_tests.py @@ -18,8 +18,7 @@ import pytest from selenium.webdriver.common.options import ArgOptions -from selenium.webdriver.common.proxy import Proxy -from selenium.webdriver.common.proxy import ProxyType +from selenium.webdriver.common.proxy import Proxy, ProxyType MANUAL_PROXY = { "httpProxy": "some.url:1234", diff --git a/py/test/selenium/webdriver/common/select_class_tests.py b/py/test/selenium/webdriver/common/select_class_tests.py index 4374b68e90292..d72d54680927e 100644 --- a/py/test/selenium/webdriver/common/select_class_tests.py +++ b/py/test/selenium/webdriver/common/select_class_tests.py @@ -17,8 +17,7 @@ import pytest -from selenium.common.exceptions import NoSuchElementException -from selenium.common.exceptions import UnexpectedTagNameException +from selenium.common.exceptions import NoSuchElementException, UnexpectedTagNameException from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import Select diff --git a/py/test/selenium/webdriver/common/virtual_authenticator_tests.py b/py/test/selenium/webdriver/common/virtual_authenticator_tests.py index cdbbb4506ea44..79a7d21322a4d 100644 --- a/py/test/selenium/webdriver/common/virtual_authenticator_tests.py +++ b/py/test/selenium/webdriver/common/virtual_authenticator_tests.py @@ -15,15 +15,13 @@ # specific language governing permissions and limitations # under the License. -from base64 import b64decode -from base64 import urlsafe_b64decode +from base64 import b64decode, urlsafe_b64decode from typing import List import pytest from selenium.common.exceptions import InvalidArgumentException -from selenium.webdriver.common.virtual_authenticator import Credential -from selenium.webdriver.common.virtual_authenticator import VirtualAuthenticatorOptions +from selenium.webdriver.common.virtual_authenticator import Credential, VirtualAuthenticatorOptions from selenium.webdriver.remote.webdriver import WebDriver # working Key @@ -337,7 +335,8 @@ def test_set_user_verified(driver, pages): # Register a credential requiring UV. response = driver.execute_async_script( - "registerCredential({authenticatorSelection: {userVerification: 'required'}}).then(arguments[arguments.length - 1]);" + "registerCredential({authenticatorSelection: {userVerification: 'required'}})" + + ".then(arguments[arguments.length - 1]);" ) assert response.get("status", "") == "OK" raw_id = response["credential"]["rawId"] diff --git a/py/test/selenium/webdriver/common/visibility_tests.py b/py/test/selenium/webdriver/common/visibility_tests.py index 7a5eef8b36569..7cd402656c7f7 100644 --- a/py/test/selenium/webdriver/common/visibility_tests.py +++ b/py/test/selenium/webdriver/common/visibility_tests.py @@ -17,8 +17,7 @@ import pytest -from selenium.common.exceptions import ElementNotInteractableException -from selenium.common.exceptions import ElementNotVisibleException +from selenium.common.exceptions import ElementNotInteractableException, ElementNotVisibleException from selenium.webdriver.common.by import By diff --git a/py/test/selenium/webdriver/common/w3c_interaction_tests.py b/py/test/selenium/webdriver/common/w3c_interaction_tests.py index a28f99bb28495..32715fab22da9 100644 --- a/py/test/selenium/webdriver/common/w3c_interaction_tests.py +++ b/py/test/selenium/webdriver/common/w3c_interaction_tests.py @@ -245,9 +245,7 @@ def test_touch_pointer_properties(driver, pages): width=23, height=31, pressure=0.78, tilt_x=21, tilt_y=-8, twist=355 ).move_to( pointerArea, x=10, y=10, width=39, height=35, pressure=0.91, tilt_x=-19, tilt_y=62, twist=345 - ).pointer_up().move_to( - pointerArea, x=15, y=15 - ) + ).pointer_up().move_to(pointerArea, x=15, y=15) touch_chain.perform() events = _get_events(driver) assert len(events) == 7 diff --git a/py/test/selenium/webdriver/common/webdriverwait_tests.py b/py/test/selenium/webdriver/common/webdriverwait_tests.py index 51e96ffca3907..bb254871a0382 100644 --- a/py/test/selenium/webdriver/common/webdriverwait_tests.py +++ b/py/test/selenium/webdriver/common/webdriverwait_tests.py @@ -20,11 +20,13 @@ import pytest from urllib3.exceptions import ReadTimeoutError -from selenium.common.exceptions import InvalidElementStateException -from selenium.common.exceptions import InvalidSelectorException -from selenium.common.exceptions import StaleElementReferenceException -from selenium.common.exceptions import TimeoutException -from selenium.common.exceptions import WebDriverException +from selenium.common.exceptions import ( + InvalidElementStateException, + InvalidSelectorException, + StaleElementReferenceException, + TimeoutException, + WebDriverException, +) from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait @@ -205,7 +207,8 @@ def test_expected_condition_text_to_be_present_in_element(driver, pages): with pytest.raises(TimeoutException): WebDriverWait(driver, 0.01).until(EC.text_to_be_present_in_element((By.ID, "unwrappable"), "Expected")) driver.execute_script( - "setTimeout(function(){var el = document.getElementById('unwrappable'); el.textContent = el.innerText = 'Unwrappable Expected text'}, 200)" + "setTimeout(function(){var el = document.getElementById('unwrappable'); el.textContent = el.innerText = " + + "'Unwrappable Expected text'}, 200)" ) WebDriverWait(driver, 5).until(EC.text_to_be_present_in_element((By.ID, "unwrappable"), "Expected")) assert "Unwrappable Expected text" == driver.find_element(By.ID, "unwrappable").text diff --git a/py/test/selenium/webdriver/common/webserver.py b/py/test/selenium/webdriver/common/webserver.py index bd108dade8278..e3d0bb2577d30 100644 --- a/py/test/selenium/webdriver/common/webserver.py +++ b/py/test/selenium/webdriver/common/webserver.py @@ -17,6 +17,7 @@ """A simple web server for testing purpose. It serves the testing html pages that are needed by the webdriver unit tests.""" + import contextlib import logging import os @@ -28,12 +29,10 @@ except ImportError: import urllib as urllib_request try: - from http.server import BaseHTTPRequestHandler - from http.server import HTTPServer + from http.server import BaseHTTPRequestHandler, HTTPServer from socketserver import ThreadingMixIn except ImportError: - from BaseHTTPServer import BaseHTTPRequestHandler - from BaseHTTPServer import HTTPServer + from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer from SocketServer import ThreadingMixIn diff --git a/py/test/selenium/webdriver/common/window_switching_tests.py b/py/test/selenium/webdriver/common/window_switching_tests.py index 2883ab2c55f69..1cb9499f08f02 100644 --- a/py/test/selenium/webdriver/common/window_switching_tests.py +++ b/py/test/selenium/webdriver/common/window_switching_tests.py @@ -17,8 +17,7 @@ import pytest -from selenium.common.exceptions import NoSuchWindowException -from selenium.common.exceptions import WebDriverException +from selenium.common.exceptions import NoSuchWindowException, WebDriverException from selenium.webdriver.common.by import By from selenium.webdriver.common.window import WindowTypes from selenium.webdriver.support import expected_conditions as EC diff --git a/py/test/selenium/webdriver/common/window_tests.py b/py/test/selenium/webdriver/common/window_tests.py index 129a95f091ea9..07f71c56cfd62 100644 --- a/py/test/selenium/webdriver/common/window_tests.py +++ b/py/test/selenium/webdriver/common/window_tests.py @@ -30,7 +30,8 @@ # old_size = driver.get_window_size() # driver.set_window_size(200, 200) # wait.until( -# lambda dr: dr.get_window_size() != old_size if old_size["width"] != 200 and old_size["height"] != 200 else True) +# lambda dr: dr.get_window_size() != old_size if old_size["width"] != 200 \ +# and old_size["height"] != 200 else True) # size = driver.get_window_size() # driver.maximize_window() # wait.until(lambda dr: dr.get_window_size() != size) diff --git a/py/test/selenium/webdriver/marionette/mn_options_tests.py b/py/test/selenium/webdriver/marionette/mn_options_tests.py index e9cfcafca5f0b..95e7346c1b2db 100644 --- a/py/test/selenium/webdriver/marionette/mn_options_tests.py +++ b/py/test/selenium/webdriver/marionette/mn_options_tests.py @@ -22,8 +22,7 @@ from selenium.webdriver.common.options import PageLoadStrategy from selenium.webdriver.firefox.firefox_binary import FirefoxBinary from selenium.webdriver.firefox.firefox_profile import FirefoxProfile -from selenium.webdriver.firefox.options import Log -from selenium.webdriver.firefox.options import Options +from selenium.webdriver.firefox.options import Log, Options @pytest.fixture diff --git a/py/test/selenium/webdriver/safari/launcher_tests.py b/py/test/selenium/webdriver/safari/launcher_tests.py index 77a57c313aa2e..504af6a0e6a59 100644 --- a/py/test/selenium/webdriver/safari/launcher_tests.py +++ b/py/test/selenium/webdriver/safari/launcher_tests.py @@ -43,9 +43,9 @@ class TestTechnologyPreview: @pytest.fixture def driver_kwargs(self): path = "/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver" - assert os.path.exists( - path - ), "Safari Technology Preview required! Download it from https://developer.apple.com/safari/technology-preview/" + assert os.path.exists(path), ( + "Safari Technology Preview required! Download it from https://developer.apple.com/safari/technology-preview/" + ) return {"executable_path": path} def test_launch(self, driver): diff --git a/py/test/selenium/webdriver/support/event_firing_webdriver_tests.py b/py/test/selenium/webdriver/support/event_firing_webdriver_tests.py index 6b6bf77ade830..e2a598e319f29 100644 --- a/py/test/selenium/webdriver/support/event_firing_webdriver_tests.py +++ b/py/test/selenium/webdriver/support/event_firing_webdriver_tests.py @@ -23,8 +23,7 @@ from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.common.actions.action_builder import ActionBuilder from selenium.webdriver.common.by import By -from selenium.webdriver.support.events import AbstractEventListener -from selenium.webdriver.support.events import EventFiringWebDriver +from selenium.webdriver.support.events import AbstractEventListener, EventFiringWebDriver from selenium.webdriver.support.ui import WebDriverWait @@ -113,9 +112,7 @@ def after_change_value_of(self, element, driver): keyReporter.send_keys("abc def") assert keyReporter.get_attribute("value") == "abc def" - assert ( - b"before_change_value_of" b"after_change_value_of" b"before_change_value_of" b"after_change_value_of" - ) == log.getvalue() + assert (b"before_change_value_ofafter_change_value_ofbefore_change_value_ofafter_change_value_of") == log.getvalue() def test_should_fire_find_event(driver, log, pages): diff --git a/py/test/selenium/webdriver/support/relative_by_tests.py b/py/test/selenium/webdriver/support/relative_by_tests.py index 8159330441211..d0f3be1182293 100644 --- a/py/test/selenium/webdriver/support/relative_by_tests.py +++ b/py/test/selenium/webdriver/support/relative_by_tests.py @@ -18,8 +18,7 @@ from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.common.by import By -from selenium.webdriver.support.relative_locator import locate_with -from selenium.webdriver.support.relative_locator import with_tag_name +from selenium.webdriver.support.relative_locator import locate_with, with_tag_name def test_should_be_able_to_find_first_one(driver, pages): diff --git a/py/test/unit/selenium/webdriver/common/fedcm/dialog_tests.py b/py/test/unit/selenium/webdriver/common/fedcm/dialog_tests.py index 30224b723a83a..e0b040149b5fa 100644 --- a/py/test/unit/selenium/webdriver/common/fedcm/dialog_tests.py +++ b/py/test/unit/selenium/webdriver/common/fedcm/dialog_tests.py @@ -15,8 +15,7 @@ # specific language governing permissions and limitations # under the License. -from unittest.mock import Mock -from unittest.mock import patch +from unittest.mock import Mock, patch import pytest diff --git a/py/test/unit/selenium/webdriver/firefox/firefox_options_tests.py b/py/test/unit/selenium/webdriver/firefox/firefox_options_tests.py index cea2e56f6da6f..106d4d74ab6f2 100644 --- a/py/test/unit/selenium/webdriver/firefox/firefox_options_tests.py +++ b/py/test/unit/selenium/webdriver/firefox/firefox_options_tests.py @@ -19,8 +19,7 @@ from selenium.common.exceptions import InvalidArgumentException from selenium.webdriver.common.options import PageLoadStrategy -from selenium.webdriver.common.proxy import Proxy -from selenium.webdriver.common.proxy import ProxyType +from selenium.webdriver.common.proxy import Proxy, ProxyType from selenium.webdriver.firefox.firefox_binary import FirefoxBinary from selenium.webdriver.firefox.firefox_profile import FirefoxProfile from selenium.webdriver.firefox.options import Options diff --git a/py/test/unit/selenium/webdriver/ie/test_ie_options.py b/py/test/unit/selenium/webdriver/ie/test_ie_options.py index 8f8f5008ababb..faf0c34bab701 100644 --- a/py/test/unit/selenium/webdriver/ie/test_ie_options.py +++ b/py/test/unit/selenium/webdriver/ie/test_ie_options.py @@ -19,8 +19,7 @@ import pytest from selenium.webdriver.common.options import PageLoadStrategy -from selenium.webdriver.ie.options import ElementScrollBehavior -from selenium.webdriver.ie.options import Options +from selenium.webdriver.ie.options import ElementScrollBehavior, Options TIMEOUT = 30 diff --git a/py/test/unit/selenium/webdriver/remote/error_handler_tests.py b/py/test/unit/selenium/webdriver/remote/error_handler_tests.py index 9f3098550efc8..3d5afdad2bc7c 100644 --- a/py/test/unit/selenium/webdriver/remote/error_handler_tests.py +++ b/py/test/unit/selenium/webdriver/remote/error_handler_tests.py @@ -18,8 +18,7 @@ import pytest from selenium.common import exceptions -from selenium.webdriver.remote.errorhandler import ErrorCode -from selenium.webdriver.remote.errorhandler import ErrorHandler +from selenium.webdriver.remote.errorhandler import ErrorCode, ErrorHandler @pytest.fixture @@ -269,7 +268,13 @@ def test_handle_errors_better(handler): "value": json.dumps( { "value": { - "message": "Could not start a new session. No Node supports the required capabilities: Capabilities {browserName: chrome, goog:chromeOptions: {args: [headless, silent], extensions: [], w3c: false}}, Capabilities {browserName: chrome, goog:chromeOptions: {args: [headless, silent], extensions: [], w3c: false}, version: }\nBuild info: version: '4.0.0-beta-3', revision: '5d108f9a67'\nSystem info: host: '9315f0a993d2', ip: '172.17.0.8', os.name: 'Linux', os.arch: 'amd64', os.version: '5.8.0-44-generic', java.version: '1.8.0_282'\nDriver info: driver.version: unknown" + "message": "Could not start a new session. No Node supports the required capabilities: " + + "Capabilities {browserName: chrome, goog:chromeOptions: {args: [headless, silent], " + + "extensions: [], w3c: false}}, Capabilities {browserName: chrome, goog:chromeOptions: " + + "{args: [headless, silent], extensions: [], w3c: false}, version: }\nBuild info: " + + "version: '4.0.0-beta-3', revision: '5d108f9a67'\nSystem info: host: '9315f0a993d2', " + + "ip: '172.17.0.8', os.name: 'Linux', os.arch: 'amd64', os.version: '5.8.0-44-generic', " + + "java.version: '1.8.0_282'\nDriver info: driver.version: unknown" } } ), diff --git a/py/test/unit/selenium/webdriver/remote/new_session_tests.py b/py/test/unit/selenium/webdriver/remote/new_session_tests.py index b8acd00bb81b4..a664fe2176fa7 100644 --- a/py/test/unit/selenium/webdriver/remote/new_session_tests.py +++ b/py/test/unit/selenium/webdriver/remote/new_session_tests.py @@ -21,10 +21,8 @@ import pytest from selenium.webdriver.chrome.options import Options as ChromeOptions -from selenium.webdriver.common.options import ArgOptions -from selenium.webdriver.common.options import PageLoadStrategy -from selenium.webdriver.common.proxy import Proxy -from selenium.webdriver.common.proxy import ProxyType +from selenium.webdriver.common.options import ArgOptions, PageLoadStrategy +from selenium.webdriver.common.proxy import Proxy, ProxyType from selenium.webdriver.remote import webdriver from selenium.webdriver.remote.command import Command from selenium.webdriver.remote.webdriver import WebDriver diff --git a/py/test/unit/selenium/webdriver/remote/remote_connection_tests.py b/py/test/unit/selenium/webdriver/remote/remote_connection_tests.py index 87294837a2e90..2c126878691cc 100644 --- a/py/test/unit/selenium/webdriver/remote/remote_connection_tests.py +++ b/py/test/unit/selenium/webdriver/remote/remote_connection_tests.py @@ -20,15 +20,13 @@ import pytest import urllib3 -from urllib3.util import Retry -from urllib3.util import Timeout +from urllib3.util import Retry, Timeout from selenium import __version__ from selenium.webdriver import Proxy from selenium.webdriver.common.proxy import ProxyType from selenium.webdriver.remote.client_config import AuthType -from selenium.webdriver.remote.remote_connection import ClientConfig -from selenium.webdriver.remote.remote_connection import RemoteConnection +from selenium.webdriver.remote.remote_connection import ClientConfig, RemoteConnection @pytest.fixture diff --git a/py/test/unit/selenium/webdriver/remote/subtyping_tests.py b/py/test/unit/selenium/webdriver/remote/subtyping_tests.py index 1162ec7031c3d..2380b69e0222a 100644 --- a/py/test/unit/selenium/webdriver/remote/subtyping_tests.py +++ b/py/test/unit/selenium/webdriver/remote/subtyping_tests.py @@ -16,8 +16,7 @@ # under the License. -from selenium.webdriver.remote.webdriver import WebDriver -from selenium.webdriver.remote.webdriver import WebElement +from selenium.webdriver.remote.webdriver import WebDriver, WebElement def test_web_element_not_subclassed(): diff --git a/py/test/unit/selenium/webdriver/virtual_authenticator/credentials_tests.py b/py/test/unit/selenium/webdriver/virtual_authenticator/credentials_tests.py index f5df75957b51a..f46ea0dbd9c9e 100644 --- a/py/test/unit/selenium/webdriver/virtual_authenticator/credentials_tests.py +++ b/py/test/unit/selenium/webdriver/virtual_authenticator/credentials_tests.py @@ -15,8 +15,7 @@ # specific language governing permissions and limitations # under the License. -from base64 import urlsafe_b64decode -from base64 import urlsafe_b64encode +from base64 import urlsafe_b64decode, urlsafe_b64encode from typing import Tuple import pytest diff --git a/py/tox.ini b/py/tox.ini index 7bf3bc7dbcdf9..5c33778ad319f 100644 --- a/py/tox.ini +++ b/py/tox.ini @@ -32,46 +32,10 @@ deps = trio-typing==0.10.0 commands = mypy --install-types {posargs} -[testenv:linting-ci] -; checks linting for CI with stricter exiting when failing and no rewriting -skip_install = true -deps = - isort==6.0.1 - black==25.1.0 - autoflake==2.3.1 - flake8==7.1.2 - flake8-pyproject==1.2.3 - flake8-typing-imports==1.16.0 - docformatter==1.7.5 -commands = - isort --check-only --diff selenium/ test/ conftest.py - black --check --diff selenium/ test/ conftest.py - autoflake --check-diff selenium/ test/ conftest.py - flake8 selenium/ test/ conftest.py - docformatter --check --diff selenium/ test/ conftest.py - [testenv:linting] -; A consolidated linting based recipe, responsible for executing linting tools across the code base. -; This encompasses: -; - isort for imports -; - black and flake8 for general formatting -; - autoflake for unused imports and variables -; - docformatter for docstrings -; IMPORTANT: -; - isort, black, autoflake, docformatter: will rewrite files -; - flake8: only alerts to the failures skip_install = true deps = - isort==6.0.1 - black==25.1.0 - autoflake==2.3.1 - flake8==7.1.2 - flake8-pyproject==1.2.3 - flake8-typing-imports==1.16.0 - docformatter==1.7.5 + ruff==0.11.10 commands = - isort selenium/ test/ conftest.py - black selenium/ test/ conftest.py - autoflake selenium/ test/ conftest.py - flake8 selenium/ test/ conftest.py - docformatter selenium/ test/ conftest.py + ruff check --fix --show-fixes --exit-non-zero-on-fix selenium/ test/ conftest.py + ruff format --exit-non-zero-on-format selenium/ test/ conftest.py diff --git a/scripts/format.sh b/scripts/format.sh index 3d799d10be00c..357403ec9ffb8 100755 --- a/scripts/format.sh +++ b/scripts/format.sh @@ -31,12 +31,9 @@ section "Rust" echo " rustfmt" >&2 bazel run @rules_rust//:rustfmt -# TODO: use bazel target when rules_python supports formatting section "Python" -echo " python - isort, black, autoflake, flake8, docformatter" >&2 -pip install tox -export TOXENV=linting -tox -c py/tox.ini +echo " python - ruff" >&2 +bazel run //py:format section "Copyright" bazel run //scripts:update_copyright diff --git a/scripts/pinned_browsers.py b/scripts/pinned_browsers.py index 77bc0a021acf3..8b056673cb6e2 100755 --- a/scripts/pinned_browsers.py +++ b/scripts/pinned_browsers.py @@ -28,23 +28,30 @@ def calculate_hash(url): def get_chrome_milestone(): parser = argparse.ArgumentParser() - parser.add_argument('--chrome_channel', default='Stable', help='Set the Chrome channel') + parser.add_argument( + "--chrome_channel", default="Stable", help="Set the Chrome channel" + ) args = parser.parse_args() channel = args.chrome_channel r = http.request( - "GET", f"https://chromiumdash.appspot.com/fetch_releases?channel={channel}&num=1&platform=Mac,Linux" + "GET", + f"https://chromiumdash.appspot.com/fetch_releases?channel={channel}&num=1&platform=Mac,Linux", ) all_versions = json.loads(r.data) # use the same milestone for all chrome releases, so pick the lowest - milestone = min([version["milestone"] for version in all_versions if version["milestone"]]) + milestone = min( + [version["milestone"] for version in all_versions if version["milestone"]] + ) r = http.request( - "GET", "https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json" + "GET", + "https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json", ) versions = json.loads(r.data)["versions"] return sorted( - filter(lambda v: v["version"].split(".")[0] == str(milestone), versions), key=lambda v: parse(v["version"]) + filter(lambda v: v["version"].split(".")[0] == str(milestone), versions), + key=lambda v: parse(v["version"]), )[-1] @@ -266,10 +273,7 @@ def edge(): ) \"\"\", ) -""" % ( - linux, - linux_hash.lower() - ) +""" % (linux, linux_hash.lower()) return content @@ -277,13 +281,18 @@ def edge(): def edgedriver(): r_stable = http.request("GET", "https://msedgedriver.azureedge.net/LATEST_STABLE") stable_version = r_stable.data.decode("utf-16").strip() - major_version = stable_version.split('.')[0] - r = http.request("GET", f"https://msedgedriver.azureedge.net/LATEST_RELEASE_{major_version}_LINUX") + major_version = stable_version.split(".")[0] + r = http.request( + "GET", + f"https://msedgedriver.azureedge.net/LATEST_RELEASE_{major_version}_LINUX", + ) linux_version = r.data.decode("utf-16").strip() content = "" - linux = "https://msedgedriver.azureedge.net/%s/edgedriver_linux64.zip" % linux_version + linux = ( + "https://msedgedriver.azureedge.net/%s/edgedriver_linux64.zip" % linux_version + ) sha = calculate_hash(linux) content = ( content @@ -308,7 +317,10 @@ def edgedriver(): % (linux, sha) ) - r = http.request("GET", f"https://msedgedriver.azureedge.net/LATEST_RELEASE_{major_version}_MACOS") + r = http.request( + "GET", + f"https://msedgedriver.azureedge.net/LATEST_RELEASE_{major_version}_MACOS", + ) macos_version = r.data.decode("utf-16").strip() mac = "https://msedgedriver.azureedge.net/%s/edgedriver_mac64.zip" % macos_version sha = calculate_hash(mac) @@ -340,7 +352,9 @@ def edgedriver(): def geckodriver(): content = "" - r = http.request("GET", "https://api.github.com/repos/mozilla/geckodriver/releases/latest") + r = http.request( + "GET", "https://api.github.com/repos/mozilla/geckodriver/releases/latest" + ) for a in json.loads(r.data)["assets"]: if a["name"].endswith("-linux64.tar.gz"): url = a["browser_download_url"] @@ -411,21 +425,30 @@ def firefox(): def firefox_version_data(): - versions = http.request("GET", "https://product-details.mozilla.org/1.0/firefox_versions.json") + versions = http.request( + "GET", "https://product-details.mozilla.org/1.0/firefox_versions.json" + ) return versions.data def firefox_linux(version): if int(version.split(".")[0]) < 135: - return "https://ftp.mozilla.org/pub/firefox/releases/%s/linux-x86_64/en-US/firefox-%s.tar.bz2" % ( - version, version) + return ( + "https://ftp.mozilla.org/pub/firefox/releases/%s/linux-x86_64/en-US/firefox-%s.tar.bz2" + % (version, version) + ) else: - return "https://ftp.mozilla.org/pub/firefox/releases/%s/linux-x86_64/en-US/firefox-%s.tar.xz" % ( - version, version) + return ( + "https://ftp.mozilla.org/pub/firefox/releases/%s/linux-x86_64/en-US/firefox-%s.tar.xz" + % (version, version) + ) def firefox_mac(version): - return "https://ftp.mozilla.org/pub/firefox/releases/%s/mac/en-US/Firefox%%20%s.dmg" % (version, version) + return ( + "https://ftp.mozilla.org/pub/firefox/releases/%s/mac/en-US/Firefox%%20%s.dmg" + % (version, version) + ) def print_firefox(version, workspace_name, sha_linux, sha_mac): diff --git a/scripts/selenium_manager.py b/scripts/selenium_manager.py index c4d96a8732ee6..8d417aba0a046 100755 --- a/scripts/selenium_manager.py +++ b/scripts/selenium_manager.py @@ -14,52 +14,50 @@ def get_url(): r = http.request( - "GET", f"https://github.com/SeleniumHQ/selenium_manager_artifacts/releases/latest" + "GET", + f"https://github.com/SeleniumHQ/selenium_manager_artifacts/releases/latest", ) return r.url.replace("tag", "download") def get_sha_json(): - r = http.request("GET", f"https://raw.githubusercontent.com/SeleniumHQ/selenium_manager_artifacts/trunk/latest.json") + r = http.request( + "GET", + f"https://raw.githubusercontent.com/SeleniumHQ/selenium_manager_artifacts/trunk/latest.json", + ) return json.loads(r.data) def print_linux(base_url, sha): - return (""" http_file( + return """ http_file( name = "download_sm_linux", executable = True, sha256 = "%s", url = "%s", ) -""" - % (sha, base_url + "/selenium-manager-linux") - ) +""" % (sha, base_url + "/selenium-manager-linux") def print_macos(base_url, sha): - return (""" http_file( + return """ http_file( name = "download_sm_macos", executable = True, sha256 = "%s", url = "%s", ) -""" - % (sha, base_url + "/selenium-manager-macos") - ) +""" % (sha, base_url + "/selenium-manager-macos") def print_windows(base_url, sha): - return (""" http_file( + return """ http_file( name = "download_sm_windows", executable = True, sha256 = "%s", url = "%s", ) -""" - % (sha, base_url + "/selenium-manager-windows.exe") - ) +""" % (sha, base_url + "/selenium-manager-windows.exe") if __name__ == "__main__": @@ -71,9 +69,9 @@ def selenium_manager(): """ base_url = get_url() sha_dict = get_sha_json() - content = content + print_linux(base_url, sha_dict['linux']) - content = content + print_macos(base_url, sha_dict['macos']) - content = content + print_windows(base_url, sha_dict['windows']) + content = content + print_linux(base_url, sha_dict["linux"]) + content = content + print_macos(base_url, sha_dict["macos"]) + content = content + print_windows(base_url, sha_dict["windows"]) content += """ def _selenium_manager_artifacts_impl(_ctx): selenium_manager() diff --git a/scripts/update_cdp.py b/scripts/update_cdp.py index 9c978449fc828..a17c36479610d 100755 --- a/scripts/update_cdp.py +++ b/scripts/update_cdp.py @@ -21,23 +21,30 @@ def get_chrome_milestone(): """This is the same method from pinned_browser. Use --chrome_channel=Beta if using early stable release.""" parser = argparse.ArgumentParser() - parser.add_argument("--chrome_channel", default="Stable", help="Set the Chrome channel") + parser.add_argument( + "--chrome_channel", default="Stable", help="Set the Chrome channel" + ) args = parser.parse_args() channel = args.chrome_channel r = http.request( - "GET", f"https://chromiumdash.appspot.com/fetch_releases?channel={channel}&num=1&platform=Mac,Linux" + "GET", + f"https://chromiumdash.appspot.com/fetch_releases?channel={channel}&num=1&platform=Mac,Linux", ) all_versions = json.loads(r.data) # use the same milestone for all Chrome releases, so pick the lowest - milestone = min([version["milestone"] for version in all_versions if version["milestone"]]) + milestone = min( + [version["milestone"] for version in all_versions if version["milestone"]] + ) r = http.request( - "GET", "https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json" + "GET", + "https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json", ) versions = json.loads(r.data)["versions"] return sorted( - filter(lambda v: v["version"].split(".")[0] == str(milestone), versions), key=lambda v: parse(v["version"]) + filter(lambda v: v["version"].split(".")[0] == str(milestone), versions), + key=lambda v: parse(v["version"]), )[-1] @@ -60,7 +67,9 @@ def old_chrome(chrome_milestone): def add_pdls(chrome_milestone): - source_dir = root_dir / f"common/devtools/chromium/v{previous_chrome(chrome_milestone)}" + source_dir = ( + root_dir / f"common/devtools/chromium/v{previous_chrome(chrome_milestone)}" + ) target_dir = root_dir / f"common/devtools/chromium/v{new_chrome(chrome_milestone)}" old_dir = root_dir / f"common/devtools/chromium/v{old_chrome(chrome_milestone)}" @@ -78,9 +87,14 @@ def add_pdls(chrome_milestone): ) deps_content = http.request( - "GET", f"https://raw.githubusercontent.com/chromium/chromium/{chrome_milestone['version']}/DEPS" + "GET", + f"https://raw.githubusercontent.com/chromium/chromium/{chrome_milestone['version']}/DEPS", ).data.decode("utf-8") - v8_revision = [line for line in deps_content.split("\n") if "v8_revision" in line][0].split(": ")[1].strip("',") + v8_revision = ( + [line for line in deps_content.split("\n") if "v8_revision" in line][0] + .split(": ")[1] + .strip("',") + ) fetch_and_save( f"https://raw.githubusercontent.com/v8/v8/{v8_revision}/include/js_protocol.pdl", f"{target_dir}/js_protocol.pdl", @@ -112,8 +126,12 @@ def create_new_chrome_files(src_base, chrome_milestone): shutil.copy(item, target_dir) for file in target_dir.iterdir(): - replace_in_file(file, previous_chrome(chrome_milestone), new_chrome(chrome_milestone)) - new_filename = file.name.replace(previous_chrome(chrome_milestone), new_chrome(chrome_milestone)) + replace_in_file( + file, previous_chrome(chrome_milestone), new_chrome(chrome_milestone) + ) + new_filename = file.name.replace( + previous_chrome(chrome_milestone), new_chrome(chrome_milestone) + ) file.rename(target_dir / new_filename) subprocess.run(["git", "add", str(target_dir / "*")], cwd=root_dir) @@ -137,7 +155,9 @@ def update_java(chrome_milestone): root_dir / "Rakefile", ] for file in files: - replace_in_file(file, old_chrome(chrome_milestone), new_chrome(chrome_milestone)) + replace_in_file( + file, old_chrome(chrome_milestone), new_chrome(chrome_milestone) + ) def update_dotnet(chrome_milestone): @@ -149,13 +169,19 @@ def update_dotnet(chrome_milestone): root_dir / "dotnet/src/webdriver/DevTools/DevToolsDomains.cs", ] for file in files: - replace_in_file(file, old_chrome(chrome_milestone), new_chrome(chrome_milestone)) + replace_in_file( + file, old_chrome(chrome_milestone), new_chrome(chrome_milestone) + ) - files = [root_dir / "dotnet/test/common/CustomDriverConfigs/StableChannelChromeDriver.cs"] + files = [ + root_dir / "dotnet/test/common/CustomDriverConfigs/StableChannelChromeDriver.cs" + ] dir_path = root_dir / "dotnet/test/common/DevTools" files.extend(str(file) for file in dir_path.glob("*") if file.is_file()) for file in files: - replace_in_file(file, previous_chrome(chrome_milestone), new_chrome(chrome_milestone)) + replace_in_file( + file, previous_chrome(chrome_milestone), new_chrome(chrome_milestone) + ) def update_ruby(chrome_milestone): @@ -163,10 +189,16 @@ def update_ruby(chrome_milestone): replace_in_file(file, old_chrome(chrome_milestone), new_chrome(chrome_milestone)) file = root_dir / "rb/lib/selenium/devtools/version.rb" - replace_in_file(file, rf"{previous_chrome(chrome_milestone)}\.[0-9]*", f"{new_chrome(chrome_milestone)}.0", True) + replace_in_file( + file, + rf"{previous_chrome(chrome_milestone)}\.[0-9]*", + f"{new_chrome(chrome_milestone)}.0", + True, + ) subprocess.run(["bundle", "install"], cwd=root_dir / "rb", check=True) + def update_python(chrome_milestone): file = root_dir / "py/BUILD.bazel" replace_in_file(file, old_chrome(chrome_milestone), new_chrome(chrome_milestone)) @@ -186,4 +218,6 @@ def update_js(chrome_milestone): update_python(chrome_milestone) update_js(chrome_milestone) - print(f"adding CDP {new_chrome(chrome_milestone)} and removing {old_chrome(chrome_milestone)}") + print( + f"adding CDP {new_chrome(chrome_milestone)} and removing {old_chrome(chrome_milestone)}" + ) diff --git a/scripts/update_copyright.py b/scripts/update_copyright.py index 57e37abb7a406..d61d03127d296 100755 --- a/scripts/update_copyright.py +++ b/scripts/update_copyright.py @@ -4,6 +4,7 @@ import os from pathlib import Path + class Copyright: NOTICE = """Licensed to the Software Freedom Conservancy (SFC) under one or more contributor license agreements. See the NOTICE file @@ -22,19 +23,20 @@ class Copyright: specific language governing permissions and limitations under the License.""" - def __init__(self, comment_characters='//', prefix=None): + def __init__(self, comment_characters="//", prefix=None): self._comment_characters = comment_characters self._prefix = prefix or [] def update(self, files): for file in files: - with open(file, 'r', encoding='utf-8-sig') as f: + with open(file, "r", encoding="utf-8-sig") as f: lines = f.readlines() index = -1 for i, line in enumerate(lines): - if line.startswith(self._comment_characters) or \ - self.valid_copyright_notice_line(line, index, file): + if line.startswith( + self._comment_characters + ) or self.valid_copyright_notice_line(line, index, file): index += 1 else: break @@ -42,39 +44,48 @@ def update(self, files): if index == -1: self.write_update_notice(file, lines) else: - current = ''.join(lines[:index + 1]) + current = "".join(lines[: index + 1]) if current != self.copyright_notice(file): - self.write_update_notice(file, lines[index + 1:]) + self.write_update_notice(file, lines[index + 1 :]) def valid_copyright_notice_line(self, line, index, file): - return index + 1 < len(self.copyright_notice_lines(file)) and \ - line.startswith(self.copyright_notice_lines(file)[index + 1]) + return index + 1 < len(self.copyright_notice_lines(file)) and line.startswith( + self.copyright_notice_lines(file)[index + 1] + ) def copyright_notice(self, file): - return ''.join(self.copyright_notice_lines(file)) + return "".join(self.copyright_notice_lines(file)) def copyright_notice_lines(self, file): - return self.dotnet(file) if file.endswith("cs") else self._prefix + self.commented_notice_lines + return ( + self.dotnet(file) + if file.endswith("cs") + else self._prefix + self.commented_notice_lines + ) def dotnet(self, file): file_name = os.path.basename(file) - first = f"{self._comment_characters} \n" + first = f'{self._comment_characters} \n' last = f"{self._comment_characters} " return [first] + self.commented_notice_lines + [last] @property def commented_notice_lines(self): - return [f"{self._comment_characters} {line}".rstrip() + "\n" for line in self.NOTICE.split('\n')] + return [ + f"{self._comment_characters} {line}".rstrip() + "\n" + for line in self.NOTICE.split("\n") + ] def write_update_notice(self, file, lines): print(f"Adding notice to {file}") - with open(file, 'w') as f: + with open(file, "w") as f: f.write(self.copyright_notice(file) + "\n") if lines and lines[0] != "\n": f.write("\n") trimmed_lines = [line.rstrip() + "\n" for line in lines] f.writelines(trimmed_lines) + ROOT = Path(os.path.realpath(__file__)).parent.parent JS_EXCLUSIONS = [ @@ -87,18 +98,18 @@ def write_update_notice(self, file, lines): f"{ROOT}/javascript/selenium-core/scripts/user-extensions.js", f"{ROOT}/javascript/selenium-core/scripts/xmlextras.js", f"{ROOT}/javascript/selenium-core/xpath/**/*.js", - f"{ROOT}/javascript/grid-ui/node_modules/**/*.js" + f"{ROOT}/javascript/grid-ui/node_modules/**/*.js", ] PY_EXCLUSIONS = [ f"{ROOT}/py/selenium/webdriver/common/bidi/cdp.py", f"{ROOT}/py/generate.py", f"{ROOT}/py/selenium/webdriver/common/devtools/**/*", - f"{ROOT}/py/venv/**/*" + f"{ROOT}/py/venv/**/*", ] -def update_files(file_pattern, exclusions, comment_characters='//', prefix=None): +def update_files(file_pattern, exclusions, comment_characters="//", prefix=None): included = set(glob.glob(file_pattern, recursive=True)) excluded = set() for pattern in exclusions: @@ -113,7 +124,12 @@ def update_files(file_pattern, exclusions, comment_characters='//', prefix=None) update_files(f"{ROOT}/javascript/**/*.js", JS_EXCLUSIONS) update_files(f"{ROOT}/javascript/**/*.tsx", []) update_files(f"{ROOT}/py/**/*.py", PY_EXCLUSIONS, comment_characters="#") - update_files(f"{ROOT}/rb/**/*.rb", [], comment_characters="#", prefix=["# frozen_string_literal: true\n", "\n"]) + update_files( + f"{ROOT}/rb/**/*.rb", + [], + comment_characters="#", + prefix=["# frozen_string_literal: true\n", "\n"], + ) update_files(f"{ROOT}/java/**/*.java", []) update_files(f"{ROOT}/rust/**/*.rs", []) update_files(f"{ROOT}/dotnet/**/*.cs", [])