Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitf104914

Browse files
authored
Improve performance for errors on class with many attributes (#14379)
When checking manticore with `--check-untyped-defs`, this is a 4x totalspeedup from master, from ~320s to ~80s (uncompiled).I looked into this because ofpython/typeshed#9443 (comment)
1 parent5f480f3 commitf104914

File tree

5 files changed

+32
-19
lines changed

5 files changed

+32
-19
lines changed

‎mypy/messages.py‎

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
importre
1616
fromcontextlibimportcontextmanager
1717
fromtextwrapimportdedent
18-
fromtypingimportAny,Callable,Iterable,Iterator,List,Sequence,cast
18+
fromtypingimportAny,Callable,Collection,Iterable,Iterator,List,Sequence,cast
1919
fromtyping_extensionsimportFinal
2020

2121
frommypyimporterrorcodesascodes,message_registry
@@ -440,7 +440,7 @@ def has_no_attr(
440440
alternatives.discard(member)
441441

442442
matches= [mforminCOMMON_MISTAKES.get(member, [])ifminalternatives]
443-
matches.extend(best_matches(member,alternatives)[:3])
443+
matches.extend(best_matches(member,alternatives,n=3))
444444
ifmember=="__aiter__"andmatches== ["__iter__"]:
445445
matches= []# Avoid misleading suggestion
446446
ifmatches:
@@ -928,11 +928,11 @@ def unexpected_keyword_argument(
928928
matching_type_args.append(callee_arg_name)
929929
else:
930930
not_matching_type_args.append(callee_arg_name)
931-
matches=best_matches(name,matching_type_args)
931+
matches=best_matches(name,matching_type_args,n=3)
932932
ifnotmatches:
933-
matches=best_matches(name,not_matching_type_args)
933+
matches=best_matches(name,not_matching_type_args,n=3)
934934
ifmatches:
935-
msg+=f"; did you mean{pretty_seq(matches[:3],'or')}?"
935+
msg+=f"; did you mean{pretty_seq(matches,'or')}?"
936936
self.fail(msg,context,code=codes.CALL_ARG)
937937
module=find_defining_module(self.modules,callee)
938938
ifmodule:
@@ -1695,10 +1695,10 @@ def typeddict_key_not_found(
16951695
context,
16961696
code=codes.TYPEDDICT_ITEM,
16971697
)
1698-
matches=best_matches(item_name,typ.items.keys())
1698+
matches=best_matches(item_name,typ.items.keys(),n=3)
16991699
ifmatches:
17001700
self.note(
1701-
"Did you mean {}?".format(pretty_seq(matches[:3],"or")),
1701+
"Did you mean {}?".format(pretty_seq(matches,"or")),
17021702
context,
17031703
code=codes.TYPEDDICT_ITEM,
17041704
)
@@ -2798,11 +2798,24 @@ def find_defining_module(modules: dict[str, MypyFile], typ: CallableType) -> Myp
27982798
COMMON_MISTAKES:Final[dict[str,Sequence[str]]]= {"add": ("append","extend")}
27992799

28002800

2801-
defbest_matches(current:str,options:Iterable[str])->list[str]:
2802-
ratios= {v:difflib.SequenceMatcher(a=current,b=v).ratio()forvinoptions}
2803-
returnsorted(
2804-
(oforoinoptionsifratios[o]>0.75),reverse=True,key=lambdav: (ratios[v],v)
2805-
)
2801+
def_real_quick_ratio(a:str,b:str)->float:
2802+
# this is an upper bound on difflib.SequenceMatcher.ratio
2803+
# similar to difflib.SequenceMatcher.real_quick_ratio, but faster since we don't instantiate
2804+
al=len(a)
2805+
bl=len(b)
2806+
return2.0*min(al,bl)/ (al+bl)
2807+
2808+
2809+
defbest_matches(current:str,options:Collection[str],n:int)->list[str]:
2810+
# narrow down options cheaply
2811+
assertcurrent
2812+
options= [oforoinoptionsif_real_quick_ratio(current,o)>0.75]
2813+
iflen(options)>=50:
2814+
options= [oforoinoptionsifabs(len(o)-len(current))<=1]
2815+
2816+
ratios= {option:difflib.SequenceMatcher(a=current,b=option).ratio()foroptioninoptions}
2817+
options= [optionforoption,ratioinratios.items()ifratio>0.75]
2818+
returnsorted(options,key=lambdav: (-ratios[v],v))[:n]
28062819

28072820

28082821
defpretty_seq(args:Sequence[str],conjunction:str)->str:

‎mypy/semanal.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2531,7 +2531,7 @@ def report_missing_module_attribute(
25312531
)
25322532
else:
25332533
alternatives=set(module.names.keys()).difference({source_id})
2534-
matches=best_matches(source_id,alternatives)[:3]
2534+
matches=best_matches(source_id,alternatives,n=3)
25352535
ifmatches:
25362536
suggestion=f"; maybe{pretty_seq(matches,'or')}?"
25372537
message+=f"{suggestion}"

‎test-data/unit/check-kwargs.test‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ class A: pass
8787

8888
[case testMultipleKeywordsForMisspelling]
8989
def f(thing : 'A', other: 'A', atter: 'A', btter: 'B') -> None: pass # N: "f" defined here
90-
f(otter=A()) # E: Unexpected keyword argument "otter" for "f"; did you mean "other" or "atter"?
90+
f(otter=A()) # E: Unexpected keyword argument "otter" for "f"; did you mean "atter" or "other"?
9191
class A: pass
9292
class B: pass
9393

@@ -99,15 +99,15 @@ class B: pass
9999

100100
[case testKeywordMisspellingInheritance]
101101
def f(atter: 'A', btter: 'B', ctter: 'C') -> None: pass # N: "f" defined here
102-
f(otter=B()) # E: Unexpected keyword argument "otter" for "f"; did you mean "btter" or "atter"?
102+
f(otter=B()) # E: Unexpected keyword argument "otter" for "f"; did you mean "atter" or "btter"?
103103
class A: pass
104104
class B(A): pass
105105
class C: pass
106106

107107
[case testKeywordMisspellingFloatInt]
108108
def f(atter: float, btter: int) -> None: pass # N: "f" defined here
109109
x: int = 5
110-
f(otter=x) # E: Unexpected keyword argument "otter" for "f"; did you mean "btter" or "atter"?
110+
f(otter=x) # E: Unexpected keyword argument "otter" for "f"; did you mean "atter" or "btter"?
111111

112112
[case testKeywordMisspellingVarArgs]
113113
def f(other: 'A', *atter: 'A') -> None: pass # N: "f" defined here

‎test-data/unit/check-modules.test‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2871,7 +2871,7 @@ aaaaa: int
28712871

28722872
[case testModuleAttributeThreeSuggestions]
28732873
import m
2874-
m.aaaaa # E: Module has no attribute "aaaaa"; maybe "aabaa", "aaaba", or "aaaab"?
2874+
m.aaaaa # E: Module has no attribute "aaaaa"; maybe "aaaab", "aaaba", or "aabaa"?
28752875

28762876
[file m.py]
28772877
aaaab: int

‎test-data/unit/semanal-modules.test‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -814,7 +814,7 @@ def somef_unction():
814814
[file f.py]
815815
from m.x import somefunction
816816
[out]
817-
tmp/f.py:1: error: Module "m.x" has no attribute "somefunction"; maybe "somef_unction" or "some_function"?
817+
tmp/f.py:1: error: Module "m.x" has no attribute "somefunction"; maybe "some_function" or "somef_unction"?
818818

819819
[case testImportMisspellingMultipleCandidatesTruncated]
820820
import f
@@ -831,7 +831,7 @@ def somefun_ction():
831831
[file f.py]
832832
from m.x import somefunction
833833
[out]
834-
tmp/f.py:1: error: Module "m.x" has no attribute "somefunction"; maybe "somefun_ction", "somefu_nction", or "somef_unction"?
834+
tmp/f.py:1: error: Module "m.x" has no attribute "somefunction"; maybe "some_function", "somef_unction", or "somefu_nction"?
835835

836836
[case testFromImportAsInStub]
837837
from m import *

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp