diff options
-rw-r--r-- | .github/workflows/pythonpackage.yml | 5 | ||||
-rw-r--r-- | MANIFEST.in | 7 | ||||
-rw-r--r-- | git/cmd.py | 2 | ||||
-rw-r--r-- | git/compat.py | 30 | ||||
-rw-r--r-- | git/config.py | 2 | ||||
-rw-r--r-- | git/exc.py | 1 | ||||
-rw-r--r-- | git/objects/__init__.py | 4 | ||||
-rw-r--r-- | git/objects/base.py | 3 | ||||
-rw-r--r-- | git/refs/reference.py | 4 | ||||
-rw-r--r-- | mypy.ini | 7 | ||||
-rw-r--r-- | tox.ini | 8 |
11 files changed, 60 insertions, 13 deletions
diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index eb5c894e..3c7215cb 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -47,6 +47,11 @@ jobs: pip install flake8 # stop the build if there are Python syntax errors or undefined names flake8 --ignore=W293,E265,E266,W503,W504,E731 --count --show-source --statistics + - name: Check types with mypy + run: | + set -x + pip install tox + tox -e type - name: Test with nose run: | set -x diff --git a/MANIFEST.in b/MANIFEST.in index 5fd771db..f02721fc 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,10 +1,11 @@ -include VERSION -include LICENSE -include CHANGES include AUTHORS +include CHANGES include CONTRIBUTING.md +include LICENSE include README.md +include VERSION include requirements.txt +include test-requirements.txt recursive-include doc * recursive-exclude test * @@ -138,7 +138,7 @@ CREATE_NO_WINDOW = 0x08000000 ## CREATE_NEW_PROCESS_GROUP is needed to allow killing it afterwards, # see https://docs.python.org/3/library/subprocess.html#subprocess.Popen.send_signal -PROC_CREATIONFLAGS = (CREATE_NO_WINDOW | subprocess.CREATE_NEW_PROCESS_GROUP +PROC_CREATIONFLAGS = (CREATE_NO_WINDOW | subprocess.CREATE_NEW_PROCESS_GROUP # type: ignore[attr-defined] if is_win else 0) diff --git a/git/compat.py b/git/compat.py index c9b83ba4..c4bd2aa3 100644 --- a/git/compat.py +++ b/git/compat.py @@ -18,7 +18,16 @@ from gitdb.utils.encoding import ( # typing -------------------------------------------------------------------- -from typing import IO, Any, AnyStr, Dict, Optional, Type, Union +from typing import ( + Any, + AnyStr, + Dict, + IO, + Optional, + Type, + Union, + overload, +) from git.types import TBD # --------------------------------------------------------------------------- @@ -30,6 +39,12 @@ is_darwin = (os.name == 'darwin') defenc = sys.getfilesystemencoding() +@overload +def safe_decode(s: None) -> None: ... + +@overload +def safe_decode(s: Union[IO[str], AnyStr]) -> str: ... + def safe_decode(s: Union[IO[str], AnyStr, None]) -> Optional[str]: """Safely decodes a binary string to unicode""" if isinstance(s, str): @@ -42,6 +57,12 @@ def safe_decode(s: Union[IO[str], AnyStr, None]) -> Optional[str]: raise TypeError('Expected bytes or text, but got %r' % (s,)) +@overload +def safe_encode(s: None) -> None: ... + +@overload +def safe_encode(s: AnyStr) -> bytes: ... + def safe_encode(s: Optional[AnyStr]) -> Optional[bytes]: """Safely encodes a binary string to unicode""" if isinstance(s, str): @@ -54,6 +75,12 @@ def safe_encode(s: Optional[AnyStr]) -> Optional[bytes]: raise TypeError('Expected bytes or text, but got %r' % (s,)) +@overload +def win_encode(s: None) -> None: ... + +@overload +def win_encode(s: AnyStr) -> bytes: ... + def win_encode(s: Optional[AnyStr]) -> Optional[bytes]: """Encode unicodes for process arguments on Windows.""" if isinstance(s, str): @@ -65,7 +92,6 @@ def win_encode(s: Optional[AnyStr]) -> Optional[bytes]: return None - def with_metaclass(meta: Type[Any], *bases: Any) -> 'metaclass': # type: ignore ## mypy cannot understand dynamic class creation """copied from https://github.com/Byron/bcore/blob/master/src/python/butility/future.py#L15""" diff --git a/git/config.py b/git/config.py index aadb0aac..1cb80475 100644 --- a/git/config.py +++ b/git/config.py @@ -216,7 +216,7 @@ def get_config_path(config_level: Literal['system', 'global', 'user', 'repositor raise ValueError("Invalid configuration level: %r" % config_level) -class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, object)): +class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, object)): # type: ignore ## mypy does not understand dynamic class creation # noqa: E501 """Implements specifics required to read git style configuration files. @@ -5,6 +5,7 @@ # the BSD License: http://www.opensource.org/licenses/bsd-license.php """ Module containing all exceptions thrown throughout the git package, """ +from gitdb.exc import BadName # NOQA @UnusedWildImport skipcq: PYL-W0401, PYL-W0614 from gitdb.exc import * # NOQA @UnusedWildImport skipcq: PYL-W0401, PYL-W0614 from git.compat import safe_decode diff --git a/git/objects/__init__.py b/git/objects/__init__.py index 23b2416a..897eb98f 100644 --- a/git/objects/__init__.py +++ b/git/objects/__init__.py @@ -16,8 +16,8 @@ from .tag import * from .tree import * # Fix import dependency - add IndexObject to the util module, so that it can be # imported by the submodule.base -smutil.IndexObject = IndexObject -smutil.Object = Object +smutil.IndexObject = IndexObject # type: ignore[attr-defined] +smutil.Object = Object # type: ignore[attr-defined] del(smutil) # must come after submodule was made available diff --git a/git/objects/base.py b/git/objects/base.py index cccb5ec6..59f0e836 100644 --- a/git/objects/base.py +++ b/git/objects/base.py @@ -7,6 +7,7 @@ from git.util import LazyMixin, join_path_native, stream_copy, bin_to_hex import gitdb.typ as dbtyp import os.path as osp +from typing import Optional # noqa: F401 unused import from .util import get_object_type_by_name @@ -24,7 +25,7 @@ class Object(LazyMixin): TYPES = (dbtyp.str_blob_type, dbtyp.str_tree_type, dbtyp.str_commit_type, dbtyp.str_tag_type) __slots__ = ("repo", "binsha", "size") - type = None # to be set by subclass + type = None # type: Optional[str] # to be set by subclass def __init__(self, repo, binsha): """Initialize an object by identifying it by its binary sha. diff --git a/git/refs/reference.py b/git/refs/reference.py index aaa9b63f..9014f555 100644 --- a/git/refs/reference.py +++ b/git/refs/reference.py @@ -103,7 +103,7 @@ class Reference(SymbolicReference, LazyMixin, Iterable): #{ Remote Interface - @property + @property # type: ignore ## mypy cannot deal with properties with an extra decorator (2021-04-21) @require_remote_ref_path def remote_name(self): """ @@ -114,7 +114,7 @@ class Reference(SymbolicReference, LazyMixin, Iterable): # /refs/remotes/<remote name>/<branch_name> return tokens[2] - @property + @property # type: ignore ## mypy cannot deal with properties with an extra decorator (2021-04-21) @require_remote_ref_path def remote_head(self): """:return: Name of the remote head itself, i.e. master. @@ -1,4 +1,9 @@ [mypy] -disallow_untyped_defs = True +# TODO: enable when we've fully annotated everything +#disallow_untyped_defs = True + +# TODO: remove when 'gitdb' is fully annotated +[mypy-gitdb.*] +ignore_missing_imports = True @@ -14,6 +14,14 @@ commands = coverage run --omit="git/test/*" -m unittest --buffer {posargs} [testenv:flake8] commands = flake8 --ignore=W293,E265,E266,W503,W504,E731 {posargs} +[testenv:type] +description = type check ourselves +deps = + {[testenv]deps} + mypy +commands = + mypy -p git + [testenv:venv] commands = {posargs} |