summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNejc Habjan <hab.nejc@gmail.com>2021-02-23 17:28:34 +0100
committerGitHub <noreply@github.com>2021-02-23 17:28:34 +0100
commita18bc5c525b686af5f28216d2f1da95942b63f61 (patch)
tree8faa35a417ed2e070d1181366b65fda7f0fc9488
parentd9fdf1db9b928ac154ad385cf6e7f8220ea42aa1 (diff)
parent3727cbd21fc40b312573ca8da56e0f6cf9577d08 (diff)
downloadgitlab-a18bc5c525b686af5f28216d2f1da95942b63f61.tar.gz
Merge pull request #1299 from JohnVillalovos/mypy
Enable mypy type checking and add type hints to gitlab/base.py
-rw-r--r--.github/workflows/lint.yml8
-rw-r--r--.mypy.ini2
-rw-r--r--gitlab/base.py63
-rw-r--r--gitlab/cli.py2
-rw-r--r--gitlab/client.py2
-rw-r--r--test-requirements.txt1
-rw-r--r--tox.ini9
7 files changed, 55 insertions, 32 deletions
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 968320d..4b918df 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -27,3 +27,11 @@ jobs:
with:
fetch-depth: 0
- uses: wagoid/commitlint-github-action@v2
+
+ mypy:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: actions/setup-python@v2
+ - run: pip install --upgrade tox
+ - run: tox -e mypy
diff --git a/.mypy.ini b/.mypy.ini
new file mode 100644
index 0000000..e68f0f6
--- /dev/null
+++ b/.mypy.ini
@@ -0,0 +1,2 @@
+[mypy]
+files = gitlab/*.py
diff --git a/gitlab/base.py b/gitlab/base.py
index 6d92fdf..f0bedc7 100644
--- a/gitlab/base.py
+++ b/gitlab/base.py
@@ -16,7 +16,9 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import importlib
+from typing import Any, Dict, Optional
+from .client import Gitlab, GitlabList
__all__ = [
"RESTObject",
@@ -38,7 +40,7 @@ class RESTObject(object):
_id_attr = "id"
- def __init__(self, manager, attrs):
+ def __init__(self, manager: "RESTManager", attrs: Dict[str, Any]) -> None:
self.__dict__.update(
{
"manager": manager,
@@ -50,18 +52,18 @@ class RESTObject(object):
self.__dict__["_parent_attrs"] = self.manager.parent_attrs
self._create_managers()
- def __getstate__(self):
+ def __getstate__(self) -> Dict[str, Any]:
state = self.__dict__.copy()
module = state.pop("_module")
state["_module_name"] = module.__name__
return state
- def __setstate__(self, state):
+ def __setstate__(self, state: Dict[str, Any]) -> None:
module_name = state.pop("_module_name")
self.__dict__.update(state)
self.__dict__["_module"] = importlib.import_module(module_name)
- def __getattr__(self, name):
+ def __getattr__(self, name: str) -> Any:
try:
return self.__dict__["_updated_attrs"][name]
except KeyError:
@@ -90,15 +92,15 @@ class RESTObject(object):
except KeyError:
raise AttributeError(name)
- def __setattr__(self, name, value):
+ def __setattr__(self, name: str, value) -> None:
self.__dict__["_updated_attrs"][name] = value
- def __str__(self):
+ def __str__(self) -> str:
data = self._attrs.copy()
data.update(self._updated_attrs)
return "%s => %s" % (type(self), data)
- def __repr__(self):
+ def __repr__(self) -> str:
if self._id_attr:
return "<%s %s:%s>" % (
self.__class__.__name__,
@@ -108,12 +110,12 @@ class RESTObject(object):
else:
return "<%s>" % self.__class__.__name__
- def __eq__(self, other):
+ def __eq__(self, other) -> bool:
if self.get_id() and other.get_id():
return self.get_id() == other.get_id()
return super(RESTObject, self) == other
- def __ne__(self, other):
+ def __ne__(self, other) -> bool:
if self.get_id() and other.get_id():
return self.get_id() != other.get_id()
return super(RESTObject, self) != other
@@ -121,12 +123,12 @@ class RESTObject(object):
def __dir__(self):
return super(RESTObject, self).__dir__() + list(self.attributes)
- def __hash__(self):
+ def __hash__(self) -> int:
if not self.get_id():
return super(RESTObject, self).__hash__()
return hash(self.get_id())
- def _create_managers(self):
+ def _create_managers(self) -> None:
managers = getattr(self, "_managers", None)
if managers is None:
return
@@ -136,7 +138,7 @@ class RESTObject(object):
manager = cls(self.manager.gitlab, parent=self)
self.__dict__[attr] = manager
- def _update_attrs(self, new_attrs):
+ def _update_attrs(self, new_attrs) -> None:
self.__dict__["_updated_attrs"] = {}
self.__dict__["_attrs"] = new_attrs
@@ -147,7 +149,7 @@ class RESTObject(object):
return getattr(self, self._id_attr)
@property
- def attributes(self):
+ def attributes(self) -> Dict[str, Any]:
d = self.__dict__["_updated_attrs"].copy()
d.update(self.__dict__["_attrs"])
d.update(self.__dict__["_parent_attrs"])
@@ -169,7 +171,7 @@ class RESTObjectList(object):
_list: A GitlabList object
"""
- def __init__(self, manager, obj_cls, _list):
+ def __init__(self, manager: "RESTManager", obj_cls, _list: GitlabList) -> None:
"""Creates an objects list from a GitlabList.
You should not create objects of this type, but use managers list()
@@ -184,10 +186,10 @@ class RESTObjectList(object):
self._obj_cls = obj_cls
self._list = _list
- def __iter__(self):
+ def __iter__(self) -> "RESTObjectList":
return self
- def __len__(self):
+ def __len__(self) -> int:
return len(self._list)
def __next__(self):
@@ -198,12 +200,12 @@ class RESTObjectList(object):
return self._obj_cls(self.manager, data)
@property
- def current_page(self):
+ def current_page(self) -> int:
"""The current page number."""
return self._list.current_page
@property
- def prev_page(self):
+ def prev_page(self) -> int:
"""The previous page number.
If None, the current page is the first.
@@ -211,7 +213,7 @@ class RESTObjectList(object):
return self._list.prev_page
@property
- def next_page(self):
+ def next_page(self) -> int:
"""The next page number.
If None, the current page is the last.
@@ -219,17 +221,17 @@ class RESTObjectList(object):
return self._list.next_page
@property
- def per_page(self):
+ def per_page(self) -> int:
"""The number of items per page."""
return self._list.per_page
@property
- def total_pages(self):
+ def total_pages(self) -> int:
"""The total number of pages."""
return self._list.total_pages
@property
- def total(self):
+ def total(self) -> int:
"""The total number of items."""
return self._list.total
@@ -243,10 +245,11 @@ class RESTManager(object):
``_obj_cls``: The class of objects that will be created
"""
- _path = None
- _obj_cls = None
+ _path: Optional[str] = None
+ _obj_cls: Optional[Any] = None
+ _from_parent_attrs: Dict[str, Any] = {}
- def __init__(self, gl, parent=None):
+ def __init__(self, gl: Gitlab, parent: Optional[RESTObject] = None) -> None:
"""REST manager constructor.
Args:
@@ -259,23 +262,25 @@ class RESTManager(object):
self._computed_path = self._compute_path()
@property
- def parent_attrs(self):
+ def parent_attrs(self) -> Optional[Dict[str, Any]]:
return self._parent_attrs
- def _compute_path(self, path=None):
+ def _compute_path(self, path: Optional[str] = None) -> Optional[str]:
self._parent_attrs = {}
if path is None:
path = self._path
+ if path is None:
+ return None
if self._parent is None or not hasattr(self, "_from_parent_attrs"):
return path
data = {
self_attr: getattr(self._parent, parent_attr, None)
- for self_attr, parent_attr in self._from_parent_attrs.items()
+ for self_attr, parent_attr in self._from_parent_attrs.items() # type: ignore
}
self._parent_attrs = data
return path % data
@property
- def path(self):
+ def path(self) -> Optional[str]:
return self._computed_path
diff --git a/gitlab/cli.py b/gitlab/cli.py
index d858a74..3a315a8 100644
--- a/gitlab/cli.py
+++ b/gitlab/cli.py
@@ -193,7 +193,7 @@ def main():
# Now we build the entire set of subcommands and do the complete parsing
parser = _get_parser(gitlab.v4.cli)
try:
- import argcomplete
+ import argcomplete # type: ignore
argcomplete.autocomplete(parser)
except Exception:
diff --git a/gitlab/client.py b/gitlab/client.py
index 43cee10..910926a 100644
--- a/gitlab/client.py
+++ b/gitlab/client.py
@@ -25,7 +25,7 @@ import gitlab.config
import gitlab.const
import gitlab.exceptions
from gitlab import utils
-from requests_toolbelt.multipart.encoder import MultipartEncoder
+from requests_toolbelt.multipart.encoder import MultipartEncoder # type: ignore
REDIRECT_MSG = (
diff --git a/test-requirements.txt b/test-requirements.txt
index 8d61ad1..53456ad 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,6 +1,7 @@
coverage
httmock
mock
+mypy
pytest
pytest-cov
responses
diff --git a/tox.ini b/tox.ini
index ba64a43..826e081 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,7 +1,7 @@
[tox]
minversion = 1.6
skipsdist = True
-envlist = py39,py38,py37,py36,pep8,black,twine-check
+envlist = py39,py38,py37,py36,pep8,black,twine-check,mypy
[testenv]
passenv = GITLAB_IMAGE GITLAB_TAG
@@ -35,6 +35,13 @@ deps = -r{toxinidir}/requirements.txt
commands =
twine check dist/*
+[testenv:mypy]
+basepython = python3
+deps = -r{toxinidir}/requirements.txt
+ -r{toxinidir}/test-requirements.txt
+commands =
+ mypy {posargs}
+
[testenv:venv]
commands = {posargs}