Skip to content

Commit f741645

Browse files
authored
Merge branch 'master' into fix_strict_quality_in_loops
2 parents 4e474cb + eb49662 commit f741645

File tree

106 files changed

+6988
-196
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

106 files changed

+6988
-196
lines changed

LICENSE

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,3 +227,38 @@ FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
227227
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
228228
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
229229
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
230+
231+
= = = = =
232+
233+
Files under lib-rt/base64 are licensed under the following license.
234+
235+
= = = = =
236+
237+
Copyright (c) 2005-2007, Nick Galbreath
238+
Copyright (c) 2015-2018, Wojciech Muła
239+
Copyright (c) 2016-2017, Matthieu Darbois
240+
Copyright (c) 2013-2022, Alfred Klomp
241+
All rights reserved.
242+
243+
Redistribution and use in source and binary forms, with or without
244+
modification, are permitted provided that the following conditions are
245+
met:
246+
247+
- Redistributions of source code must retain the above copyright notice,
248+
this list of conditions and the following disclaimer.
249+
250+
- Redistributions in binary form must reproduce the above copyright
251+
notice, this list of conditions and the following disclaimer in the
252+
documentation and/or other materials provided with the distribution.
253+
254+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
255+
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
256+
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
257+
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
258+
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
259+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
260+
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
261+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
262+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
263+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
264+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

mypy-requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ typing_extensions>=4.6.0
44
mypy_extensions>=1.0.0
55
pathspec>=0.9.0
66
tomli>=1.1.0; python_version<'3.11'
7-
librt>=0.6.0
7+
librt>=0.6.2

mypy/checker.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3424,7 +3424,11 @@ def check_assignment(
34243424
and lvalue_type is not None
34253425
):
34263426
lvalue.node.type = remove_instance_last_known_values(lvalue_type)
3427-
elif self.options.allow_redefinition_new and lvalue_type is not None:
3427+
elif (
3428+
self.options.allow_redefinition_new
3429+
and lvalue_type is not None
3430+
and not isinstance(lvalue_type, PartialType)
3431+
):
34283432
# TODO: Can we use put() here?
34293433
self.binder.assign_type(lvalue, lvalue_type, lvalue_type)
34303434

mypy/nodes.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3732,12 +3732,18 @@ def get_method(self, name: str) -> FuncBase | Decorator | None:
37323732
for cls in self.mro:
37333733
if name in cls.names:
37343734
node = cls.names[name].node
3735-
if isinstance(node, SYMBOL_FUNCBASE_TYPES):
3736-
return node
3737-
elif isinstance(node, Decorator): # Two `if`s make `mypyc` happy
3738-
return node
3739-
else:
3740-
return None
3735+
elif possible_redefinitions := sorted(
3736+
[n for n in cls.names.keys() if n.startswith(f"{name}-redefinition")]
3737+
):
3738+
node = cls.names[possible_redefinitions[-1]].node
3739+
else:
3740+
continue
3741+
if isinstance(node, SYMBOL_FUNCBASE_TYPES):
3742+
return node
3743+
elif isinstance(node, Decorator): # Two `if`s make `mypyc` happy
3744+
return node
3745+
else:
3746+
return None
37413747
return None
37423748

37433749
def calculate_metaclass_type(self) -> mypy.types.Instance | None:

mypy/partially_defined.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,11 +206,13 @@ def __init__(self) -> None:
206206
# disable_branch_skip is used to disable skipping a branch due to a return/raise/etc. This is useful
207207
# in things like try/except/finally statements.
208208
self.disable_branch_skip = False
209+
self.in_finally = False
209210

210211
def copy(self) -> DefinedVariableTracker:
211212
result = DefinedVariableTracker()
212213
result.scopes = [s.copy() for s in self.scopes]
213214
result.disable_branch_skip = self.disable_branch_skip
215+
result.in_finally = self.in_finally
214216
return result
215217

216218
def _scope(self) -> Scope:
@@ -579,7 +581,9 @@ def process_try_stmt(self, o: TryStmt) -> None:
579581
self.tracker.end_branch_statement()
580582

581583
if o.finally_body is not None:
584+
self.tracker.in_finally = True
582585
o.finally_body.accept(self)
586+
self.tracker.in_finally = False
583587

