Skip to content

Commit 70a0586

Browse files
authored
build: enable more linting rules (#57)
1 parent 57eb02e commit 70a0586

File tree

15 files changed

+104
-59
lines changed

15 files changed

+104
-59
lines changed

pyproject.toml

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,33 @@ log_level = "DEBUG"
9494
line-length = 79
9595

9696
[tool.ruff.lint]
97-
select = ["D", "E", "F", "I", "N", "PL", "RUF", "SIM"]
98-
ignore = ["D102", "D103", "D105", "D107", "D415", "PLR2004"]
97+
select = [
98+
"A",
99+
"ANN",
100+
"ARG",
101+
"D",
102+
"E",
103+
"ERA",
104+
"F",
105+
"I",
106+
"INP",
107+
"LOG",
108+
"N",
109+
"PL",
110+
"RUF",
111+
"SIM",
112+
"SLF",
113+
"T20",
114+
"TD",
115+
"UP",
116+
"W"
117+
]
118+
ignore = [
119+
"ANN003", "ANN401",
120+
"D102", "D103", "D105", "D107", "D415",
121+
"PLR2004",
122+
"TD002", "TD003",
123+
]
99124

100125
[tool.ruff.lint.isort]
101126
force-sort-within-sections = true
@@ -105,4 +130,5 @@ lines-after-imports = 2
105130
convention = "google"
106131

107132
[tool.ruff.lint.per-file-ignores]
108-
"tests/**" = ["D"]
133+
"__main__.py" = ["T20"]
134+
"tests/**" = ["ANN", "D", "SLF"]

src/git_draft/__main__.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@
22

33
from __future__ import annotations
44

5+
from collections.abc import Sequence
56
import importlib.metadata
67
import logging
78
import optparse
89
from pathlib import Path, PurePosixPath
910
import sys
10-
from typing import Sequence
1111

1212
from .bots import load_bot
1313
from .common import PROGRAM, Config, UnreachableError, ensure_state_home
1414
from .drafter import Drafter
1515
from .editor import open_editor
16-
from .prompt import Template, TemplatedPrompt, templates_table
16+
from .prompt import Template, TemplatedPrompt, find_template, templates_table
1717
from .store import Store
1818
from .toolbox import ToolVisitor
1919

@@ -41,7 +41,13 @@ def new_parser() -> optparse.OptionParser:
4141
)
4242

4343
def add_command(name: str, short: str | None = None, **kwargs) -> None:
44-
def callback(_option, _opt, _value, parser) -> None:
44+
def callback(
45+
_option: object,
46+
_opt: object,
47+
_value: object,
48+
parser: optparse.OptionParser,
49+
) -> None:
50+
assert parser.values
4551
parser.values.command = name
4652

