Skip to content

Commit 96eb8ff

Browse files
committed
Fix pylint not found in CI
1 parent 9624b9a commit 96eb8ff

4 files changed

Lines changed: 71 additions & 16 deletions

File tree

test/pylint/BUILD

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
load("@rules_python//python:py_binary.bzl", "py_binary")
1516
load("//test/pylint:pylint_test.bzl", "pylint_test")
1617

1718
exports_files([
@@ -20,6 +21,13 @@ exports_files([
2021
"requirements.txt",
2122
])
2223

24+
py_binary(
25+
name = "pylint_bin",
26+
srcs = ["pylint_bin.py"],
27+
visibility = ["//visibility:public"],
28+
deps = ["@pylint_deps//pylint"],
29+
)
30+
2331
pylint_test(
2432
name = "pylint",
2533
exclude = [
@@ -31,6 +39,6 @@ pylint_test(
3139
"test",
3240
"__init__.py",
3341
],
34-
pylint = "@pylint_deps//pylint",
42+
pylint = ":pylint_bin",
3543
pylintrc = ":.pylintrc",
3644
)

test/pylint/pylint_bin.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Copyright 2026 Ericsson AB
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Entry point wrapper for pylint, used as a Bazel py_binary."""
16+
17+
from pylint import run_pylint
18+
19+
run_pylint()

test/pylint/pylint_runner.py

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,16 @@
1818
Uses a workspace marker file (like MODULE.bazel) to find the repo
1919
root.
2020
21-
Pylint is imported as a Python dependency provided by Bazel,
22-
not invoked from PATH.
21+
The pylint executable is provided by Bazel as a py_binary and
22+
passed via the --pylint argument.
2323
"""
2424

2525
import argparse
2626
import os
2727
import pathlib
28+
import subprocess
2829
import sys
2930

30-
from pylint import lint
31-
3231

3332
def workspace_root(marker):
3433
"""Resolve the workspace root from a marker file."""
@@ -52,11 +51,33 @@ def find_py_files(root, paths, exclude_patterns):
5251
return files
5352

5453

54+
def resolve_runfile(path):
55+
"""Resolve a Bazel rootpath to an absolute path via runfiles."""
56+
# In a py_test, the working directory is the runfiles tree
57+
# so rootpaths can be resolved relative to cwd
58+
resolved = os.path.realpath(path)
59+
if os.path.exists(resolved):
60+
return resolved
61+
# Try via RUNFILES_DIR
62+
runfiles_dir = os.environ.get("RUNFILES_DIR", "")
63+
workspace = os.environ.get("TEST_WORKSPACE", "_main")
64+
if runfiles_dir:
65+
candidate = os.path.join(runfiles_dir, workspace, path)
66+
if os.path.exists(candidate):
67+
return os.path.realpath(candidate)
68+
return resolved
69+
70+
5571
def main():
5672
"""Parse arguments and run pylint on discovered sources."""
5773
parser = argparse.ArgumentParser(
5874
description="Run pylint on Python source files."
5975
)
76+
parser.add_argument(
77+
"--pylint",
78+
required=True,
79+
help="Path to the pylint executable.",
80+
)
6081
parser.add_argument(
6182
"--workspace",
6283
required=True,
@@ -82,6 +103,12 @@ def main():
82103
)
83104
args = parser.parse_args()
84105

106+
# Resolve paths before changing directories
107+
pylint_exe = resolve_runfile(args.pylint)
108+
rcfile_path = None
109+
if args.rcfile:
110+
rcfile_path = os.path.realpath(args.rcfile)
111+
85112
root = workspace_root(args.workspace)
86113
sources = find_py_files(root, args.paths, args.exclude)
87114

@@ -93,15 +120,14 @@ def main():
93120
# (which uses os.getcwd()) can resolve project imports
94121
os.chdir(root)
95122

96-
pylint_args = []
97-
if args.rcfile:
98-
rcfile_path = os.path.realpath(args.rcfile)
99-
pylint_args.append(f"--rcfile={rcfile_path}")
100-
pylint_args.extend(str(s) for s in sources)
123+
cmd = [pylint_exe]
124+
if rcfile_path:
125+
cmd.append(f"--rcfile={rcfile_path}")
126+
cmd.extend(str(s) for s in sources)
101127

102-
print(f"Running: pylint {' '.join(pylint_args)}")
103-
result = lint.Run(pylint_args, exit=False)
104-
sys.exit(result.linter.msg_status)
128+
print(f"Running: {' '.join(cmd)}")
129+
result = subprocess.run(cmd, check=False)
130+
sys.exit(result.returncode)
105131

106132

107133
if __name__ == "__main__":

test/pylint/pylint_test.bzl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ Usage:
2626
],
2727
paths = [
2828
"src",
29+
2930
],
30-
pylint = "@pylint_deps//pylint",
31+
pylint = ":pylint_bin",
3132
pylintrc = ":.pylintrc",
3233
workspace = "//:MODULE.bazel",
3334
)
@@ -48,7 +49,7 @@ def pylint_test(
4849
4950
Args:
5051
name: Test name.
51-
pylint: Label of the pylint pip package.
52+
pylint: Label of the pylint py_binary executable.
5253
pylintrc: Label of the .pylintrc configuration file.
5354
paths: Directories or .py files to lint (relative to workspace root).
5455
workspace: Label of a file at the workspace root, used to locate
@@ -64,6 +65,7 @@ def pylint_test(
6465
pylint_tags.append("external")
6566

6667
args = [
68+
"--pylint=$(rootpath {})".format(pylint),
6769
"--workspace=$(rootpath {})".format(workspace),
6870
"--rcfile=$(rootpath {})".format(pylintrc),
6971
]
@@ -79,10 +81,10 @@ def pylint_test(
7981
main = "//test/pylint:pylint_runner.py",
8082
args = args,
8183
data = [
84+
pylint,
8285
pylintrc,
8386
workspace,
8487
],
85-
deps = [pylint],
8688
local = True,
8789
tags = pylint_tags,
8890
**kwargs

0 commit comments

Comments
 (0)