From 685253d166d4252f9c37b042eb7f8d432e579f2f Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Fri, 22 Mar 2019 12:44:00 -0700 Subject: [PATCH] implement @no_type_check decorator for class defs --- mypy/checkmember.py | 3 +++ mypy/nodes.py | 1 + mypy/semanal.py | 11 +++++++++++ mypy/semanal_pass3.py | 2 ++ 4 files changed, 17 insertions(+) diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 2117194e7fba..c0508cce9f33 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -162,6 +162,9 @@ def analyze_instance_member_access(name: str, if override_info: info = override_info + if info.is_no_type_check: + return AnyType(TypeOfAny.special_form) + if (state.find_occurrences and info.name() == state.find_occurrences[0] and name == state.find_occurrences[1]): diff --git a/mypy/nodes.py b/mypy/nodes.py index fc4312f6353f..880cb9d36710 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -2219,6 +2219,7 @@ class is generic then it will be a type constructor of higher kind. metaclass_type = None # type: Optional[mypy.types.Instance] names = None # type: SymbolTable # Names defined directly in this type + is_no_type_check = False # Was the class annotated with @no_type_check? is_abstract = False # Does the class have any abstract attributes? is_protocol = False # Is this a protocol class? runtime_protocol = False # Does this protocol support isinstance checks? diff --git a/mypy/semanal.py b/mypy/semanal.py index 7f1f32fc96ff..84796c632a94 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -487,6 +487,9 @@ def prepare_method_signature(self, func: FuncDef, info: TypeInfo) -> None: """Check basic signature validity and tweak annotation of self/cls argument.""" # Only non-static methods are special. functype = func.type + if info.is_no_type_check: + func.type = AnyType(TypeOfAny.special_form) + return if not func.is_static: if not func.arguments: self.fail('Method must have at least one argument', func) @@ -807,6 +810,14 @@ def visit_class_def(self, defn: ClassDef) -> None: self.analyze_class(defn) def analyze_class(self, defn: ClassDef) -> None: + if defn.decorators: + for decorator in reversed(defn.decorators): + if isinstance(decorator, NameExpr) and \ + decorator.name in ('no_type_check', 'typing.no_type_check'): + defn.info.is_no_type_check = True + defn.info.fallback_to_any = True + return + is_protocol = self.detect_protocol_base(defn) self.update_metaclass(defn) self.clean_up_bases_and_infer_type_variables(defn) diff --git a/mypy/semanal_pass3.py b/mypy/semanal_pass3.py index 835d61564ead..c8c2ab9e9fb2 100644 --- a/mypy/semanal_pass3.py +++ b/mypy/semanal_pass3.py @@ -161,6 +161,8 @@ def visit_overloaded_func_def(self, fdef: OverloadedFuncDef) -> None: super().visit_overloaded_func_def(fdef) def visit_class_def(self, tdef: ClassDef) -> None: + if tdef.info.is_no_type_check: + return # NamedTuple base classes are validated in check_namedtuple_classdef; we don't have to # check them again here. self.scope.enter_class(tdef.info)