-
Notifications
You must be signed in to change notification settings - Fork 17
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
chore: add incremental type checking with mypy #59
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PR sets up mypy to be adopted incrementally in the code base.
Great, thanks!
The idea is: we make mypy ignore all files. We then annotate one file at a time. As we annotate files, we remove them from being ignored by mypy.
Good idea.
The workflow for annotating an extra file is: …
This sounds reasonable as a workflow. I guess it shouldn't take that long either, it is not really so much code.
Do you think this works for you, @lervag?
Yes!
If you're happy with the approach, I will annotate/fix other files and add a type-check step to the Github Action.
Good; I guess adding the type-check step to the GHA could be useful as part of this PR?
Greetings from Hamburg!
Greetings from Norway :)
bda8e5a
to
9414580
Compare
9414580
to
31e988b
Compare
@lervag I have addressed your comments and added mypy to CI. I was also thinking we could make the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was also thinking we could make the cfg dictionary a dataclasses.dataclass eventually.
Seems like a good idea!
I think this is very good! The final thing I'm thinking about is if we should include the tests here?
I was actually planning to make a PR with a refactor of the config to use a dataclass. It's cleaner because you see the fields and the types all in one place. type checker can work with it better than a heterogeneously typed dict. |
the idea is something like this import json
import os
from dataclasses import dataclass, field
from pathlib import Path
from typing import Optional, Any
from platformdirs import user_config_path, user_data_path
def env_path(name: str, must_exist_if_specified=True) -> Optional[Path]:
if (raw_path := os.environ.get(name)) is None:
return None
if must_exist_if_specified and not (path := Path(raw_path)).exists():
raise FileNotFoundError(f"No such path: {name}={path}")
return path
def get_raw_config() -> dict[str, Any]:
cfg_dir = env_path("APY_CONFIG") or user_config_path("apy")
if not (cfg_path := cfg_dir / "apy.json").exists():
return {}
return json.loads(cfg_path.read_text())
def get_base_path() -> Path:
return env_path("APY_BASE") or env_path("ANKI_BASE") or user_data_path("Anki2")
@dataclass
class Config:
base_path: Path = field(default_factory=get_base_path)
img_viewers: dict[str, list[str]] = field(
default_factory=lambda: {"svg": ["display", "-density", "300"]}
)
img_viewers_default: list[str] = field(default_factory=lambda: ["feh"])
markdown_models: list[str] = field(default_factory=lambda: ["Basic"])
presets: dict[str, dict] = field(default_factory=dict)
profile: Optional[str] = None
query: str = "tag:marked OR -flag:0"
def __post_init__(self) -> None:
if not self.base_path.exists():
raise FileNotFoundError(f"Could not find Anki base path: {self.base_path}")
self.base_path = self.base_path.absolute()
self.presets.setdefault("default", {"model": "Basic", "tags": []})
cfg = Config(**get_raw_config()) haven't tested this or modified the other modules to account for the changes yet. |
Would it make more sense for me to push this dataclass config stuff to this PR, or to make a separate one? |
Could you make a new PR? I'll merge this one probably later today. If you make the PR based on this branch and later rebase it on master after this is merged, then it should be quite clean. |
I've merged this now; thanks! |
The PR sets up mypy to be adopted incrementally in the code base.
The idea is: we make mypy ignore all files. We then annotate one file at a time. As we annotate files, we remove them from being ignored by mypy.
I have type-annotated the
apy.config
module while ignoring all other modules.The workflow for annotating an extra file is:
pyproject.toml
mypy src
to identify the violationsDo you think this works for you, @lervag?
If you're happy with the approach, I will annotate/fix other files and add a type-check step to the Github Action.
Looking forward to your feedback.
Greetings from Hamburg!