Browse Source

Enable type checking.

Jelmer Vernooij 4 years ago
parent
commit
2f933bd334

+ 1 - 0
.travis.yml

@@ -43,6 +43,7 @@ script:
 
   # Style
   - make style
+  - make typing
 
   - if [ $PURE = true ]; then SETUP_ARGS=--pure; fi
   - python setup.py $SETUP_ARGS bdist_wheel

+ 3 - 0
Makefile

@@ -43,6 +43,9 @@ check-noextensions:: clean
 
 check-all: check check-pypy check-noextensions
 
+typing:
+	mypy dulwich
+
 clean::
 	$(SETUP) clean --all
 	rm -f dulwich/*.so

+ 5 - 1
dulwich/diff_tree.py

@@ -618,6 +618,10 @@ _merge_entries_py = _merge_entries
 _count_blocks_py = _count_blocks
 try:
     # Try to import C versions
-    from dulwich._diff_tree import _is_tree, _merge_entries, _count_blocks
+    from dulwich._diff_tree import (  # type: ignore
+        _is_tree,
+        _merge_entries,
+        _count_blocks,
+        )
 except ImportError:
     pass

+ 13 - 4
dulwich/objects.py

@@ -27,6 +27,12 @@ from collections import namedtuple
 import os
 import posixpath
 import stat
+from typing import (
+    Optional,
+    Dict,
+    Union,
+    Type,
+    )
 import warnings
 import zlib
 from hashlib import sha1
@@ -146,13 +152,13 @@ def filename_to_hex(filename):
     return hex
 
 
-def object_header(num_type, length):
+def object_header(num_type: int, length: int) -> bytes:
     """Return an object header for the given numeric type and text length."""
     return (object_class(num_type).type_name +
             b' ' + str(length).encode('ascii') + b'\0')
 
 
-def serializable_property(name, docstring=None):
+def serializable_property(name: str, docstring:Optional[str]=None):
     """A property that helps tracking whether serialization is necessary.
     """
     def set(obj, value):
@@ -253,6 +259,9 @@ class ShaFile(object):
 
     __slots__ = ('_chunked_text', '_sha', '_needs_serialization')
 
+    type_name:bytes
+    type_num:int
+
     @staticmethod
     def _parse_legacy_object_header(magic, f):
         """Parse a legacy object, creating it but not reading the file."""
@@ -1417,7 +1426,7 @@ OBJECT_CLASSES = (
     Tag,
     )
 
-_TYPE_MAP = {}
+_TYPE_MAP:Dict[Union[bytes,int],Type[ShaFile]] = {}
 
 for cls in OBJECT_CLASSES:
     _TYPE_MAP[cls.type_name] = cls
@@ -1429,6 +1438,6 @@ _parse_tree_py = parse_tree
 _sorted_tree_items_py = sorted_tree_items
 try:
     # Try to import C versions
-    from dulwich._objects import parse_tree, sorted_tree_items
+    from dulwich._objects import parse_tree, sorted_tree_items  # type: ignore
 except ImportError:
     pass

+ 8 - 11
dulwich/pack.py

@@ -43,12 +43,6 @@ import difflib
 import struct
 
 from itertools import chain
-try:
-    from itertools import imap, izip
-except ImportError:
-    # Python3
-    imap = map
-    izip = zip
 
 import os
 import sys
@@ -363,8 +357,8 @@ class PackIndex(object):
         if not isinstance(other, PackIndex):
             return False
 
-        for (name1, _, _), (name2, _, _) in izip(self.iterentries(),
-                                                 other.iterentries()):
+        for (name1, _, _), (name2, _, _) in zip(self.iterentries(),
+                                                other.iterentries()):
             if name1 != name2:
                 return False
         return True
@@ -378,7 +372,7 @@ class PackIndex(object):
 
     def __iter__(self):
         """Iterate over the SHAs in this pack."""
-        return imap(sha_to_hex, self._itersha())
+        return map(sha_to_hex, self._itersha())
 
     def iterentries(self):
         """Iterate over the entries in this pack index.
@@ -710,7 +704,7 @@ def chunks_length(chunks):
     if isinstance(chunks, bytes):
         return len(chunks)
     else:
-        return sum(imap(len, chunks))
+        return sum(map(len, chunks))
 
 
 def unpack_object(read_all, read_some=None, compute_crc32=False,
@@ -2094,6 +2088,9 @@ class Pack(object):
 
 
 try:
-    from dulwich._pack import apply_delta, bisect_find_sha  # noqa: F811
+    from dulwich._pack import (  # type: ignore # noqa: F811
+        apply_delta,
+        bisect_find_sha,
+        )
 except ImportError:
     pass

+ 2 - 1
dulwich/tests/compat/test_web.py

@@ -28,6 +28,7 @@ warning: these tests should be fairly stable, but when writing/debugging new
 import threading
 from wsgiref import simple_server
 import sys
+from typing import Tuple
 
 from dulwich.server import (
     DictBackend,
@@ -87,7 +88,7 @@ class SmartWebTestCase(WebTests, CompatTestCase):
     This server test case does not use side-band-64k in git-receive-pack.
     """
 
-    min_git_version = (1, 6, 6)
+    min_git_version:Tuple[int, ...] = (1, 6, 6)
 
     def _handlers(self):
         return {b'git-receive-pack': NoSideBand64kReceivePackHandler}

+ 2 - 1
dulwich/tests/compat/utils.py

@@ -30,6 +30,7 @@ import subprocess
 import sys
 import tempfile
 import time
+from typing import Tuple
 
 from dulwich.repo import Repo
 from dulwich.protocol import TCP_GIT_PORT
@@ -215,7 +216,7 @@ class CompatTestCase(TestCase):
     min_git_version.
     """
 
-    min_git_version = (1, 5, 0)
+    min_git_version:Tuple[int, ...] = (1, 5, 0)
 
     def setUp(self):
         super(CompatTestCase, self).setUp()

+ 1 - 1
dulwich/tests/test_archive.py

@@ -43,7 +43,7 @@ from dulwich.tests.utils import (
 try:
     from mock import patch
 except ImportError:
-    patch = None
+    patch = None   # type: ignore
 
 
 class ArchiveTests(TestCase):

+ 2 - 1
dulwich/tests/test_web.py

@@ -24,6 +24,7 @@ from io import BytesIO
 import gzip
 import re
 import os
+from typing import Type
 
 from dulwich.object_store import (
     MemoryObjectStore,
@@ -107,7 +108,7 @@ class TestHTTPGitRequest(HTTPGitRequest):
 class WebTestCase(TestCase):
     """Base TestCase with useful instance vars and utility functions."""
 
-    _req_class = TestHTTPGitRequest
+    _req_class:Type[HTTPGitRequest] = TestHTTPGitRequest
 
     def setUp(self):
         super(WebTestCase, self).setUp()

+ 3 - 0
setup.cfg

@@ -1,2 +1,5 @@
 [flake8]
 exclude = build,.git,build-pypy,.tox
+
+[mypy]
+ignore_missing_imports = True