Skip to content

[py] Use ruff for linting and code formatting #15746

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
May 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
bb64a90
[py] Add ruff linter/formatter and fix violations
cgoldberg May 5, 2025
119181e
Merge branch 'SeleniumHQ:trunk' into py-ruff
cgoldberg May 6, 2025
cd40251
Merge branch 'SeleniumHQ:trunk' into py-ruff
cgoldberg May 6, 2025
d5f6d35
Merge branch 'SeleniumHQ:trunk' into py-ruff
cgoldberg May 7, 2025
34286e9
Merge branch 'SeleniumHQ:trunk' into py-ruff
cgoldberg May 10, 2025
a61cadf
Merge branch 'SeleniumHQ:trunk' into py-ruff
cgoldberg May 11, 2025
80bd62f
Merge branch 'SeleniumHQ:trunk' into py-ruff
cgoldberg May 11, 2025
0207e95
Merge branch 'SeleniumHQ:trunk' into py-ruff
cgoldberg May 13, 2025
b502193
Merge branch 'SeleniumHQ:trunk' into py-ruff
cgoldberg May 14, 2025
4a6bf9e
Merge branch 'SeleniumHQ:trunk' into py-ruff
cgoldberg May 15, 2025
d54aacf
Merge branch 'SeleniumHQ:trunk' into py-ruff
cgoldberg May 15, 2025
e07e050
Merge branch 'SeleniumHQ:trunk' into py-ruff
cgoldberg May 15, 2025
04791a7
[py] Remove old linters and add ruff
cgoldberg May 16, 2025
24d0194
[py] Fix the rest of the linting errors
cgoldberg May 16, 2025
95b5594
[py] Remove docformatter and update README.md
cgoldberg May 16, 2025
9aa794f
[py] Fix docstring
cgoldberg May 16, 2025
780297e
[py] Remove comments
cgoldberg May 16, 2025
1797093
[py] Plug-in ruff into Bazel
p0deje May 16, 2025
1db60e9
[py] Update readme
p0deje May 16, 2025
b244b2c
Merge branch 'SeleniumHQ:trunk' into py-ruff
cgoldberg May 16, 2025
fb7f0f1
[py] Add import sorting
cgoldberg May 16, 2025
6ae2f4c
[py] Remove docformatter from tox
cgoldberg May 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 0 additions & 22 deletions .github/workflows/ci-python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
@@ -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")
Expand Down
14 changes: 3 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
6 changes: 0 additions & 6 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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`
Expand Down
25 changes: 16 additions & 9 deletions common/devtools/convert_protocol_to_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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:]))
136 changes: 74 additions & 62 deletions common/devtools/pdl.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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

Expand Down
8 changes: 4 additions & 4 deletions javascript/grid-ui/scripts/rmSourcemaps.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Loading
Loading