summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn L. Villalovos <john@sodarock.com>2021-11-24 17:43:46 -0800
committerJohn L. Villalovos <john@sodarock.com>2021-11-24 20:41:36 -0800
commit308210b3dee15c844cd5db4ddd8c7404bb188990 (patch)
tree4df88a7a967e209afcf2efea9efc5fd8be358128
parentab82fd84ba3cecf766915112dcb46fdfab383e73 (diff)
downloadgitlab-jlvillal/mypy_strict.tar.gz
WIP: work on enable mypy 'strict' modejlvillal/mypy_strict
-rw-r--r--gitlab/__init__.py4
-rw-r--r--gitlab/base.py21
-rw-r--r--gitlab/client.py15
-rw-r--r--gitlab/mixins.py9
-rw-r--r--gitlab/utils.py2
-rw-r--r--gitlab/v4/objects/files.py5
-rw-r--r--gitlab/v4/objects/keys.py2
-rw-r--r--gitlab/v4/objects/packages.py2
-rw-r--r--gitlab/v4/objects/projects.py6
-rw-r--r--gitlab/v4/objects/users.py1
-rw-r--r--pyproject.toml17
-rw-r--r--tests/functional/api/test_users.py4
-rw-r--r--tests/meta/test_ensure_type_hints.py15
-rw-r--r--tests/unit/test_base.py11
14 files changed, 90 insertions, 24 deletions
diff --git a/gitlab/__init__.py b/gitlab/__init__.py
index 7b79f22..34f6619 100644
--- a/gitlab/__init__.py
+++ b/gitlab/__init__.py
@@ -32,3 +32,7 @@ from gitlab.const import * # noqa: F401,F403
from gitlab.exceptions import * # noqa: F401,F403
warnings.filterwarnings("default", category=DeprecationWarning, module="^gitlab")
+
+__all__ = [
+ "Gitlab",
+]
diff --git a/gitlab/base.py b/gitlab/base.py
index 5e5f57b..8dcae7d 100644
--- a/gitlab/base.py
+++ b/gitlab/base.py
@@ -17,7 +17,17 @@
import importlib
from types import ModuleType
-from typing import Any, Dict, Iterable, NamedTuple, Optional, Tuple, Type
+from typing import (
+ Any,
+ Dict,
+ Iterable,
+ NamedTuple,
+ Optional,
+ Tuple,
+ Type,
+ TYPE_CHECKING,
+ Union,
+)
from gitlab import types as g_types
from gitlab.exceptions import GitlabParsingError
@@ -172,15 +182,18 @@ class RESTObject(object):
self.__dict__["_updated_attrs"] = {}
self.__dict__["_attrs"] = new_attrs
- def get_id(self) -> Any:
+ def get_id(self) -> Optional[Union[int, str]]:
"""Returns the id of the resource."""
if self._id_attr is None or not hasattr(self, self._id_attr):
return None
- return getattr(self, self._id_attr)
+ id_val = getattr(self, self._id_attr)
+ if TYPE_CHECKING:
+ assert isinstance(id_val, (int, str))
+ return id_val
@property
def attributes(self) -> Dict[str, Any]:
- d = self.__dict__["_updated_attrs"].copy()
+ d: Dict[str, Any] = self.__dict__["_updated_attrs"].copy()
d.update(self.__dict__["_attrs"])
d.update(self.__dict__["_parent_attrs"])
return d
diff --git a/gitlab/client.py b/gitlab/client.py
index 295712c..467c5dc 100644
--- a/gitlab/client.py
+++ b/gitlab/client.py
@@ -337,6 +337,7 @@ class Gitlab(object):
data = self.http_post("/markdown", post_data=post_data, **kwargs)
if TYPE_CHECKING:
assert not isinstance(data, requests.Response)
+ assert isinstance(data["html"], str)
return data["html"]
@gitlab.exceptions.on_http_error(gitlab.exceptions.GitlabLicenseError)
@@ -614,10 +615,13 @@ class Gitlab(object):
cur_retries = 0
while True:
result = self.session.send(prepped, timeout=timeout, **settings)
+ print("result type:", type(result))
+ print("result:", result)
self._check_redirects(result)
if 200 <= result.status_code < 300:
+ print("Returning result:", result)
return result
retry_transient_errors = kwargs.get(
@@ -694,7 +698,8 @@ class Gitlab(object):
and not raw
):
try:
- return result.json()
+ data: Dict[str, Any] = result.json()
+ return data
except Exception as e:
raise gitlab.exceptions.GitlabParsingError(
error_message="Failed to parse the server message"
@@ -791,7 +796,10 @@ class Gitlab(object):
)
try:
if result.headers.get("Content-Type", None) == "application/json":
- return result.json()
+ print("data.text:", result.text)
+ data: Dict[str, Any] = result.json()
+ print("data type:", type(data))
+ return data
except Exception as e:
raise gitlab.exceptions.GitlabParsingError(
error_message="Failed to parse the server message"
@@ -839,7 +847,8 @@ class Gitlab(object):
**kwargs,
)
try:
- return result.json()
+ data: Dict[str, Any] = result.json()
+ return data
except Exception as e:
raise gitlab.exceptions.GitlabParsingError(
error_message="Failed to parse the server message"
diff --git a/gitlab/mixins.py b/gitlab/mixins.py
index 0159ecd..785e3c5 100644
--- a/gitlab/mixins.py
+++ b/gitlab/mixins.py
@@ -573,9 +573,11 @@ class ObjectDeleteMixin(_RestObjectBase):
GitlabAuthenticationError: If authentication is not correct
GitlabDeleteError: If the server cannot perform the request
"""
+ id_val = self.get_id()
if TYPE_CHECKING:
assert isinstance(self.manager, DeleteMixin)
- self.manager.delete(self.get_id(), **kwargs)
+ assert id_val is not None
+ self.manager.delete(id_val, **kwargs)
class UserAgentDetailMixin(_RestObjectBase):
@@ -652,7 +654,7 @@ class DownloadMixin(_RestObjectBase):
def download(
self,
streamed: bool = False,
- action: Optional[Callable] = None,
+ action: Optional[Callable[[bytes], None]] = None,
chunk_size: int = 1024,
**kwargs: Any,
) -> Optional[bytes]:
@@ -779,7 +781,8 @@ class TimeTrackingMixin(_RestObjectBase):
# Use the existing time_stats attribute if it exist, otherwise make an
# API call
if "time_stats" in self.attributes:
- return self.attributes["time_stats"]
+ time_stats: Dict[str, Any] = self.attributes["time_stats"]
+ return time_stats
path = f"{self.manager.path}/{self.get_id()}/time_stats"
result = self.manager.gitlab.http_get(path, **kwargs)
diff --git a/gitlab/utils.py b/gitlab/utils.py
index 220a8c9..196210c 100644
--- a/gitlab/utils.py
+++ b/gitlab/utils.py
@@ -29,7 +29,7 @@ class _StdoutStream(object):
def response_content(
response: requests.Response,
streamed: bool,
- action: Optional[Callable],
+ action: Optional[Callable[[bytes], None]],
chunk_size: int,
) -> Optional[bytes]:
if streamed is False:
diff --git a/gitlab/v4/objects/files.py b/gitlab/v4/objects/files.py
index ce7317d..fa4d744 100644
--- a/gitlab/v4/objects/files.py
+++ b/gitlab/v4/objects/files.py
@@ -76,7 +76,10 @@ class ProjectFile(SaveMixin, ObjectDeleteMixin, RESTObject):
GitlabAuthenticationError: If authentication is not correct
GitlabDeleteError: If the server cannot perform the request
"""
- file_path = self.get_id().replace("/", "%2F")
+ id_val = self.get_id()
+ if TYPE_CHECKING:
+ assert isinstance(id_val, str)
+ file_path = id_val.replace("/", "%2F")
self.manager.delete(file_path, branch, commit_message, **kwargs)
diff --git a/gitlab/v4/objects/keys.py b/gitlab/v4/objects/keys.py
index 46f6894..c03dced 100644
--- a/gitlab/v4/objects/keys.py
+++ b/gitlab/v4/objects/keys.py
@@ -31,4 +31,4 @@ class KeyManager(GetMixin, RESTManager):
server_data = self.gitlab.http_get(self.path, **kwargs)
if TYPE_CHECKING:
assert isinstance(server_data, dict)
- return cast(Key, self._obj_cls(self, server_data))
+ return self._obj_cls(self, server_data)
diff --git a/gitlab/v4/objects/packages.py b/gitlab/v4/objects/packages.py
index 0062067..55e45a3 100644
--- a/gitlab/v4/objects/packages.py
+++ b/gitlab/v4/objects/packages.py
@@ -103,7 +103,7 @@ class GenericPackageManager(RESTManager):
package_version: str,
file_name: str,
streamed: bool = False,
- action: Optional[Callable] = None,
+ action: Optional[Callable[[bytes], None]] = None,
chunk_size: int = 1024,
**kwargs: Any,
) -> Optional[bytes]:
diff --git a/gitlab/v4/objects/projects.py b/gitlab/v4/objects/projects.py
index c5ce717..6fd60f4 100644
--- a/gitlab/v4/objects/projects.py
+++ b/gitlab/v4/objects/projects.py
@@ -436,7 +436,7 @@ class Project(RefreshMixin, SaveMixin, ObjectDeleteMixin, RepositoryMixin, RESTO
self,
wiki: bool = False,
streamed: bool = False,
- action: Optional[Callable] = None,
+ action: Optional[Callable[[bytes], None]] = None,
chunk_size: int = 1024,
**kwargs: Any,
) -> Optional[bytes]:
@@ -531,7 +531,7 @@ class Project(RefreshMixin, SaveMixin, ObjectDeleteMixin, RepositoryMixin, RESTO
ref_name: str,
job: str,
streamed: bool = False,
- action: Optional[Callable] = None,
+ action: Optional[Callable[[bytes], None]] = None,
chunk_size: int = 1024,
**kwargs: Any,
) -> Optional[bytes]:
@@ -574,7 +574,7 @@ class Project(RefreshMixin, SaveMixin, ObjectDeleteMixin, RepositoryMixin, RESTO
artifact_path: str,
job: str,
streamed: bool = False,
- action: Optional[Callable] = None,
+ action: Optional[Callable[[bytes], None]] = None,
chunk_size: int = 1024,
**kwargs: Any,
) -> Optional[bytes]:
diff --git a/gitlab/v4/objects/users.py b/gitlab/v4/objects/users.py
index bf7d283..bced3fc 100644
--- a/gitlab/v4/objects/users.py
+++ b/gitlab/v4/objects/users.py
@@ -181,6 +181,7 @@ class User(SaveMixin, ObjectDeleteMixin, RESTObject):
"""
path = f"/users/{self.id}/block"
server_data = self.manager.gitlab.http_post(path, **kwargs)
+ print(type(server_data))
if server_data is True:
self._attrs["state"] = "blocked"
return server_data
diff --git a/pyproject.toml b/pyproject.toml
index a19b28e..e70d3a6 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -8,6 +8,23 @@ disallow_incomplete_defs = true
disallow_untyped_defs = true
files = "."
+# strict = true is
+check_untyped_defs = true
+disallow_any_generics = true
+# disallow_incomplete_defs = true
+disallow_subclassing_any = true
+# disallow_untyped_calls = true
+disallow_untyped_decorators = true
+# disallow_untyped_defs = true
+no_implicit_optional = true
+# no_implicit_reexport = true
+strict_equality = true
+warn_redundant_casts = true
+warn_return_any = true
+warn_unused_configs = true
+warn_unused_ignores = true
+
+
[[tool.mypy.overrides]] # Overrides for currently untyped modules
module = [
"docs.*",
diff --git a/tests/functional/api/test_users.py b/tests/functional/api/test_users.py
index 1ef237c..a21298e 100644
--- a/tests/functional/api/test_users.py
+++ b/tests/functional/api/test_users.py
@@ -33,7 +33,9 @@ def test_create_user(gl, avatar_path):
def test_block_user(gl, user):
- user.block()
+ result = user.block()
+ result = user.block()
+ assert result == "dkdkdkdk"
users = gl.users.list(blocked=True)
assert user in users
diff --git a/tests/meta/test_ensure_type_hints.py b/tests/meta/test_ensure_type_hints.py
index 2449324..0de9af2 100644
--- a/tests/meta/test_ensure_type_hints.py
+++ b/tests/meta/test_ensure_type_hints.py
@@ -7,7 +7,7 @@ Original notes by John L. Villalovos
import dataclasses
import functools
import inspect
-from typing import Optional, Type
+from typing import Optional, Type, Union, TYPE_CHECKING
import _pytest
@@ -19,7 +19,7 @@ import gitlab.v4.objects
@dataclasses.dataclass(frozen=True)
class ClassInfo:
name: str
- type: Type
+ type: Type[Union[gitlab.mixins.GetMixin, gitlab.mixins.GetWithoutIdMixin]]
def __lt__(self, other: object) -> bool:
if not isinstance(other, ClassInfo):
@@ -108,7 +108,7 @@ class TestTypeHints:
def get_check_helper(
self,
*,
- base_type: Type,
+ base_type: Type[Union[gitlab.mixins.GetMixin, gitlab.mixins.GetWithoutIdMixin]],
class_info: ClassInfo,
method_template: str,
optional_return: bool,
@@ -121,6 +121,11 @@ class TestTypeHints:
return
obj_cls = class_info.type._obj_cls
+ if TYPE_CHECKING:
+ assert obj_cls is not None
+ assert issubclass(
+ obj_cls, (gitlab.mixins.GetMixin, gitlab.mixins.GetWithoutIdMixin)
+ )
signature = inspect.signature(class_info.type.get)
filename = inspect.getfile(class_info.type)
@@ -131,7 +136,9 @@ class TestTypeHints:
f"Recommend adding the followinng method:\n"
)
fail_message += method_template.format(obj_cls=obj_cls)
- check_type = obj_cls
+ check_type: Optional[
+ Type[Union[gitlab.mixins.GetMixin, gitlab.mixins.GetWithoutIdMixin]]
+ ] = obj_cls
if optional_return:
check_type = Optional[obj_cls]
assert check_type == signature.return_annotation, fail_message
diff --git a/tests/unit/test_base.py b/tests/unit/test_base.py
index 137f480..902d9b4 100644
--- a/tests/unit/test_base.py
+++ b/tests/unit/test_base.py
@@ -117,8 +117,8 @@ class TestRESTObject:
obj.id = 42
assert 42 == obj.get_id()
- obj.id = None
- assert obj.get_id() is None
+ obj.id = "hello"
+ assert "hello" == obj.get_id()
def test_custom_id_attr(self, fake_manager):
class OtherFakeObject(FakeObject):
@@ -127,6 +127,13 @@ class TestRESTObject:
obj = OtherFakeObject(fake_manager, {"foo": "bar"})
assert "bar" == obj.get_id()
+ def test_custom_id_attr_missing(self, fake_manager):
+ class OtherFakeObject(FakeObject):
+ _id_attr = "spam"
+
+ obj = OtherFakeObject(fake_manager, {"foo": "bar"})
+ assert obj.get_id() is None
+
def test_update_attrs(self, fake_manager):
obj = FakeObject(fake_manager, {"foo": "bar"})
obj.bar = "baz"