Skip to content

Commit 4ea05b9

Browse files
committed
type-checking: also use ty
ty is quite fast and also brings a performant language server
1 parent b12a90c commit 4ea05b9

21 files changed

+144
-56
lines changed

.github/workflows/test.yml

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ jobs:
9494
- run: uv run --no-dev --group pre-commit pre-commit run -a eslint
9595
- run: cd frontend; npx tsc
9696
- run: cd frontend; npx svelte-check
97-
lint-python:
97+
lint-python-mypy:
9898
runs-on: "ubuntu-latest"
9999
steps:
100100
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
@@ -108,3 +108,17 @@ jobs:
108108
enable-cache: false
109109
- run: touch src/fava/static/app.js
110110
- run: make mypy
111+
lint-python-ty:
112+
runs-on: "ubuntu-latest"
113+
steps:
114+
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
115+
with:
116+
persist-credentials: false
117+
- uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
118+
with:
119+
python-version: "3.13"
120+
- uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6
121+
with:
122+
enable-cache: false
123+
- run: touch src/fava/static/app.js
124+
- run: make ty

Makefile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ mostlyclean:
4444

4545
# Run linters.
4646
.PHONY: lint
47-
lint: frontend/node_modules mypy
47+
lint: frontend/node_modules ty
4848
uv run pre-commit run -v -a
4949
cd frontend; npm exec tsc
5050
cd frontend; npm exec svelte-check
@@ -54,6 +54,11 @@ lint: frontend/node_modules mypy
5454
mypy:
5555
uv run --no-dev --group mypy mypy
5656

57+
# Run ty for Python type-checking.
58+
.PHONY: ty
59+
ty:
60+
uv run --no-dev --group ty ty check
61+
5762
# Run tests.
5863
.PHONY: test test-js test-py test-py-old-deps
5964
test: test-js test-py

