Skip to content

ci: check types with mypy #1226

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Apr 23, 2021
5 changes: 5 additions & 0 deletions .github/workflows/pythonpackage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 4 additions & 3 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -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 *
Expand Down
2 changes: 1 addition & 1 deletion git/cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def dict_to_slots_and__excluded_are_none(self, d, excluded=()):

## 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)


Expand Down
30 changes: 28 additions & 2 deletions git/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,16 @@

# 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

# ---------------------------------------------------------------------------
Expand All @@ -30,6 +39,12 @@
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):
Expand All @@ -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):
Expand All @@ -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):
Expand All @@ -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"""

Expand Down
2 changes: 1 addition & 1 deletion git/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
1 change: 1 addition & 0 deletions git/exc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions git/objects/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
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
Expand Down
3 changes: 2 additions & 1 deletion git/objects/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

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

Expand All @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions git/refs/reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def iter_items(cls, repo, common_path=None):

#{ 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):
"""
Expand All @@ -114,7 +114,7 @@ def remote_name(self):
# /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.
Expand Down
7 changes: 6 additions & 1 deletion mypy.ini
Original file line number Diff line number Diff line change
@@ -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
8 changes: 8 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -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}

Expand Down