From c70eef5293e158a55b84465bb00ca9a393e23b50 Mon Sep 17 00:00:00 2001 From: Rafael Caricio Date: Tue, 7 May 2019 11:37:22 -0400 Subject: [PATCH 1/2] Skip error if attr is private to class definition --- mypy/checker.py | 11 +++++++++++ test-data/unit/check-classes.test | 22 ++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/mypy/checker.py b/mypy/checker.py index 2af33533a25f..1758b1d042ce 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -1504,6 +1504,9 @@ def check_override(self, override: FunctionLike, original: FunctionLike, if original_class_or_static and not override_class_or_static: fail = True + if is_private(name): + fail = False + if fail: emitted_msg = False if (isinstance(override, CallableType) and @@ -1940,6 +1943,9 @@ def check_compatibility_all_supers(self, lvalue: RefExpr, lvalue_type: Optional[ if lvalue_node.name() == "__slots__" and base.fullname() != "builtins.object": continue + if is_private(lvalue_node.name()): + continue + base_type, base_node = self.lvalue_type_from_base(lvalue_node, base) if base_type: @@ -4396,3 +4402,8 @@ def is_subtype_no_promote(left: Type, right: Type) -> bool: def is_overlapping_types_no_promote(left: Type, right: Type) -> bool: return is_overlapping_types(left, right, ignore_promotions=True) + + +def is_private(node_name: str) -> bool: + """Check if node is private to class definition.""" + return node_name.startswith('__') and not node_name.endswith('__') diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index f40373c30211..cc9fa9ffc0d9 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -5899,3 +5899,25 @@ class A: class B: @dec # E: Unsupported decorated constructor type def __new__(cls, x: int) -> B: ... + +[case testIgnorePrivateAttributesTypeCheck] +class B: + __foo_: int +class C(B): + __foo_: str +[out] + +[case testIgnorePrivateMethodsTypeCheck] +class B: + def __foo_(self) -> int: ... +class C(B): + def __foo_(self) -> str: ... +[out] + +[case testCheckForPrivateMethodsWhenPublicCheck] +class B: + __foo__: int +class C(B): + __foo__: str +[out] +main:4: error: Incompatible types in assignment (expression has type "str", base class "B" defined the type as "int") From a3b2dbd0098ef62a361a527013d73570cd23328e Mon Sep 17 00:00:00 2001 From: Rafael Caricio Date: Tue, 7 May 2019 13:35:04 -0400 Subject: [PATCH 2/2] Cover one more scenario for transitive class attrs --- mypy/checker.py | 2 ++ test-data/unit/check-classes.test | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/mypy/checker.py b/mypy/checker.py index 1758b1d042ce..f48be72c1d3d 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -1652,6 +1652,8 @@ def check_multiple_inheritance(self, typ: TypeInfo) -> None: # Normal checks for attribute compatibility should catch any problems elsewhere. non_overridden_attrs = base.names.keys() - typ.names.keys() for name in non_overridden_attrs: + if is_private(name): + continue for base2 in mro[i + 1:]: # We only need to check compatibility of attributes from classes not # in a subclass relationship. For subclasses, normal (single inheritance) diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index cc9fa9ffc0d9..80a52857980d 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -5921,3 +5921,12 @@ class C(B): __foo__: str [out] main:4: error: Incompatible types in assignment (expression has type "str", base class "B" defined the type as "int") + +[case testIgnorePrivateMethodsTypeCheck] +class A: + def __foo_(self) -> int: ... +class B: + def __foo_(self) -> str: ... + +class C(A, B): pass +[out]