4753
parser.add_option(
@@ -222,11 +228,11 @@ def main() -> None: # noqa: PLR0912 PLR0915
222228
if table:
223229
print(table.to_json() if opts.json else table)
224230
elif command == "show-prompts":
225-
raise NotImplementedError() # TODO
231+
raise NotImplementedError() # TODO: Implement
226232
elif command == "show-templates":
227233
if args:
228234
name = args[0]
229-
tpl = Template.find(name)
235+
tpl = find_template(name)
230236
if opts.edit:
231237
if tpl:
232238
edit(path=tpl.local_path(), text=tpl.source)

src/git_draft/bots/common.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ class Action:
2929
request_count: int | None = None
3030
token_count: int | None = None
3131

32-
def increment_request_count(self, n=1, init=False) -> None:
32+
def increment_request_count(self, n: int = 1, init: bool = False) -> None:
3333
self._increment("request_count", n, init)
3434

35-
def increment_token_count(self, n, init=False) -> None:
35+
def increment_token_count(self, n: int, init: bool = False) -> None:
3636
self._increment("token_count", n, init)
3737

3838
def _increment(self, attr: str, count: int, init: bool) -> None:
@@ -48,7 +48,7 @@ class Bot:
4848
"""Code assistant bot"""
4949

5050
@classmethod
51-
def state_folder_path(cls, ensure_exists=False) -> Path:
51+
def state_folder_path(cls, ensure_exists: bool = False) -> Path:
5252
"""Returns a path unique to this bot class
5353
5454
The path can be used to store data specific to this bot implementation.

src/git_draft/bots/openai.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@
1212
* https://github.com/openai/openai-python/blob/main/src/openai/resources/beta/threads/runs/runs.py
1313
"""
1414

15+
from collections.abc import Mapping, Sequence
1516
import json
1617
import logging
1718
import os
1819
from pathlib import PurePosixPath
19-
from typing import Any, Mapping, Self, Sequence, TypedDict, override
20+
from typing import Any, Self, TypedDict, override
2021

2122
import openai
2223

@@ -61,7 +62,7 @@ def _param(
6162
name: str,
6263
description: str,
6364
inputs: Mapping[str, Any] | None = None,
64-
required_inputs: Sequence[str] | None = None,
65+
_required_inputs: Sequence[str] | None = None,
6566
) -> openai.types.beta.FunctionToolParam:
6667
param: openai.types.beta.FunctionToolParam = {
6768
"type": "function",
@@ -225,10 +226,10 @@ def _on_read_file(self, path: PurePosixPath, contents: str | None) -> str:
225226
return f"`{path}` does not exist."
226227
return f"The contents of `{path}` are:\n\n```\n{contents}\n```\n"
227228

228-
def _on_write_file(self, path: PurePosixPath) -> None:
229+
def _on_write_file(self, _path: PurePosixPath) -> None:
229230
return None
230231

231-
def _on_delete_file(self, path: PurePosixPath) -> None:
232+
def _on_delete_file(self, _path: PurePosixPath) -> None:
232233
return None
233234

234235
def _on_list_files(self, paths: Sequence[PurePosixPath]) -> str:
@@ -316,7 +317,7 @@ def on_run_step_done(
316317
else:
317318
_logger.warning("Missing usage in threads run step")
318319

319-
def _handle_action(self, run_id: str, data: Any) -> None:
320+
def _handle_action(self, _run_id: str, data: Any) -> None:
320321
tool_outputs = list[Any]()
321322
for tool in data.required_action.submit_tool_outputs.tool_calls:
322323
handler = _ThreadToolHandler(self._toolbox, tool.id)
@@ -347,15 +348,15 @@ def _wrap(self, output: str) -> _ToolOutput:
347348
return _ToolOutput(tool_call_id=self._call_id, output=output)
348349

349350
def _on_read_file(
350-
self, path: PurePosixPath, contents: str | None
351+
self, _path: PurePosixPath, contents: str | None
351352
) -> _ToolOutput:
352353
return self._wrap(contents or "")
353354

354-
def _on_write_file(self, path: PurePosixPath) -> _ToolOutput:
355+
def _on_write_file(self, _path: PurePosixPath) -> _ToolOutput:
355356
return self._wrap("OK")
356357

357-
def _on_delete_file(self, path: PurePosixPath) -> _ToolOutput:
358+
def _on_delete_file(self, _path: PurePosixPath) -> _ToolOutput:
358359
return self._wrap("OK")
359360

360361
def _on_list_files(self, paths: Sequence[PurePosixPath]) -> _ToolOutput:
361-
return self._wrap("\n".join((str(p) for p in paths)))
362+
return self._wrap("\n".join(str(p) for p in paths))

src/git_draft/common.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from __future__ import annotations
44

5+
from collections.abc import Mapping, Sequence
56
import dataclasses
67
import itertools
78
import logging
@@ -11,7 +12,7 @@
1112
import string
1213
import textwrap
1314
import tomllib
14-
from typing import Any, ClassVar, Mapping, Self, Sequence, Type
15+
from typing import Any, ClassVar, Self
1516

1617
import prettytable
1718
import xdg_base_dirs
@@ -84,7 +85,7 @@ class UnreachableError(RuntimeError):
8485
"""Indicates unreachable code was unexpectedly executed"""
8586

8687

87-
def reindent(s: str, width=0) -> str:
88+
def reindent(s: str, width: int = 0) -> str:
8889
"""Reindents text by dedenting and optionally wrapping paragraphs"""
8990
paragraphs = (
9091
" ".join(textwrap.dedent("\n".join(g)).splitlines())
@@ -96,7 +97,7 @@ def reindent(s: str, width=0) -> str:
9697
)
9798

9899

99-
def qualified_class_name(cls: Type) -> str:
100+
def qualified_class_name(cls: type) -> str:
100101
name = cls.__qualname__
101102
return f"{cls.__module__}.{name}" if cls.__module__ else name
102103

src/git_draft/drafter.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from __future__ import annotations
44

5+
from collections.abc import Callable, Sequence
56
import dataclasses
67
from datetime import datetime
78
import json
@@ -10,9 +11,9 @@
1011
import os.path as osp
1112
from pathlib import PurePosixPath
1213
import re
14+
from re import Match
1315
import textwrap
1416
import time
15-
from typing import Callable, Match, Sequence
1617

1718
import git
1819

@@ -53,7 +54,7 @@ def active(cls, repo: git.Repo, name: str | None = None) -> _Branch | None:
5354
return _Branch(match[1])
5455

5556
@staticmethod
56-
def new_suffix():
57+
def new_suffix() -> str:
5758
return random_id(9)
5859

5960

@@ -85,7 +86,7 @@ def generate_draft( # noqa: PLR0913
8586
timeout: float | None = None,
8687
) -> str:
8788
if timeout is not None:
88-
raise NotImplementedError() # TODO
89+
raise NotImplementedError() # TODO: Implement
8990

9091
if self._repo.is_dirty(working_tree=False):
9192
if not reset:
@@ -174,7 +175,9 @@ def generate_draft( # noqa: PLR0913
174175
_logger.info("Completed generation for %s.", branch)
175176
return str(branch)
176177

177-
def exit_draft(self, *, revert: bool, clean=False, delete=False) -> str:
178+
def exit_draft(
179+
self, *, revert: bool, clean: bool = False, delete: bool = False
180+
) -> str:
178181
branch = _Branch.active(self._repo)
179182
if not branch:
180183
raise RuntimeError("Not currently on a draft branch")
@@ -312,7 +315,7 @@ def _untracked(self) -> frozenset[str]:
312315
text = self._repo.git.ls_files(exclude_standard=True, others=True)
313316
return frozenset(text.splitlines())
314317

315-
def _delta(self, spec) -> _Delta:
318+
def _delta(self, spec: str) -> _Delta:
316319
changed = list[str]()
317320
deleted = list[str]()
318321
for line in self._repo.git.diff(spec, name_status=True).splitlines():

src/git_draft/editor.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,16 @@ def _guess_editor_binpath() -> str:
2222
return ""
2323

2424

25-
def _get_tty_filename():
25+
def _get_tty_filename() -> str:
2626
return "CON:" if sys.platform == "win32" else "/dev/tty"
2727

2828

29-
def open_editor(text="", path: Path | None = None, *, _open_tty=open) -> str:
29+
def open_editor(
30+
text: str = "",
31+
path: Path | None = None,
32+
*,
33+
_open_tty=open, # noqa
34+
) -> str:
3035
"""Open an editor to edit a file and return its contents
3136
3237
The method returns once the editor is closed. It respects the `$EDITOR`
@@ -46,7 +51,7 @@ def edit(path: str) -> str:
4651
proc = subprocess.Popen([binpath, path], close_fds=True, stdout=stdout)
4752
proc.communicate()
4853

49-
with open(path, mode="r") as reader:
54+
with open(path) as reader:
5055
return reader.read()
5156

5257
if path:

src/git_draft/prompt.py

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22

33
from __future__ import annotations
44

5+
from collections.abc import Mapping
56
import dataclasses
67
import enum
78
import itertools
89
import os
910
from pathlib import Path
10-
from typing import Mapping, Self
11+
from typing import Self
1112

1213
import jinja2
1314
import jinja2.meta
@@ -72,7 +73,7 @@ def templates_table() -> Table:
7273
for rel_path in env.list_templates(extensions=[_extension]):
7374
if any(p.startswith(".") for p in rel_path.split(os.sep)):
7475
continue
75-
tpl = Template._load(rel_path, env)
76+
tpl = _load_template(rel_path, env)
7677
local = "y" if tpl.is_local() else "n"
7778
table.data.add_row([tpl.name, local, tpl.preamble or "-"])
7879
return table
@@ -95,6 +96,22 @@ def _extract_preamble(source: str, env: jinja2.Environment) -> str | None:
9596
return None
9697

9798

99+
def _load_template(rel_path: str, env: jinja2.Environment) -> Template:
100+
assert env.loader, "No loader in environment"
101+
source, abs_path, _uptodate = env.loader.get_source(env, rel_path)
102+
assert abs_path, "Missing template path"
103+
preamble = _extract_preamble(source, env)
104+
return Template(Path(rel_path), Path(abs_path), source, preamble)
105+
106+
107+
def find_template(name: str) -> Template | None:
108+
env = _jinja_environment()
109+
try:
110+
return _load_template(f"{name}.{_extension}", env)
111+
except jinja2.TemplateNotFound:
112+
return None
113+
114+
98115
@dataclasses.dataclass(frozen=True)
99116
class Template:
100117
"""An available template"""
@@ -126,22 +143,6 @@ def extract_variables(self, env: jinja2.Environment) -> frozenset[str]:
126143
ast = env.parse(self.source)
127144
return frozenset(jinja2.meta.find_undeclared_variables(ast))
128145

129-
@classmethod
130-
def _load(cls, rel_path: str, env: jinja2.Environment) -> Self:
131-
assert env.loader, "No loader in environment"
132-
source, abs_path, _uptodate = env.loader.get_source(env, rel_path)
133-
assert abs_path, "Missing template path"
134-
preamble = _extract_preamble(source, env)
135-
return cls(Path(rel_path), Path(abs_path), source, preamble)
136-
137-
@classmethod
138-
def find(cls, name: str) -> Self | None:
139-
env = _jinja_environment()
140-
try:
141-
return cls._load(f"{name}.{_extension}", env)
142-
except jinja2.TemplateNotFound:
143-
return None
144-
145146
@staticmethod
146147
def local_path_for(name: str) -> Path:
147148
return _PromptFolder.LOCAL.path / Path(f"{name}.{_extension}")

src/git_draft/store.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
"""Persistent state storage"""
22

3+
from collections.abc import Iterator
34
import contextlib
45
from datetime import datetime
56
import functools
67
import sqlite3
7-
from typing import Iterator, Self
8+
from typing import Self
89

910
from .common import ensure_state_home, package_root
1011

src/git_draft/toolbox.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22

33
from __future__ import annotations
44

5+
from collections.abc import Callable, Sequence
56
import logging
67
from pathlib import PurePosixPath
78
import tempfile
8-
from typing import Callable, Protocol, Sequence, override
9+
from typing import Protocol, override
910

1011
import git
1112

0 commit comments

Comments
 (0)