-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathpyproject.toml
More file actions
543 lines (527 loc) · 26.2 KB
/
Copy pathpyproject.toml
File metadata and controls
543 lines (527 loc) · 26.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "yazses"
version = "2.36.0"
description = "Local, offline-by-default voice dictation for Linux, macOS, and Windows — hold a key, speak, release"
readme = "README.md"
license = {text = "Apache-2.0"}
requires-python = ">=3.11"
authors = [
{name = "Mohsen Seyedkazemi Ardebili", email = "mohsen.seyedkazemi@gmail.com"},
]
keywords = [
"voice",
"dictation",
"voice-dictation",
"voice-typing",
"voice-commands",
"speech-to-text",
"speech-recognition",
"whisper",
"faster-whisper",
"hold-to-talk",
"offline",
"on-device",
"privacy",
"cross-platform",
"linux",
"macos",
"windows",
"accessibility",
"wayland",
"x11",
"transcription",
"speaker-diarization",
"meeting-notes",
"open-source",
]
classifiers = [
"Development Status :: 3 - Alpha",
"Environment :: No Input/Output (Daemon)",
"Intended Audience :: End Users/Desktop",
"License :: OSI Approved :: Apache Software License",
"Operating System :: POSIX :: Linux",
"Operating System :: MacOS :: MacOS X",
"Operating System :: Microsoft :: Windows",
# One line per interpreter the test matrix actually runs the suite on --
# no more, no less. PyPI renders these as the project's own answer to "does
# this run on my Python?", and packagers filter on them without ever seeing
# the CI matrix, so drift here is a wrong answer given to the people least
# able to check it. 3.13 and 3.14 were green for weeks while these two lines
# still said otherwise. `tests/test_platform_support_claims.py` holds both
# directions of this invariant, so adding a matrix entry without a classifier
# (or a classifier without a matrix entry) now fails the suite.
#
# Deliberately absent: `Operating System :: POSIX :: BSD`. A BSD backend
# ships and is unit-tested, but `pip install yazses` cannot succeed there --
# ctranslate2 has no BSD wheel and no sdist (#306) -- and a classifier says
# the install works. Same test guards that omission.
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Topic :: Multimedia :: Sound/Audio :: Speech",
]
dependencies = [
"faster-whisper>=1.2.1",
"sounddevice>=0.5.5",
"numpy>=2.4.6",
"typer>=0.26.8",
"platformdirs>=4.10.0",
# Linux
# evdev stays Linux-only on purpose: it is a C extension compiled against
# <linux/input.h>. FreeBSD exposes /dev/input/event* with EVDEV_SUPPORT, but
# python-evdev does not build there, so BSD falls back to the X11 grab path.
'evdev>=1.9.3; sys_platform == "linux"',
# python-xlib is pure Python and works anywhere X11 does, so the BSDs get it
# too — it is the only hotkey backend available to them.
#
# Matched on platform_system, NOT sys_platform: sys_platform carries the major
# version on a BSD ("freebsd14", "freebsd15"), and PEP 508 markers have no
# prefix operator, so a sys_platform list would silently stop matching at the
# next FreeBSD release. platform_system is the unversioned "FreeBSD".
'python-xlib>=0.33; sys_platform == "linux" or platform_system == "FreeBSD" or platform_system == "OpenBSD" or platform_system == "NetBSD" or platform_system == "DragonFly"',
# macOS
'pyobjc-framework-Quartz>=12.2.1; sys_platform == "darwin"',
'pyobjc-framework-Cocoa>=12.2.1; sys_platform == "darwin"',
'pyobjc-framework-ApplicationServices>=12.2.1; sys_platform == "darwin"',
'pyobjc-framework-AVFoundation>=12.2.1; sys_platform == "darwin"',
'rumps>=0.4.0; sys_platform == "darwin"',
# Windows
'pywin32>=312; sys_platform == "win32"',
'pystray>=0.19.5; sys_platform == "win32"',
'Pillow>=12.3.0; sys_platform == "win32"',
# NOTE: onnx-asr is deliberately NOT here. It is the `parakeet` extra
# (`onnx-asr[cpu,hub]`), imported lazily by stt/parakeet.py; stt/factory.py falls
# back to faster-whisper with a warning when it is absent, and
# `yazses features enable stt-parakeet` installs it on demand. Listing it in the
# base install forced an ONNX runtime on every user of the default engine, and
# made the package unbuildable for distros that have no onnx-asr (see the AUR work).
"cryptography>=50.0.0",
# NOTE: PySide6 is deliberately NOT here. It is 648 MB of Qt -- 59% of a 1.1 GB
# install -- and it exists only for two desktop features (the voice-activity
# overlay and the system tray). Every headless install was paying for it and
# could not use any of it: servers, containers, CI, and anyone who only runs
# `yazses transcribe`, which never imports it.
#
# It lives in the `desktop` extra instead. Every documented install path
# (install.sh, the .deb, the Snap) asks for that extra, so a normal desktop
# install is unchanged; `yazses features enable overlay|tray` installs it
# on demand; and every import site is already lazy and degrades with a hint.
# See docs/install-cost.md and issue #259.
]
[project.urls]
Homepage = "https://github.com/MSKazemi/yazses"
Documentation = "https://mskazemi.com/yazses/"
Repository = "https://github.com/MSKazemi/yazses"
"Bug Tracker" = "https://github.com/MSKazemi/yazses/issues"
[project.scripts]
yazses = "yazses.cli:main"
yazses-daemon = "yazses.main:run"
yazses-agent = "yazses.remote.agent:main"
# Windowed programs. On Windows, pip builds a console launcher for
# [project.scripts] and a pythonw launcher for [project.gui-scripts] — so
# listing these above meant a console window appeared behind the tray, the
# settings window and the overlay, and popped up at every login (Windows
# autostart runs yazses-tray.exe). Identical to [project.scripts] on Linux and
# macOS, where the two tables generate the same launcher.
#
# Each of these run() functions calls system.wincon.ensure_streams() first: a
# GUI launcher has no console, so sys.stderr is None and logging.basicConfig
# would raise on its first line.
[project.gui-scripts]
yazses-tray = "yazses.tray.app:run"
yazses-settings = "yazses.settingsui.app:run"
yazses-overlay = "yazses.overlay.app:run"
[project.optional-dependencies]
slm = [
"llama-cpp-python>=0.3.33",
]
lsp = [
"pygls>=2.1.1",
"pynvim>=0.6.0",
]
emg = [
"pyserial>=3.5",
]
ble = [
"bleak>=3.0.2",
]
overlay = [
"PySide6>=6.11.1",
]
# Everything the desktop experience needs beyond the headless core. Kept as a
# named alias of `overlay` so install paths can ask for intent ("I have a
# desktop") rather than for a widget, and so adding a second desktop-only
# dependency later does not mean editing every installer again.
desktop = [
"PySide6>=6.11.1",
]
prosody = [
"praat-parselmouth>=0.4.7",
]
# Simplified/Traditional Han conversion for `[stt] chinese_script`. Whisper picks
# a Han script per utterance and is not consistent, so Chinese output needs
# normalising to the one the user actually writes in. Pure Python, no compiled
# extension — imported lazily by postprocess/han_script.py.
chinese = [
"opencc-python-reimplemented>=0.1.7",
]
tts = [
"kokoro-onnx>=0.5.0",
"onnxruntime>=1.27.0; sys_platform != 'darwin' or platform_machine != 'x86_64'",
# Intel macOS: onnxruntime stopped publishing an x86_64 wheel after 1.23.0
# (1.24 through 1.28 are macosx_14_0_arm64 only; 1.23.2 is the last with
# macosx_13_0_x86_64). A bare `>=1.27` floor is not a
# preference there, it is an install failure -- uv reports "no source
# distribution or wheel for the current platform", which reads like a broken
# package rather than a dropped platform. See `[tool.uv]` below.
"onnxruntime>=1.23.2,<1.24; sys_platform == 'darwin' and platform_machine == 'x86_64'",
"soundfile>=0.14.0",
]
# EMG device breadth (#103). BrainFlow is MIT, offline and Linux-native, and
# covers OpenBCI/Muse and friends behind one API. Imported lazily; absent or
# unplugged degrades to a logged no-op, exactly like the serial YESP path.
emg-band = [
"brainflow>=5.22.2",
]
# Real-time noise suppression before STT (ADR-v2-015, #69). Spectral gating over
# numpy + scipy — no torch, no numpy ceiling. DeepFilterNet is deliberately NOT
# here: its latest release pins numpy<2.0 against this project's numpy>=2.4.6, so
# an extra for it could never install.
denoise = [
"noisereduce>=3.0.3",
]
# v2 cognitive layer — speaker voiceprint (Cocktail Filter + Voiceprint Mind)
voiceprint = [
"speechbrain>=1.1",
]
# The alternative embedder behind `[voiceprint] backend = "resemblyzer"`: GE2E
# 256-d d-vectors, ~17 MB of weights. Declared separately from `voiceprint`
# rather than folded into it because the two are *alternatives* — only one
# backend runs — and merging them would make every ECAPA user download a second
# model stack they never load.
voiceprint-resemblyzer = [
"resemblyzer>=0.1.4",
# ⚠ This extra needs `pkg_resources` and there is deliberately NO `setuptools<81`
# pin here any more. Resemblyzer requires `webrtcvad`, whose first line is
# `import pkg_resources`; setuptools removed that package outright (verified:
# 80.10.2 has it, 83.0.0 and 84.0.0 do not), so `from resemblyzer import
# VoiceEncoder` raises ModuleNotFoundError on a current setuptools.
#
# The pin was here and had to go, because `uv.lock` is a **universal**
# resolution: one version per package for the whole workspace. A pin inside an
# opt-in extra is not confined to that extra — it held the *base* install down
# too. `uv export --no-dev` (no extras at all) emitted `setuptools==80.10.2`,
# because core `ctranslate2` requires setuptools and there is only one entry to
# satisfy. `scripts/build-macos.sh` and `scripts/build-windows.ps1` build the
# shipped .dmg and .exe from that lock, so it went into release artifacts.
# Without the pin the lock takes 84.0.0, above the 83.0.0 that patches
# Dependabot alert #9.
#
# What the extra loses is nothing silent: `voiceprint/factory.py` already
# distinguishes "installed but cannot import" from "absent" and reports the
# ModuleNotFoundError, so a user who deliberately installs this backend is told
# what happened and can `pip install "setuptools<81"` in their own environment.
# A self-describing failure in one opt-in alternative backend is worth more than
# holding every install and every shipped bundle below a security patch.
# Pinning below the removal is upstream's own advice -- the deprecation
# warning reads "pin to Setuptools<81" verbatim -- and the maintained fork
# `webrtcvad-wheels` is not an alternative: it installs a *second* distribution
# owning the `webrtcvad` module name alongside the one resemblyzer pulls in by
# name, and two dists owning one module is a worse failure than the one being
# fixed. So the advice is correct and it simply cannot be taken *here*, in a
# file whose pins are resolved for everybody. It belongs in the environment of
# whoever chooses this backend, and `docs/` and the factory's message say so.
]
# Pluggable STT — NVIDIA Parakeet TDT via onnx-asr (`[stt] engine = "parakeet"`,
# `yazses features enable stt-parakeet`). onnxruntime only, no torch, no NeMo;
# imported lazily by stt/parakeet.py — absent → stt/factory.py falls back to
# faster-whisper with a warning. [hub] adds huggingface-hub for the model download.
parakeet = [
"onnx-asr[cpu,hub]>=0.12",
]
# Moonshine STT (#74, `[stt] engine = "moonshine"`, `yazses features enable
# stt-moonshine`). onnxruntime + tokenizers only — no torch, no numpy ceiling.
# Declared here because `system/features.py` installs it on enable, and a package
# that only that map knows about is a package no extra, no `all`, and no
# dependency-budget rule can see.
moonshine = [
"useful-moonshine-onnx>=20251121",
]
# Wave O — Diarized Recording Import (ADR-v2-125). sherpa-onnx carries ONNX Runtime
# with it (no torch, no GPU, no HF token); imported lazily only when
# `[recimport] diarize`. Audio decoding needs no extra (PyAV rides in with
# faster-whisper).
#
# `sherpa-onnx-core` is named explicitly even though `sherpa-onnx` depends on it.
# It holds the native libraries -- libonnxruntime.so and the two sherpa .so files --
# and the split is invisible to the resolver: the wheel's METADATA declares
# `Requires-Dist: sherpa-onnx-core`, the sdist's PKG-INFO does not, and uv locked
# the sdist's view while installing the wheel. So `uv sync --extra diarization`
# installed the Python bindings with no runtime underneath them and
# `import sherpa_onnx` raised `ImportError: libonnxruntime.so: cannot open shared
# object file` on every platform.
#
# That failure was invisible twice over: `build_diarizer` catches it and degrades to
# an unattributed transcript, and `diarization_status` decides "installed" with
# `importlib.util.find_spec`, which finds a package that cannot actually import --
# so `meeting start`'s "no silent un-attributed transcript" warning stayed silent.
# Pinning the floor alone does not fix it; the dependency has to be named here.
diarization = [
"sherpa-onnx>=1.13.6",
"sherpa-onnx-core>=1.13.6",
]
# The accuracy alternative behind `[recimport]`/`[meeting] backend = "pyannote"`.
# Kept out of `diarization` (and out of `all`) on purpose: it pulls the whole
# torch stack, and its pretrained pipeline is a *gated* Hugging Face repo whose
# conditions have to be accepted once by hand — so it can never be a dependency
# that installs silently underneath someone. sherpa stays the default.
diarization-pyannote = [
"pyannote.audio>=4.0.7",
]
# Meeting Mode minutes (ADR-v2-128). Optional local-LLM notes at `yazses meeting stop`;
# imported lazily only when `[meeting] notes = true` AND `[meeting] notes_model` points at
# a local GGUF. Recommended models (Q4_K_M, CPU-fit): Phi-4-mini-instruct or Qwen2.5-3B.
# Same runtime as the `slm` extra; declared separately so `yazses[notes]` reads by intent.
notes = [
"llama-cpp-python>=0.3.33",
]
# Meeting Mode neural VAD (ADR-v2-127 P4). Optional Silero VAD for utterance
# segmentation in noisier rooms; imported lazily only when `[meeting] vad_backend =
# "silero"`. ONNX path (no torch). Absent → the calibrated RMS gate is used instead.
silero = [
"silero-vad>=5.1.2",
"onnxruntime>=1.27.0; sys_platform != 'darwin' or platform_machine != 'x86_64'",
# Intel macOS: onnxruntime stopped publishing an x86_64 wheel after 1.23.0
# (1.24 through 1.28 are macosx_14_0_arm64 only; 1.23.2 is the last with
# macosx_13_0_x86_64). A bare `>=1.27` floor is not a
# preference there, it is an install failure -- uv reports "no source
# distribution or wheel for the current platform", which reads like a broken
# package rather than a dropped platform. See `[tool.uv]` below.
"onnxruntime>=1.23.2,<1.24; sys_platform == 'darwin' and platform_machine == 'x86_64'",
]
# v2.0.0 Wave B — Voice-to-Tool / offline Spoken MCP (ADR-v2-006). Heavy; opt-in.
# The MCP client is imported lazily only when [agent] enabled; absent → dormant.
agent = [
"mcp>=1.28.1",
]
# v2.0.0 Wave B — AT-SPI Voice Pilot (ADR-v2-007). Linux only. pyatspi ships via
# system packages (e.g. `apt install python3-pyatspi gir1.2-atspi-2.0`), NOT pip,
# so it is intentionally NOT declared here; the backend imports it lazily when
# [pilot] enabled → absent means Voice Pilot stays dormant.
# v2 cognitive layer — Glance-Type look-to-pane (webcam gaze).
# Default backend is MediaPipe FaceLandmarker (light, CPU-only, no torch); it
# downloads a ~3.7 MB model once on first use. The heavier L2CS backend pins an
# older torch that conflicts with a unified resolution, so it is intentionally
# NOT declared — install it manually (`pip install "l2cs>=2.0"`) only if you set
# `[gaze] backend = "l2cs"`. Gaze deps are imported lazily; absent → dormant.
gaze = [
"mediapipe>=0.10.35",
"opencv-python>=5.0",
]
# "Just give me the lot." This list is the union of every other extra minus exactly one
# exclusion, and tests/test_the_all_extra_is_the_union_it_claims.py computes that equality
# on every run. It was hand-maintained until 2026-08-23 and had silently fallen eight
# extras behind: `pip install yazses[all]` shipped no denoise, no Chinese script
# normalisation, no Silero VAD, no Moonshine, no EMG band, no MCP agent and no pyannote
# diarization. Nothing computed the claim, so nothing noticed.
#
# THE EXCLUSION LIST -- add here only with a reason that survives being read out loud:
#
# voiceprint-resemblyzer -- it needs `pkg_resources`, which no current setuptools
# ships, so on a modern environment it installs and cannot import. It used to
# carry a `setuptools<81` pin to prevent that; the pin is gone because a
# universal lock resolves one setuptools for everyone, so it was holding the
# base install and both shipped bundles below a security patch (see its comment
# above). No capability is lost by the exclusion either way: this is the
# alternative backend behind `[voiceprint] backend`, and its default (ECAPA, via
# `speechbrain`) is already here. Ask for `yazses[all,voiceprint-resemblyzer]`
# to add it deliberately, and pin setuptools yourself in that environment.
#
# Pins are copied verbatim from the owning extra; the guard fails on any drift, so a
# version bump happens in one place and is checked here rather than remembered.
all = [
"llama-cpp-python>=0.3.33",
"pygls>=2.1.1",
"pynvim>=0.6.0",
"pyserial>=3.5",
"bleak>=3.0.2",
"PySide6>=6.11.1",
"praat-parselmouth>=0.4.7",
"kokoro-onnx>=0.5.0",
"onnxruntime>=1.27.0; sys_platform != 'darwin' or platform_machine != 'x86_64'",
# Intel macOS: onnxruntime stopped publishing an x86_64 wheel after 1.23.0
# (1.24 through 1.28 are macosx_14_0_arm64 only; 1.23.2 is the last with
# macosx_13_0_x86_64). A bare `>=1.27` floor is not a
# preference there, it is an install failure -- uv reports "no source
# distribution or wheel for the current platform", which reads like a broken
# package rather than a dropped platform. See `[tool.uv]` below.
"onnxruntime>=1.23.2,<1.24; sys_platform == 'darwin' and platform_machine == 'x86_64'",
"soundfile>=0.14.0",
"speechbrain>=1.1",
"onnx-asr[cpu,hub]>=0.12",
"sherpa-onnx>=1.13.6",
"sherpa-onnx-core>=1.13.6",
"mediapipe>=0.10.35; sys_platform != 'darwin' or platform_machine != 'x86_64'",
"opencv-python>=5.0",
"opencc-python-reimplemented>=0.1.7",
"brainflow>=5.22.2",
"noisereduce>=3.0.3",
"useful-moonshine-onnx>=20251121",
"pyannote.audio>=4.0.7; sys_platform != 'darwin' or platform_machine != 'x86_64'",
"silero-vad>=5.1.2",
"mcp>=1.28.1",
]
[dependency-groups]
dev = [
"pytest>=9.1.1",
"pytest-mock>=3.15.1",
"pytest-cov>=7.1.0",
"hypothesis>=6.165.2",
"useful-moonshine-onnx>=20251121",
# Lint + type gates. CONTRIBUTING.md and the README tell contributors to run
# `uv run ruff check src tests` and `uv run mypy src`; they belong here so a
# fresh `uv sync` can actually run them.
"ruff>=0.14.5",
"mypy>=1.19.1",
"jiwer>=3.0.0",
# Pillow is a win32-only runtime dep (the pystray tray), but the brand-mark
# renderer and `scripts/gen-icons.py` need it on every platform so the icon
# assets can be regenerated and unit-tested on the Linux CI leg too.
"Pillow>=12.3.0",
# Declared because the suite imports them, not because anything here is new.
# Thirteen test files `import yaml` at module scope and one imports `click`,
# and both were arriving only as transitive dependencies of mkdocs and
# huggingface-hub -- so the whole suite's ability to *collect* rested on a
# docs tool's dependency list. That is not theoretical: typer dropped its
# click dependency at 0.27, and the FreeBSD leg -- the one environment that
# installs test dependencies by name rather than from this file -- went from
# thirteen collection errors to one the moment it stopped inheriting them.
"click>=8.4.2",
"PyYAML>=6.0.3",
]
# Reproducible benchmark harness behind docs/benchmarks.md and the arXiv paper
# (paper/benchmark/). Build-only; never shipped in the wheel. `uv sync --group
# benchmark` then `uv run python paper/benchmark/run_all.py`. jiwer = WER scoring;
# whisper-normalizer = Whisper's own EnglishTextNormalizer, the standard that makes
# our WER comparable with other Whisper results; psutil = RSS; soundfile = read
# LibriSpeech FLAC; matplotlib = the paper figures.
benchmark = [
"jiwer>=4.0.0",
"psutil>=7.1.0",
"matplotlib>=3.10.0",
"soundfile>=0.14.0",
"whisper-normalizer>=0.1.15",
]
# Documentation site (MkDocs + Material). Build-only; never shipped in the wheel.
# `uv sync --group docs` then `uv run mkdocs serve`. Deployed to GitHub Pages by
# .github/workflows/docs.yml. The `[imaging]` extra enables Material social cards
# (needs libcairo at build time — present on CI via apt).
docs = [
"mkdocs-material[imaging]>=9.6.14",
"mkdocs-minify-plugin>=0.8.0",
"mkdocs-git-revision-date-localized-plugin>=1.4.5",
"mkdocs-glightbox>=0.4.0",
"mkdocs-rss-plugin>=1.19.0",
]
[tool.pytest.ini_options]
testpaths = ["tests"]
# Lint gate. Deliberately a small, high-signal core (pyflakes + the serious pycodestyle
# checks + import ordering) so `uv run ruff check src tests` is green and a contributor's
# first run is not a wall of style noise. Widening the ruleset (UP / B / SIM …) is tracked
# as a good first issue — do it one rule family at a time.
[tool.ruff]
line-length = 100
target-version = "py311"
[tool.ruff.lint]
select = ["E4", "E7", "E9", "F", "I"]
ignore = [
"E402", # module-level import not at top — deliberate for lazy/optional imports
"E741", # ambiguous variable name (l, I, O) — a couple of legitimate uses
"E731", # lambda assignment — used in tests as compact stubs
"E702", # `x = 1; i += 2; continue` — deliberate in the table-driven parsers
]
[tool.ruff.lint.isort]
# `_common` is the shared helper module that sits *beside* the benchmark scripts in
# paper/benchmark/, imported as a bare name because they run from that directory.
# Without this ruff reads it as third-party and folds it in among jiwer and numpy,
# which is where its autofix would put it — the nine scripts that import it all keep
# it in its own block, and that grouping is the author's, not an accident.
known-first-party = ["_common"]
[tool.ruff.lint.per-file-ignores]
# Re-exports: package __init__ files intentionally import names they do not use.
"__init__.py" = ["F401"]
# CLAUDE.md names `uv run mypy src` as a quality gate, but the gate had no config, so it
# ran with bare defaults and buried its real findings under ~35 unfixable import errors:
# yazses loads every heavy backend lazily behind an optional extra (ADR-011), so on a base
# install those imports are *correctly* absent and no contributor can "fix" them.
# The overrides below silence exactly that class, leaving only genuine, actionable type
# errors — which is what makes "fix mypy errors in one module" a real good first issue.
# Widening this (disallow_untyped_defs, strict) is deliberately NOT done yet: land the
# module-by-module cleanup first, then tighten one flag at a time.
[tool.mypy]
python_version = "3.11"
files = ["src"]
# Optional/lazy backends and platform-specific modules that a base install omits, plus
# third-party packages that simply ship no type stubs.
[[tool.mypy.overrides]]
module = [
"bleak.*", "cv2.*", "df.*", "faster_whisper.*", "kokoro_onnx.*", "l2cs.*",
"brainflow.*", "llama_cpp.*", "mediapipe.*", "moonshine_onnx.*", "noisereduce.*",
"opencc.*",
"pyannote.*", "pyatspi.*", "pynvim.*",
"pywintypes.*", "resemblyzer.*", "sherpa_onnx.*", "silero_vad.*", "sounddevice.*",
"speechbrain.*", "tomli_w.*", "torch.*", "win32file.*", "win32pipe.*", "Xlib.*",
]
ignore_missing_imports = true
# In-tree adapters that are referenced by a `backend = ...` config option but were never
# shipped in this build. The factories import them lazily inside try/except and degrade
# honestly (see yazses/system/backends.py), so their absence is by design, not drift.
# Delete an entry here when its adapter actually lands.
[[tool.mypy.overrides]]
module = [
"yazses.denoise.deepfilter",
"yazses.recimport.pyannote_backend",
"yazses.voiceprint.resemblyzer_backend",
]
ignore_missing_imports = true
# Win32-only APIs. `ctypes.windll`, `ctypes.get_last_error` and every `winreg`
# attribute are declared in typeshed behind `sys.platform == "win32"`, so they do
# not resolve when mypy runs on Linux — which is where CI runs it. The code is
# correct and only ever imported on Windows (see platform/factory.py), so the
# errors are an artefact of the checking platform, not a defect.
#
# Scoped to `attr-defined` and to these three modules on purpose: every other
# error code still applies here, and the two Windows modules that contain no
# Win32 attribute access (tray.py, ipc.py) are deliberately left out so real
# mistakes in them still fail the gate.
[[tool.mypy.overrides]]
module = [
"yazses.platform.windows.hotkey",
"yazses.platform.windows.injector",
"yazses.platform.windows.lifecycle",
]
disable_error_code = ["attr-defined"]
[tool.hatch.build.targets.wheel]
# Include the whole package. `artifacts` un-ignores src/yazses/overlay/ in case a
# broad `overlay/` VCS-ignore rule (snapcraft's build dir) would otherwise drop it
# — without the force-include that double-added overlay/__init__.py and broke the build.
packages = ["src/yazses"]
artifacts = ["src/yazses/overlay/**"]
[tool.uv]
# `useful-moonshine-onnx`, `onnx-asr` and `kokoro-onnx` all depend on `onnxruntime`
# without a version marker, so uv resolves one version for every platform and picks the
# newest -- which has no Intel macOS wheel. That is what broke the `macOS x86_64 (Intel)`
# leg of `benchmark.yml`: `uv sync` resolved 284 packages and then refused to install
# `onnxruntime==1.28.0` on `macosx_15_0_x86_64`. Constraining it here makes uv fork the
# resolution rather than leaving one platform unresolvable, and it does so for
# dependencies we do not declare, which a marker in `[project]` cannot reach.
#
# Not a pin: everything except Intel macOS still resolves to the newest release.
constraint-dependencies = [
"onnxruntime<1.24; sys_platform == 'darwin' and platform_machine == 'x86_64'",
]