pyproject.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,14 @@ mypy = [
8383
"types-setuptools>=67",
8484
"types-simplejson>=3",
8585
]
86+
# Type-checking with ty.
87+
ty = [
88+
"ty>=0.0.2",
89+
"pytest>=8",
90+
"types-requests>=2.32.0.20250515",
91+
"types-setuptools>=67",
92+
"types-simplejson>=3",
93+
]
8694
# Add setuptools for the old_deps constraints
8795
# (otherwise it is not added to the constraints as it's only a build dependency).
8896
old-deps = [
@@ -108,6 +116,7 @@ dev = [
108116
{ include-group = "mypy" },
109117
{ include-group = "pre-commit" },
110118
{ include-group = "test" },
119+
{ include-group = "ty" },
111120
"ruff>=0.11",
112121
]
113122

@@ -142,6 +151,14 @@ where = ["src"]
142151
line-length = 79
143152
preview = true
144153

154+
[tool.ty.environment]
155+
python-version = "3.12"
156+
157+
[tool.ty.src]
158+
exclude = [
159+
"src/fava/core/ingest.py",
160+
]
161+
145162
[tool.mypy]
146163
mypy_path = "stubs"
147164
strict = true

src/fava/application.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ def ledgers(self) -> list[FavaLedger]:
149149
# avoid loading it already loaded while waiting for the lock
150150
if self._ledgers is None: # pragma: no cover
151151
self._ledgers = self._load()
152-
return self._ledgers
152+
return self._ledgers # ty:ignore[invalid-return-type]
153153

154154
@property
155155
def ledgers_by_slug(self) -> dict[str, FavaLedger]:
@@ -379,7 +379,7 @@ def extension_report(extension_name: str) -> str:
379379
"""Endpoint for extension reports."""
380380
ext = g.ledger.extensions.get_extension(extension_name)
381381
if ext is None or ext.report_title is None:
382-
abort(404)
382+
return abort(404)
383383

384384
g.extension = ext
385385
template = ext.jinja_env.get_template(f"{ext.name}.html")
@@ -415,7 +415,7 @@ def download_journal() -> Response:
415415
def help_page(page_slug: str) -> str:
416416
"""Fava's included documentation."""
417417
if page_slug not in HELP_PAGES:
418-
abort(404)
418+
return abort(404)
419419
help_path = Path(__file__).parent / "help" / (page_slug + ".md")
420420
contents = help_path.read_text(encoding="utf-8")
421421
html = markdown2.markdown(

src/fava/beans/create.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def amount(amt: Amount | Decimal | str, currency: str | None = None) -> Amount:
4848
if isinstance(amt, str):
4949
return BEANCOUNT_A(amt) # type: ignore[return-value]
5050
if hasattr(amt, "number") and hasattr(amt, "currency"):
51-
return amt
51+
return amt # ty:ignore[invalid-return-type]
5252
if not isinstance(currency, str): # pragma: no cover
5353
raise TypeError
5454
return BeancountAmount(amt, currency) # type: ignore[return-value]

src/fava/core/__init__.py

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -330,46 +330,58 @@ class FavaLedger:
330330
#: Dict of list of all (unfiltered) entries by type.
331331
all_entries_by_type: EntriesByType
332332

333+
#: A :class:`.AccountDict` module - details about the accounts.
334+
accounts: AccountDict
335+
336+
#: An :class:`AttributesModule` instance.
337+
attributes: AttributesModule
338+
339+
#: A :class:`.BudgetModule` instance.
340+
budgets: BudgetModule
341+
342+
#: A :class:`.ChartModule` instance.
343+
charts: ChartModule
344+
345+
#: A :class:`.CommoditiesModule` instance.
346+
commodities: CommoditiesModule
347+
348+
#: A :class:`.ExtensionModule` instance.
349+
extensions: ExtensionModule
350+
351+
#: A :class:`.FileModule` instance.
352+
file: FileModule
353+
354+
#: A :class:`.DecimalFormatModule` instance.
355+
format_decimal: DecimalFormatModule
356+
357+
#: A :class:`.IngestModule` instance.
358+
ingest: IngestModule
359+
360+
#: A :class:`.FavaMisc` instance.
361+
misc: FavaMisc
362+
363+
#: A :class:`.QueryShell` instance.
364+
query_shell: QueryShell
365+
333366
def __init__(self, path: str, *, poll_watcher: bool = False) -> None:
334367
#: The path to the main Beancount file.
335368
self.beancount_file_path = path
336369
self._is_encrypted = is_encrypted_file(path)
337370
self.get_filtered = lru_cache(maxsize=16)(self._get_filtered)
338371
self.get_entry = lru_cache(maxsize=16)(self._get_entry)
339372

340-
#: An :class:`AttributesModule` instance.
373+
self.accounts = AccountDict(self)
341374
self.attributes = AttributesModule(self)
342-
343-
#: A :class:`.BudgetModule` instance.
344375
self.budgets = BudgetModule(self)
345-
346-
#: A :class:`.ChartModule` instance.
347376
self.charts = ChartModule(self)
348-
349-
#: A :class:`.CommoditiesModule` instance.
350377
self.commodities = CommoditiesModule(self)
351-
352-
#: A :class:`.ExtensionModule` instance.
353378
self.extensions = ExtensionModule(self)
354-
355-
#: A :class:`.FileModule` instance.
356379
self.file = FileModule(self)
357-
358-
#: A :class:`.IngestModule` instance.
380+
self.format_decimal = DecimalFormatModule(self)
359381
self.ingest = IngestModule(self)
360-
361-
#: A :class:`.FavaMisc` instance.
362382
self.misc = FavaMisc(self)
363-
364-
#: A :class:`.DecimalFormatModule` instance.
365-
self.format_decimal = DecimalFormatModule(self)
366-
367-
#: A :class:`.QueryShell` instance.
368383
self.query_shell = QueryShell(self)
369384

370-
#: A :class:`.AccountDict` module - details about the accounts.
371-
self.accounts = AccountDict(self)
372-
373385
self.watcher = WatchfilesWatcher() if not poll_watcher else Watcher()
374386

375387
self.load_file()

src/fava/core/filters.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ def __init__(self, value: str) -> None:
437437
tokens = LEXER.lex(value)
438438
self._include = PARSE(
439439
lexer="NONE",
440-
tokenfunc=lambda toks=tokens: next(toks, None),
440+
tokenfunc=lambda toks=tokens: next(toks, None), # ty:ignore[invalid-argument-type]
441441
)
442442
except FilterError as exception:
443443
exception.message += value

src/fava/core/query_shell.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,9 @@ def noop(self, _: T) -> None:
127127
print(self.noop.__doc__, file=self.outfile)
128128

129129
on_Reload = noop # noqa: N815
130-
do_exit = noop
130+
do_exit = noop # ty:ignore[invalid-method-override]
131131
do_quit = noop
132-
do_EOF = noop # noqa: N815
132+
do_EOF = noop # noqa: N815 # ty:ignore[invalid-method-override]
133133

134134
def on_Select(self, statement: str) -> Cursor: # noqa: D102, N802
135135
return self.context.execute(statement)

src/fava/ext/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -219,14 +219,14 @@ def decorator(
219219
func: Callable[[T], Response],
220220
) -> Callable[[T], Response]:
221221
f: Any = func
222-
f.endpoint_key = (
223-
endpoint_name or func.__name__,
222+
f.endpoint_key = ( # ty:ignore[unresolved-attribute]
223+
endpoint_name or func.__name__, # ty:ignore[unresolved-attribute]
224224
methods or ["GET"],
225225
)
226226
return func
227227

228228
return (
229-
decorator(func_or_endpoint_name)
229+
decorator(func_or_endpoint_name) # ty:ignore[invalid-argument-type]
230230
if callable(func_or_endpoint_name)
231231
else decorator
232232
)

src/fava/ext/auto_commit.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,17 @@ def _run(self, args: list[str]) -> None:
2424
cwd = Path(self.ledger.beancount_file_path).parent
2525
call(args, cwd=cwd, stdout=DEVNULL)
2626

27-
def after_write_source(self, path: str, _source: str) -> None:
27+
def after_write_source(self, path: str, source: str) -> None: # noqa: ARG002
2828
"""Add changed file to git and commit."""
2929
message = "autocommit: file saved"
3030
self._run(["git", "add", path])
3131
self._run(["git", "commit", "-m", message])
3232

3333
def after_insert_metadata(
3434
self,
35-
_entry: Directive,
36-
_key: str,
37-
_value: str,
35+
entry: Directive, # noqa: ARG002
36+
key: str, # noqa: ARG002
37+
value: str, # noqa: ARG002
3838
) -> None:
3939
"""Commit all changes on `after_insert_metadata`."""
4040
message = "autocommit: metadata added"
@@ -50,7 +50,7 @@ def after_delete_entry(self, entry: Directive) -> None:
5050
message = f"autocommit: deleted entry on {entry.date}"
5151
self._run(["git", "commit", "-am", message])
5252

53-
def after_entry_modified(self, entry: Directive, _new_lines: str) -> None:
53+
def after_entry_modified(self, entry: Directive, new_lines: str) -> None: # noqa: ARG002
5454
"""Commit all changes on `after_entry_modified`."""
5555
message = f"autocommit: modified entry on {entry.date}"
5656
self._run(["git", "commit", "-am", message])

0 commit comments

Comments
 (0)