Automatically generate type annotations

To generate annotations with MonkeyType and PyAnnotate for eg. for module paper_clip — replace paper_clip with your module:

Find out what type are used

Use test run to find out what types are actually used

pip install pytest-monkeytype
pytest --monkeytype-output=./monkeytype.sqlite3 paper_clip
monkeytype list-modules | grep paper_clip | grep -v tests | xargs -n 1 monkeytype -v apply

Fill out missing annotations with Any

Supplement all the missing types with Any. Using Any is not preferable and should not be your final solution. But! It is better to have all type annotation present and be strict about requiring annotations to be present everywhere once you have supplemented them. If you rely on humans to point out missing annotations or worse rely on warnings which are basically noise that everybody ignores — you will fail in having type annotations added on new code.

In my opinion it’s better to have loose type requirements and improve them with every code change/review. It’s better to miss an opportunity to improve type cheeking than allow code without any type annotation at all.

pip install pyannotate
find paper_clip -type f -name "*.py" ! -path "*/tests*" ! -path "*/migrations*" |xargs -n 1 pyannotate --auto-any --py3 -w

Django support

The above requires a config file, you can apply the path below on your working copy:

Index: monkeytype_config.py
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/monkeytype_config.py b/monkeytype_config.py
new file mode 100644
--- /dev/null	(date 1664189881231)
+++ b/monkeytype_config.py	(date 1664189881231)
@@ -0,0 +1,18 @@
+import os
+from contextlib import contextmanager
+from typing import Iterator
+
+from monkeytype.config import DefaultConfig
+
+
+class MyConfig(DefaultConfig):
+    @contextmanager
+    def cli_context(self, command: str) -> Iterator[None]:
+        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "website.settings.development")
+        import django
+
+        django.setup()
+        yield
+
+
+CONFIG = MyConfig()


Further reading

  1. Tests aren’t enough: Case study after adding type hints to urllib3

Leave a Reply

Back to Top