Skip to content

Commit d901f27

Browse files
authored
chore: add type validation to core commands (#3221)
1 parent 0046bd0 commit d901f27

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+690
-623
lines changed

.github/workflows/test_deploy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ jobs:
168168
- name: Test mypy
169169
env:
170170
POETRY_VIRTUALENVS_CREATE: false
171-
run: mypy
171+
run: mypy renku
172172

173173
test-distro:
174174
runs-on: ubuntu-latest

.pre-commit-config.yaml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,9 @@ repos:
3737
hooks:
3838
- id: shellcheck
3939
- repo: https://github.com/pre-commit/mirrors-mypy
40-
rev: "v0.961"
40+
rev: "v0.990"
4141
hooks:
4242
- id: mypy
43-
language_version: '3.8'
4443
args:
4544
- --no-strict-optional
4645
- --ignore-missing-imports

poetry.lock

Lines changed: 55 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ pluggy = "==1.0.0"
9898
poetry-dynamic-versioning = { version = ">=0.14,<0.18", optional = true }
9999
portalocker = ">=2.2.1,<2.5"
100100
psutil = ">=5.4.7,<5.9.2"
101+
pydantic = "==1.10.2"
101102
pydocstyle = { version = "<6.1.2,>=4.0.1", optional = true }
102103
pyjwt = ">=2.1.0,<2.5.0"
103104
pyld = "==2.0.3"
@@ -123,7 +124,7 @@ rdflib = "<7.0,>=6.0.0"
123124
redis = { version = ">=3.5.3,<4.2.0", optional = true }
124125
renku-sphinx-theme = { version = ">=0.2.0", optional = true }
125126
requests = ">=2.23.0,<2.28.2"
126-
responses = { version = ">=0.7.0,<=0.22.0", optional = true }
127+
responses = { version = ">=0.22.0,<0.23.0", optional = true }
127128
rich = ">=9.3.0,<12.6.0"
128129
rq = { version = "==1.11.0", optional = true }
129130
rq-scheduler = { version = "==0.11.0", optional = true }
@@ -227,6 +228,7 @@ all = [
227228
"plantweb",
228229
"poetry-dynamic-versioning",
229230
"ptvsd",
231+
"pydantic",
230232
"pydocstyle",
231233
"pyte",
232234
"pytest",
@@ -344,6 +346,7 @@ files = [
344346
"tests/**/*.py"
345347
]
346348
implicit_optional = true
349+
check_untyped_defs = true
347350

348351
[[tool.mypy.overrides]]
349352
module = [
@@ -397,6 +400,10 @@ ignore_missing_imports = true
397400
module = "renku.core.migration.*"
398401
ignore_errors = true
399402

403+
[[tool.mypy.overrides]]
404+
module = "renku.command.schema.calamus.*"
405+
ignore_errors = true
406+
400407
[tool.coverage.run]
401408
omit = ["renku/conftest.py", "renku/data/*", "docs/*", "tests/*"]
402409
relative_files = true

renku/__init__.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from __future__ import absolute_import, print_function
2121

2222
import importlib
23+
import importlib.util
2324
import sys
2425
import warnings
2526

@@ -55,9 +56,9 @@ def exec_module(self, module):
5556
sys.modules[self.additional_namespace] = module
5657

5758
def __getattr__(self, name):
58-
"""Forward all calls to wrapped loaded except for one implemented here."""
59+
"""Forward all calls to wrapped loader except for one implemented here."""
5960
if name in ["exec_module", "create_module", "get_code"]:
60-
object.__getattr__(self, name)
61+
object.__getattribute__(self, name)
6162

6263
return getattr(self.wrapped_loader, name)
6364

@@ -88,6 +89,9 @@ def find_spec(self, fullname, path, target=None):
8889

8990
sys.meta_path = [x for x in sys.meta_path if x is not self]
9091
spec = importlib.util.find_spec(target_name)
92+
if spec is None:
93+
return None
94+
9195
spec.loader = LoaderWrapper(spec.loader, fullname, target_name)
9296
finally:
9397
sys.meta_path.insert(0, self)

renku/command/checks/githooks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
from renku.domain_model.project_context import project_context
2626

2727
try:
28-
import importlib_resources
28+
import importlib_resources # type: ignore[import]
2929
except ImportError:
3030
import importlib.resources as importlib_resources # type: ignore
3131

renku/command/clone.py

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,39 +17,46 @@
1717
# limitations under the License.
1818
"""Clone a Renku repo along with all Renku-specific initializations."""
1919

20+
from pathlib import Path
21+
from typing import Any, Dict, Optional, Union
22+
23+
from git.remote import RemoteProgress
24+
from pydantic import validate_arguments
25+
2026
from renku.command.command_builder.command import Command
2127
from renku.domain_model.project_context import project_context
2228

2329

30+
@validate_arguments(config=dict(arbitrary_types_allowed=True))
2431
def _project_clone(
25-
url,
26-
path=None,
27-
install_githooks=True,
28-
install_mergetool=True,
29-
skip_smudge=True,
30-
recursive=True,
31-
depth=None,
32-
progress=None,
33-
config=None,
34-
raise_git_except=False,
35-
checkout_revision=None,
36-
use_renku_credentials=False,
32+
url: str,
33+
path: Optional[Union[str, Path]] = None,
34+
install_githooks: bool = True,
35+
install_mergetool: bool = True,
36+
skip_smudge: bool = True,
37+
recursive: bool = True,
38+
depth: Optional[int] = None,
39+
progress: Optional[RemoteProgress] = None,
40+
config: Optional[Dict[str, Any]] = None,
41+
raise_git_except: bool = False,
42+
checkout_revision: Optional[str] = None,
43+
use_renku_credentials: bool = False,
3744
):
3845
"""Clone Renku project repo, install Git hooks and LFS.
3946
4047
Args:
41-
url: Git URL to clone.
42-
path: Path to clone to (Default value = None).
43-
install_githooks: Whether to install the pre-commit hook or not (Default value = True).
44-
install_mergetool: Whether to install the renku metadata git mergetool or not (Default value = True).
45-
skip_smudge: Whether to skip pulling files from LFS (Default value = True).
46-
recursive: Recursively clone (Default value = True).
47-
depth: Clone depth (commits from HEAD) (Default value = None).
48-
progress: Git progress object (Default value = None).
49-
config: Initial config (Default value = None).
50-
raise_git_except: Whether to raise Git exceptions or not (Default value = False).
51-
checkout_revision: Specific revision to check out (Default value = None).
52-
use_renku_credentials: Whether to use credentials stored in renku (Default value = False).
48+
url(str): Git URL to clone.
49+
path(Optional[str]): Path to clone to (Default value = None).
50+
install_githooks(bool): Whether to install the pre-commit hook or not (Default value = True).
51+
install_mergetool(bool): Whether to install the renku metadata git mergetool or not (Default value = True).
52+
skip_smudge(bool): Whether to skip pulling files from LFS (Default value = True).
53+
recursive(bool): Recursively clone (Default value = True).
54+
depth(Optional[int]): Clone depth (commits from HEAD) (Default value = None).
55+
progress(Optional[RemoteProgress]): Git progress object (Default value = None).
56+
config(Optional[Dict[str, Any]]): Initial config (Default value = None).
57+
raise_git_except(bool): Whether to raise Git exceptions or not (Default value = False).
58+
checkout_revision(Optional[str]): Specific revision to check out (Default value = None).
59+
use_renku_credentials(bool): Whether to use credentials stored in renku (Default value = False).
5360
5461
Returns:
5562
Tuple of cloned ``Repository`` and whether it's a Renku project or not.

renku/command/command_builder/command.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ def command(self, operation: Callable):
357357
Returns:
358358
Command: This command.
359359
"""
360+
360361
self._operation = operation
361362

362363
return self

renku/command/config.py

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
# limitations under the License.
1818
"""Get and set Renku repository or global options."""
1919

20+
from typing import Dict, Optional
21+
22+
from pydantic import validate_arguments
23+
2024
from renku.command.command_builder.command import Command
2125
from renku.core import errors
2226
from renku.core.config import get_config, get_value, remove_value, set_value
@@ -39,13 +43,16 @@ def _split_section_and_key(key):
3943
return "renku", key
4044

4145

42-
def _update_multiple_config(values, global_only=False, commit_message=None):
46+
@validate_arguments(config=dict(arbitrary_types_allowed=True))
47+
def _update_multiple_config(
48+
values: Dict[str, Optional[str]], global_only: bool = False, commit_message: Optional[str] = None
49+
):
4350
"""Add, update, or remove multiple configuration values.
4451
4552
Args:
46-
values: Dictionary of config key values to update.
47-
global_only: Whether to only update global config (Default value = False).
48-
commit_message: Commit message for change (Default value = None).
53+
values(Dict[str, str]): Dictionary of config key values to update.
54+
global_only(bool): Whether to only update global config (Default value = False).
55+
commit_message(Optional[str]): Commit message for change (Default value = None).
4956
"""
5057
for k, v in values.items():
5158
if v is not None:
@@ -65,15 +72,23 @@ def update_multiple_config():
6572
)
6673

6774

68-
def _update_config(key, *, value=None, remove=False, global_only=False, commit_message=None):
75+
@validate_arguments(config=dict(arbitrary_types_allowed=True))
76+
def _update_config(
77+
key: str,
78+
*,
79+
value: Optional[str] = None,
80+
remove: bool = False,
81+
global_only: bool = False,
82+
commit_message: Optional[str] = None,
83+
):
6984
"""Add, update, or remove configuration values.
7085
7186
Args:
72-
key: Config key.
73-
value: Config value (Default value = None).
74-
remove: Whether to remove values (Default value = False).
75-
global_only: Whether to only update global config (Default value = False).
76-
commit_message: Commit message for change (Default value = None).
87+
key(str): Config key.
88+
value(Optional[str]): Config value (Default value = None).
89+
remove(bool): Whether to remove values (Default value = False).
90+
global_only(bool): Whether to only update global config (Default value = False).
91+
commit_message(Optional[str]): Commit message for change (Default value = None).
7792
Raises:
7893
errors.ParameterError: If key wasn't found.
7994
Returns:
@@ -100,7 +115,8 @@ def update_config():
100115
)
101116

102117

103-
def _read_config(key, config_filter=ConfigFilter.ALL, as_string=True):
118+
@validate_arguments(config=dict(arbitrary_types_allowed=True))
119+
def _read_config(key: Optional[str], config_filter: ConfigFilter = ConfigFilter.ALL, as_string: bool = True):
104120
"""Read configuration.
105121
106122
Args:

0 commit comments

Comments
 (0)