Repository: python/mypy

Issue:
Setting `disallow_any = generics` in mypy.ini breaks `disallow_untyped_defs = True`
I have the following code (`rpc_server.py`):
```
def get_tasks(self):
    return 'whatever'
```
And `mypy.ini`:
```
[mypy]
disallow_untyped_defs = True
disallow_any = generics
```
I would expect to get an error because `get_tasks` is missing an argument annotation and a return type annotation.

However, `mypy --config-file /path/to/mypy.ini /path/to/rpc_server.py` gives no errors. When I remove `disallow_any = generics`, I get the expected error. I also get the expected error if I simply do `mypy --disallow-untyped-defs --disallow-any=generics`—somehow it makes a difference that I use a config file.


Discussion:

Resolving patch:
diff --git a/mypy/main.py b/mypy/main.py
--- a/mypy/main.py
+++ b/mypy/main.py
@@ -750,7 +750,13 @@ def parse_section(prefix: str, template: Options,
             print("%s: %s: %s" % (prefix, key, err), file=sys.stderr)
             continue
         if key == 'disallow_any':
-            results['disallow_untyped_defs'] = v and 'unannotated' in v
+            # "disallow_any = " should disable all disallow_any options, including untyped defs,
+            # given in a more general config.
+            if not v:
+                results['disallow_untyped_defs'] = False
+            # If "unannotated" is explicitly given, turn on disallow_untyped_defs.
+            elif 'unannotated' in v:
+                results['disallow_untyped_defs'] = True
         if key == 'silent_imports':
             print("%s: silent_imports has been replaced by "
                   "ignore_missing_imports=True; follow_imports=skip" % prefix, file=sys.stderr)
diff --git a/mypy/types.py b/mypy/types.py
--- a/mypy/types.py
+++ b/mypy/types.py
@@ -1411,7 +1411,7 @@ def resolve(self, resolved: Type) -> None:
     def accept(self, visitor: 'TypeVisitor[T]') -> T:
         return visitor.visit_forwardref_type(self)
 
-    def serialize(self):
+    def serialize(self) -> str:
         name = self.unbound.name
         # We should never get here since all forward references should be resolved
         # and removed during semantic analysis.


Test patch:
diff --git a/mypy/test/testcmdline.py b/mypy/test/testcmdline.py
--- a/mypy/test/testcmdline.py
+++ b/mypy/test/testcmdline.py
@@ -41,7 +41,7 @@ def cases(cls) -> List[DataDrivenTestCase]:
                                   native_sep=True)
         return c
 
-    def run_case(self, testcase: DataDrivenTestCase):
+    def run_case(self, testcase: DataDrivenTestCase) -> None:
         test_python_evaluation(testcase)
 
 
diff --git a/mypy/test/testpythoneval.py b/mypy/test/testpythoneval.py
--- a/mypy/test/testpythoneval.py
+++ b/mypy/test/testpythoneval.py
@@ -49,7 +49,7 @@ def cases(cls) -> List[DataDrivenTestCase]:
                     test_python_evaluation, test_temp_dir, True)
         return c
 
-    def run_case(self, testcase: DataDrivenTestCase):
+    def run_case(self, testcase: DataDrivenTestCase) -> None:
         test_python_evaluation(testcase)
 
 
diff --git a/test-data/unit/cmdline.test b/test-data/unit/cmdline.test
--- a/test-data/unit/cmdline.test
+++ b/test-data/unit/cmdline.test
@@ -1078,3 +1078,15 @@ ignore_errors = True
 ignore_errors = False
 [out]
 a/b/c/d/e/__init__.py:1: error: "int" not callable
+
+[case testDisallowUntypedDefsAndGenerics]
+# cmd: mypy a.py
+[file mypy.ini]
+[[mypy]
+disallow_untyped_defs = True
+disallow_any = generics
+[file a.py]
+def get_tasks(self):
+    return 'whatever'
+[out]
+a.py:1: error: Function is missing a type annotation