Skip to content

Commit ffcdf42

Browse files
d1gl3DanielNoordPierre-Sassoulas
committed
Prevent pylint.run._cpu_count() from returning 0 (#6903)
Co-authored-by: Daniël van Noord <[email protected]> Co-authored-by: Pierre Sassoulas <[email protected]>
1 parent c742f8f commit ffcdf42

File tree

3 files changed

+48
-1
lines changed

3 files changed

+48
-1
lines changed

doc/whatsnew/2/2.14/full.rst

+5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ What's New in Pylint 2.14.2?
55
----------------------------
66
Release date: TBA
77

8+
* Don't crash if ``lint.run._query_cpu()`` is run within a Kubernetes Pod, that has only
9+
a fraction of a cpu core assigned. Just go with one process then.
10+
11+
Closes #6902
12+
813
* Fixed a false positive in ``consider-using-f-string`` if the left side of a ``%`` is not a string.
914

1015
Closes #6689

pylint/lint/run.py

+7
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@ def _query_cpu() -> int | None:
5858
cpu_shares = int(file.read().rstrip())
5959
# For AWS, gives correct value * 1024.
6060
avail_cpu = int(cpu_shares / 1024)
61+
62+
# In K8s Pods also a fraction of a single core could be available
63+
# As multiprocessing is not able to run only a "fraction" of process
64+
# assume we have 1 CPU available
65+
if avail_cpu == 0:
66+
avail_cpu = 1
67+
6168
return avail_cpu
6269

6370

tests/test_pylint_runners.py

+36-1
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,17 @@
66
from __future__ import annotations
77

88
import os
9+
import pathlib
910
import sys
1011
from collections.abc import Callable
11-
from unittest.mock import patch
12+
from unittest.mock import MagicMock, mock_open, patch
1213

1314
import pytest
1415
from py._path.local import LocalPath # type: ignore[import]
1516

1617
from pylint import run_epylint, run_pylint, run_pyreverse, run_symilar
18+
from pylint.lint import Run
19+
from pylint.testutils import GenericTestReporter as Reporter
1720

1821

1922
@pytest.mark.parametrize(
@@ -40,3 +43,35 @@ def test_runner_with_arguments(runner: Callable, tmpdir: LocalPath) -> None:
4043
with pytest.raises(SystemExit) as err:
4144
runner(testargs)
4245
assert err.value.code == 0
46+
47+
48+
def test_pylint_run_jobs_equal_zero_dont_crash_with_cpu_fraction(
49+
tmpdir: LocalPath,
50+
) -> None:
51+
"""Check that the pylint runner does not crash if `pylint.lint.run._query_cpu`
52+
determines only a fraction of a CPU core to be available.
53+
"""
54+
builtin_open = open
55+
56+
def _mock_open(*args, **kwargs):
57+
if args[0] == "/sys/fs/cgroup/cpu/cpu.cfs_quota_us":
58+
return mock_open(read_data=b"-1")(*args, **kwargs)
59+
if args[0] == "/sys/fs/cgroup/cpu/cpu.shares":
60+
return mock_open(read_data=b"2")(*args, **kwargs)
61+
return builtin_open(*args, **kwargs)
62+
63+
pathlib_path = pathlib.Path
64+
65+
def _mock_path(*args, **kwargs):
66+
if args[0] == "/sys/fs/cgroup/cpu/cpu.shares":
67+
return MagicMock(is_file=lambda: True)
68+
return pathlib_path(*args, **kwargs)
69+
70+
filepath = os.path.abspath(__file__)
71+
testargs = [filepath, "--jobs=0"]
72+
with tmpdir.as_cwd():
73+
with pytest.raises(SystemExit) as err:
74+
with patch("builtins.open", _mock_open):
75+
with patch("pylint.lint.run.Path", _mock_path):
76+
Run(testargs, reporter=Reporter())
77+
assert err.value.code == 0

0 commit comments

Comments
 (0)