Skip to content

Commit 5b2aa6c

Browse files
Speed up the generation of no-member suggestions (#10277) (#10311)
Previously, edit distances were calculated for strings that had length differences greater than the maximum suggestion threshold. Remove handling of missing-member-hint-distance = 0 Co-authored-by: Pierre Sassoulas <[email protected]> (cherry picked from commit 9a6168d) Co-authored-by: correctmost <[email protected]>
1 parent 744ba53 commit 5b2aa6c

File tree

3 files changed

+64
-3
lines changed

3 files changed

+64
-3
lines changed

doc/whatsnew/fragments/10277.other

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
The algorithm used for ``no-member`` suggestions is now more efficient and cut the
2+
calculation when the distance score is already above the threshold.
3+
4+
Refs #10277

pylint/checkers/typecheck.py

+16-3
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,12 @@ def _(node: nodes.ClassDef | bases.Instance) -> Iterable[str]:
150150
return itertools.chain(values, other_values)
151151

152152

153-
def _string_distance(seq1: str, seq2: str) -> int:
154-
seq2_length = len(seq2)
153+
def _string_distance(seq1: str, seq2: str, seq1_length: int, seq2_length: int) -> int:
154+
if not seq1_length:
155+
return seq2_length
156+
157+
if not seq2_length:
158+
return seq1_length
155159

156160
row = [*list(range(1, seq2_length + 1)), 0]
157161
for seq1_index, seq1_char in enumerate(seq1):
@@ -182,11 +186,20 @@ def _similar_names(
182186
possible_names: list[tuple[str, int]] = []
183187
names = _node_names(owner)
184188

189+
attr_str = attrname or ""
190+
attr_len = len(attr_str)
191+
185192
for name in names:
186193
if name == attrname:
187194
continue
188195

189-
distance = _string_distance(attrname or "", name)
196+
name_len = len(name)
197+
198+
min_distance = abs(attr_len - name_len)
199+
if min_distance > distance_threshold:
200+
continue
201+
202+
distance = _string_distance(attr_str, name, attr_len, name_len)
190203
if distance <= distance_threshold:
191204
possible_names.append((name, distance))
192205

tests/checkers/unittest_typecheck.py

+44
Original file line numberDiff line numberDiff line change
@@ -221,3 +221,47 @@ def decorated():
221221
)
222222
):
223223
self.checker.visit_subscript(subscript)
224+
225+
226+
class TestTypeCheckerStringDistance:
227+
"""Tests for the _string_distance helper in pylint.checkers.typecheck."""
228+
229+
def test_string_distance_identical_strings(self) -> None:
230+
seq1 = "hi"
231+
seq2 = "hi"
232+
assert typecheck._string_distance(seq1, seq2, len(seq1), len(seq2)) == 0
233+
234+
seq1, seq2 = seq2, seq1
235+
assert typecheck._string_distance(seq1, seq2, len(seq1), len(seq2)) == 0
236+
237+
def test_string_distance_empty_string(self) -> None:
238+
seq1 = ""
239+
seq2 = "hi"
240+
assert typecheck._string_distance(seq1, seq2, len(seq1), len(seq2)) == 2
241+
242+
seq1, seq2 = seq2, seq1
243+
assert typecheck._string_distance(seq1, seq2, len(seq1), len(seq2)) == 2
244+
245+
def test_string_distance_edit_distance_one_character(self) -> None:
246+
seq1 = "hi"
247+
seq2 = "he"
248+
assert typecheck._string_distance(seq1, seq2, len(seq1), len(seq2)) == 1
249+
250+
seq1, seq2 = seq2, seq1
251+
assert typecheck._string_distance(seq1, seq2, len(seq1), len(seq2)) == 1
252+
253+
def test_string_distance_edit_distance_multiple_similar_characters(self) -> None:
254+
seq1 = "hello"
255+
seq2 = "yelps"
256+
assert typecheck._string_distance(seq1, seq2, len(seq1), len(seq2)) == 3
257+
258+
seq1, seq2 = seq2, seq1
259+
assert typecheck._string_distance(seq1, seq2, len(seq1), len(seq2)) == 3
260+
261+
def test_string_distance_edit_distance_all_dissimilar_characters(self) -> None:
262+
seq1 = "yellow"
263+
seq2 = "orange"
264+
assert typecheck._string_distance(seq1, seq2, len(seq1), len(seq2)) == 6
265+
266+
seq1, seq2 = seq2, seq1
267+
assert typecheck._string_distance(seq1, seq2, len(seq1), len(seq2)) == 6

0 commit comments

Comments
 (0)