584588
def visit_while_stmt(self, o: WhileStmt) -> None:
585589
o.expr.accept(self)
@@ -620,7 +624,10 @@ def visit_starred_pattern(self, o: StarredPattern) -> None:
620624
def visit_name_expr(self, o: NameExpr) -> None:
621625
if o.name in self.builtins and self.tracker.in_scope(ScopeType.Global):
622626
return
623-
if self.tracker.is_possibly_undefined(o.name):
627+
if (
628+
self.tracker.is_possibly_undefined(o.name)
629+
and self.tracker.in_finally == self.tracker.disable_branch_skip
630+
):
624631
# A variable is only defined in some branches.
625632
self.variable_may_be_undefined(o.name, o)
626633
# We don't want to report the error on the same variable multiple times.

mypy/semanal.py

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2269,11 +2269,17 @@ class Foo(Bar, Generic[T]): ...
22692269
removed: list[int] = []
22702270
declared_tvars: TypeVarLikeList = []
22712271
is_protocol = False
2272+
has_type_var_tuple = False
22722273
if defn.type_args is not None:
22732274
for p in defn.type_args:
22742275
node = self.lookup(p.name, context)
22752276
assert node is not None
22762277
assert isinstance(node.node, TypeVarLikeExpr)
2278+
if isinstance(node.node, TypeVarTupleExpr):
2279+
if has_type_var_tuple:
2280+
self.fail("Can only use one type var tuple in a class def", context)
2281+
continue
2282+
has_type_var_tuple = True
22772283
declared_tvars.append((p.name, node.node))
22782284

22792285
for i, base_expr in enumerate(base_type_exprs):
@@ -2286,7 +2292,7 @@ class Foo(Bar, Generic[T]): ...
22862292
except TypeTranslationError:
22872293
# This error will be caught later.
22882294
continue
2289-
result = self.analyze_class_typevar_declaration(base)
2295+
result = self.analyze_class_typevar_declaration(base, has_type_var_tuple)
22902296
if result is not None:
22912297
tvars = result[0]
22922298
is_protocol |= result[1]
@@ -2340,7 +2346,9 @@ class Foo(Bar, Generic[T]): ...
23402346
tvar_defs = self.tvar_defs_from_tvars(declared_tvars, context)
23412347
return base_type_exprs, tvar_defs, is_protocol
23422348

2343-
def analyze_class_typevar_declaration(self, base: Type) -> tuple[TypeVarLikeList, bool] | None:
2349+
def analyze_class_typevar_declaration(
2350+
self, base: Type, has_type_var_tuple: bool
2351+
) -> tuple[TypeVarLikeList, bool] | None:
23442352
"""Analyze type variables declared using Generic[...] or Protocol[...].
23452353
23462354
Args:
@@ -2362,16 +2370,15 @@ def analyze_class_typevar_declaration(self, base: Type) -> tuple[TypeVarLikeList
23622370
):
23632371
is_proto = sym.node.fullname != "typing.Generic"
23642372
tvars: TypeVarLikeList = []
2365-
have_type_var_tuple = False
23662373
for arg in unbound.args:
23672374
tag = self.track_incomplete_refs()
23682375
tvar = self.analyze_unbound_tvar(arg)
23692376
if tvar:
23702377
if isinstance(tvar[1], TypeVarTupleExpr):
2371-
if have_type_var_tuple:
2378+
if has_type_var_tuple:
23722379
self.fail("Can only use one type var tuple in a class def", base)
23732380
continue
2374-
have_type_var_tuple = True
2381+
has_type_var_tuple = True
23752382
tvars.append(tvar)
23762383
elif not self.found_incomplete_ref(tag):
23772384
self.fail("Free type variable expected in %s[...]" % sym.node.name, base)
@@ -2455,7 +2462,7 @@ def tvar_defs_from_tvars(
24552462
self.fail(
24562463
message_registry.TYPE_VAR_REDECLARED_IN_NESTED_CLASS.format(name), context
24572464
)
2458-
tvar_def = self.tvar_scope.bind_new(name, tvar_expr)
2465+
tvar_def = self.tvar_scope.bind_new(name, tvar_expr, self.fail, context)
24592466
if last_tvar_name_with_default is not None and not tvar_def.has_default():
24602467
self.msg.tvar_without_default_type(
24612468
tvar_def.name, last_tvar_name_with_default, context
@@ -2473,19 +2480,18 @@ def get_and_bind_all_tvars(self, type_exprs: list[Expression]) -> list[TypeVarLi
24732480
a simplified version of the logic we use for ClassDef bases. We duplicate
24742481
some amount of code, because it is hard to refactor common pieces.
24752482
"""
2476-
tvars = []
2483+
tvars: dict[str, tuple[TypeVarLikeExpr, Expression]] = {}
24772484
for base_expr in type_exprs:
24782485
try:
24792486
base = self.expr_to_unanalyzed_type(base_expr)
24802487
except TypeTranslationError:
24812488
# This error will be caught later.
24822489
continue
2483-
base_tvars = self.find_type_var_likes(base)
2484-
tvars.extend(base_tvars)
2485-
tvars = remove_dups(tvars) # Variables are defined in order of textual appearance.
2490+
for name, expr in self.find_type_var_likes(base):
2491+
tvars.setdefault(name, (expr, base_expr))
24862492
tvar_defs = []
2487-
for name, tvar_expr in tvars:
2488-
tvar_def = self.tvar_scope.bind_new(name, tvar_expr)
2493+
for name, (tvar_expr, context) in tvars.items():
2494+
tvar_def = self.tvar_scope.bind_new(name, tvar_expr, self.fail, context)
24892495
tvar_defs.append(tvar_def)
24902496
return tvar_defs
24912497

