Skip to content

Commit 862a460

Browse files
authored
ci(mypy): Turn on mypy --strict (#386)
2 parents f7f4d96 + e8f81df commit 862a460

23 files changed

+419
-253
lines changed

.tmuxp.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ windows:
1111
panes:
1212
- focus: true
1313
- pane
14+
- make watch_mypy
1415
- make watch_test
1516
- window_name: docs
1617
layout: main-horizontal

CHANGES

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ $ pipx install --suffix=@next 'vcspull' --pip-args '\--pre' --force
2121

2222
<!-- Maintainers, insert changes / features for the next release here -->
2323

24+
25+
### Internal
26+
27+
- mypy: Add `--strict` typings (#386)
28+
2429
## vcspull v1.18.0 (2022-10-31)
2530

2631
### Python 3.11 support (#409)
@@ -218,7 +223,13 @@ $ pipx install --suffix=@next 'vcspull' --pip-args '\--pre' --force
218223

219224
- Move to `src/` directory structure (#382)
220225
- libvcs: Update to 0.17.x (#373)
221-
- Basic mypy annotations (#373)
226+
- mypy:
227+
228+
- Basic mypy annotations (#373)
229+
- [`mypy --strict`] compliant (#386)
230+
231+
[`mypy --strict`]: https://mypy.readthedocs.io/en/stable/command_line.html#cmdoption-mypy-strict
232+
222233
- Remove `.pre-commit-config.yaml`: Let's not automate what the contributor could /
223234
should do themselves.
224235
- Add [flake8-bugbear](https://github.com/PyCQA/flake8-bugbear) (#379)

conftest.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,36 +34,40 @@ def cwd_default(monkeypatch: pytest.MonkeyPatch, tmp_path: pathlib.Path) -> None
3434

3535
@pytest.fixture(autouse=True, scope="session")
3636
@pytest.mark.usefixtures("set_home")
37-
def xdg_config_path(user_path: pathlib.Path):
37+
def xdg_config_path(user_path: pathlib.Path) -> pathlib.Path:
3838
p = user_path / ".config"
3939
p.mkdir()
4040
return p
4141

4242

4343
@pytest.fixture(scope="function")
44-
def config_path(xdg_config_path: pathlib.Path, request: pytest.FixtureRequest):
44+
def config_path(
45+
xdg_config_path: pathlib.Path, request: pytest.FixtureRequest
46+
) -> pathlib.Path:
4547
conf_path = xdg_config_path / "vcspull"
4648
conf_path.mkdir(exist_ok=True)
4749

48-
def clean():
50+
def clean() -> None:
4951
shutil.rmtree(conf_path)
5052

5153
request.addfinalizer(clean)
5254
return conf_path
5355

5456

5557
@pytest.fixture(autouse=True)
56-
def set_xdg_config_path(monkeypatch: pytest.MonkeyPatch, xdg_config_path: pathlib.Path):
58+
def set_xdg_config_path(
59+
monkeypatch: pytest.MonkeyPatch, xdg_config_path: pathlib.Path
60+
) -> None:
5761
monkeypatch.setenv("XDG_CONFIG_HOME", str(xdg_config_path))
5862

5963

6064
@pytest.fixture(scope="function")
61-
def repos_path(user_path: pathlib.Path, request: pytest.FixtureRequest):
65+
def repos_path(user_path: pathlib.Path, request: pytest.FixtureRequest) -> pathlib.Path:
6266
"""Return temporary directory for repository checkout guaranteed unique."""
6367
dir = user_path / "repos"
6468
dir.mkdir(exist_ok=True)
6569

66-
def clean():
70+
def clean() -> None:
6771
shutil.rmtree(dir)
6872

6973
request.addfinalizer(clean)

docs/conf.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
# flake8: noqa E501
2+
import inspect
23
import os
34
import sys
5+
import typing as t
6+
from os.path import dirname, relpath
47
from pathlib import Path
58

9+
import vcspull
10+
611
# Get the project root dir, which is the parent dir of this
712
cwd = Path.cwd()
813
project_root = cwd.parent
@@ -60,7 +65,7 @@
6065
html_css_files = ["css/custom.css"]
6166
html_extra_path = ["manifest.json"]
6267
html_theme = "furo"
63-
html_theme_path: list = []
68+
html_theme_path: list[str] = []
6469
html_theme_options = {
6570
"light_logo": "img/vcspull.svg",
6671
"dark_logo": "img/vcspull-dark.svg",
@@ -171,13 +176,9 @@
171176
}
172177

173178

174-
def linkcode_resolve(domain, info): # NOQA: C901
175-
import inspect
176-
import sys
177-
from os.path import dirname, relpath
178-
179-
import vcspull
180-
179+
def linkcode_resolve(
180+
domain: str, info: dict[str, str]
181+
) -> t.Union[None, str]: # NOQA: C901
181182
"""
182183
Determine the URL corresponding to Python object
183184
@@ -210,7 +211,8 @@ def linkcode_resolve(domain, info): # NOQA: C901
210211
except AttributeError:
211212
pass
212213
else:
213-
obj = unwrap(obj)
214+
if callable(obj):
215+
obj = unwrap(obj)
214216

215217
try:
216218
fn = inspect.getsourcefile(obj)

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ files = [
143143
"src",
144144
"tests"
145145
]
146+
strict = true
146147

147148
[[tool.mypy.overrides]]
148149
module = [

scripts/generate_gitlab.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
import requests
88
import yaml
99

10+
from libvcs.sync.git import GitRemote
11+
from vcspull.cli.sync import guess_vcs
12+
from vcspull.types import RawConfig
13+
1014
try:
1115
gitlab_token = os.environ["GITLAB_TOKEN"]
1216
except KeyError:
@@ -69,24 +73,37 @@
6973
sys.exit(1)
7074

7175
path_prefix = os.getcwd()
72-
config: dict = {}
76+
config: RawConfig = {}
7377

7478
for group in response.json():
7579
url_to_repo = group["ssh_url_to_repo"].replace(":", "/")
7680
namespace_path = group["namespace"]["full_path"]
7781
reponame = group["path"]
7882

79-
path = "%s/%s" % (path_prefix, namespace_path)
83+
path = f"{path_prefix}/{namespace_path}"
8084

8185
if path not in config:
8286
config[path] = {}
8387

8488
# simplified config not working - https://github.com/vcs-python/vcspull/issues/332
8589
# config[path][reponame] = 'git+ssh://%s' % (url_to_repo)
8690

91+
vcs = guess_vcs(url_to_repo)
92+
if vcs is None:
93+
raise Exception(f"Could not guess VCS for URL: {url_to_repo}")
94+
8795
config[path][reponame] = {
88-
"url": "git+ssh://%s" % (url_to_repo),
89-
"remotes": {"origin": "ssh://%s" % (url_to_repo)},
96+
"name": reponame,
97+
"dir": path / reponame,
98+
"url": f"git+ssh://{url_to_repo}",
99+
"remotes": {
100+
"origin": GitRemote(
101+
name="origin",
102+
fetch_url=f"ssh://{url_to_repo}",
103+
push_url=f"ssh://{url_to_repo}",
104+
)
105+
},
106+
"vcs": vcs,
90107
}
91108

92109
config_yaml = yaml.dump(config)

src/vcspull/_internal/config_reader.py

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ class ConfigReader:
2222
'{\n "session_name": "my session"\n}'
2323
"""
2424

25-
def __init__(self, content: "RawConfigData"):
25+
def __init__(self, content: "RawConfigData") -> None:
2626
self.content = content
2727

2828
@staticmethod
29-
def _load(format: "FormatLiteral", content: str):
29+
def _load(format: "FormatLiteral", content: str) -> t.Dict[str, t.Any]:
3030
"""Load raw config data and directly return it.
3131
3232
>>> ConfigReader._load("json", '{ "session_name": "my session" }')
@@ -36,17 +36,20 @@ def _load(format: "FormatLiteral", content: str):
3636
{'session_name': 'my session'}
3737
"""
3838
if format == "yaml":
39-
return yaml.load(
40-
content,
41-
Loader=yaml.SafeLoader,
39+
return t.cast(
40+
t.Dict[str, t.Any],
41+
yaml.load(
42+
content,
43+
Loader=yaml.SafeLoader,
44+
),
4245
)
4346
elif format == "json":
44-
return json.loads(content)
47+
return t.cast(t.Dict[str, t.Any], json.loads(content))
4548
else:
4649
raise NotImplementedError(f"{format} not supported in configuration")
4750

4851
@classmethod
49-
def load(cls, format: "FormatLiteral", content: str):
52+
def load(cls, format: "FormatLiteral", content: str) -> "ConfigReader":
5053
"""Load raw config data into a ConfigReader instance (to dump later).
5154
5255
>>> cfg = ConfigReader.load("json", '{ "session_name": "my session" }')
@@ -69,7 +72,7 @@ def load(cls, format: "FormatLiteral", content: str):
6972
)
7073

7174
@classmethod
72-
def _from_file(cls, path: pathlib.Path):
75+
def _from_file(cls, path: pathlib.Path) -> t.Dict[str, t.Any]:
7376
r"""Load data from file path directly to dictionary.
7477
7578
**YAML file**
@@ -102,7 +105,7 @@ def _from_file(cls, path: pathlib.Path):
102105
content = open(path).read()
103106

104107
if path.suffix in [".yaml", ".yml"]:
105-
format: FormatLiteral = "yaml"
108+
format: "FormatLiteral" = "yaml"
106109
elif path.suffix == ".json":
107110
format = "json"
108111
else:
@@ -114,7 +117,7 @@ def _from_file(cls, path: pathlib.Path):
114117
)
115118

116119
@classmethod
117-
def from_file(cls, path: pathlib.Path):
120+
def from_file(cls, path: pathlib.Path) -> "ConfigReader":
118121
r"""Load data from file path
119122
120123
**YAML file**
@@ -169,11 +172,14 @@ def _dump(
169172
'{\n "session_name": "my session"\n}'
170173
"""
171174
if format == "yaml":
172-
return yaml.dump(
173-
content,
174-
indent=2,
175-
default_flow_style=False,
176-
Dumper=yaml.SafeDumper,
175+
return t.cast(
176+
str,
177+
yaml.dump(
178+
content,
179+
indent=2,
180+
default_flow_style=False,
181+
Dumper=yaml.SafeDumper,
182+
),
177183
)
178184
elif format == "json":
179185
return json.dumps(

src/vcspull/cli/__init__.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import argparse
88
import logging
99
import textwrap
10+
import typing as t
11+
from typing import overload
1012

1113
from libvcs.__about__ import __version__ as libvcs_version
1214

@@ -30,7 +32,21 @@
3032
).strip()
3133

3234

33-
def create_parser(return_subparsers: bool = False):
35+
@overload
36+
def create_parser(
37+
return_subparsers: t.Literal[True],
38+
) -> t.Tuple[argparse.ArgumentParser, t.Any]:
39+
...
40+
41+
42+
@overload
43+
def create_parser(return_subparsers: t.Literal[False]) -> argparse.ArgumentParser:
44+
...
45+
46+
47+
def create_parser(
48+
return_subparsers: bool = False,
49+
) -> t.Union[argparse.ArgumentParser, t.Tuple[argparse.ArgumentParser, t.Any]]:
3450
parser = argparse.ArgumentParser(
3551
prog="vcspull",
3652
formatter_class=argparse.RawDescriptionHelpFormatter,
@@ -64,9 +80,9 @@ def create_parser(return_subparsers: bool = False):
6480
return parser
6581

6682

67-
def cli(args=None):
83+
def cli(_args: t.Optional[t.List[str]] = None) -> None:
6884
parser, sync_parser = create_parser(return_subparsers=True)
69-
args = parser.parse_args(args)
85+
args = parser.parse_args(_args)
7086

7187
setup_logger(log=log, level=args.log_level.upper())
7288

0 commit comments

Comments
 (0)