@@ -6505,7 +6511,9 @@ def _lookup(
65056511
implicit_node = node
65066512
# 2b. Class attributes __qualname__ and __module__
65076513
if self.type and not self.is_func_scope() and name in {"__qualname__", "__module__"}:
6508-
return SymbolTableNode(MDEF, Var(name, self.str_type()))
6514+
v = Var(name, self.str_type())
6515+
v._fullname = self.qualified_name(name)
6516+
return SymbolTableNode(MDEF, v)
65096517
# 3. Local (function) scopes
65106518
for table in reversed(self.locals):
65116519
if table is not None and name in table:
@@ -7022,7 +7030,12 @@ def add_symbol_table_node(
70227030
if not is_same_symbol(old, new):
70237031
if isinstance(new, (FuncDef, Decorator, OverloadedFuncDef, TypeInfo)):
70247032
self.add_redefinition(names, name, symbol)
7025-
if not (isinstance(new, (FuncDef, Decorator)) and self.set_original_def(old, new)):
7033+
if isinstance(old, Var) and is_init_only(old):
7034+
if old.has_explicit_value:
7035+
self.fail("InitVar with default value cannot be redefined", context)
7036+
elif not (
7037+
isinstance(new, (FuncDef, Decorator)) and self.set_original_def(old, new)
7038+
):
70267039
self.name_already_defined(name, context, existing)
70277040
elif type_param or (
70287041
name not in self.missing_names[-1] and "*" not in self.missing_names[-1]
@@ -8271,3 +8284,10 @@ def halt(self, reason: str = ...) -> NoReturn:
82718284
return isinstance(stmt, PassStmt) or (
82728285
isinstance(stmt, ExpressionStmt) and isinstance(stmt.expr, EllipsisExpr)
82738286
)
8287+
8288+
8289+
def is_init_only(node: Var) -> bool:
8290+
return (
8291+
isinstance(type := get_proper_type(node.type), Instance)
8292+
and type.type.fullname == "dataclasses.InitVar"
8293+
)

mypy/server/update.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,8 @@ def restore(ids: list[str]) -> None:
631631

632632
# Find any other modules brought in by imports.
633633
changed_modules = [(st.id, st.xpath) for st in new_modules]
634+
for m in new_modules:
635+
manager.import_map[m.id] = set(m.dependencies + m.suppressed)
634636

635637
# If there are multiple modules to process, only process one of them and return
636638
# the remaining ones to the caller.

mypy/stubdoc.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,19 @@ def add_token(self, token: tokenize.TokenInfo) -> None:
233233
self.accumulator = ""
234234
self.state.append(STATE_ARGUMENT_TYPE)
235235

236+
elif (
237+
token.type == tokenize.OP
238+
and token.string == ":"
239+
and self.state[-1] == STATE_ARGUMENT_TYPE
240+
and self.accumulator == ""
241+
):
242+
# We thought we were after the colon of an "arg_name: arg_type"
243+
# stanza, so we were expecting an "arg_type" now. However, we ended
244+
# up with "arg_name::" (with two colons). That's a C++ type name,
245+
# not an argument name followed by a Python type. This function
246+
# signature is malformed / invalid.
247+
self.reset()
248+
236249
elif (
237250
token.type == tokenize.OP
238251
and token.string == "="

mypy/test/teststubgen.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,8 @@ def test_infer_sig_from_docstring(self) -> None:
371371
[FunctionSig(name="func", args=[ArgSig(name="x", type=None)], ret_type="Any")],
372372
)
373373

374+
assert_equal(infer_sig_from_docstring("\nfunc(invalid::type)", "func"), [])
375+
374376
assert_equal(
375377
infer_sig_from_docstring('\nfunc(x: str="")', "func"),
376378
[

0 commit comments

Comments
 (0)