openai/whisper
Patterns and conventions
The codebase is small and consistent. The following patterns recur and are worth matching when you add code.
Style
- Formatter:
black(88 cols, default config). - Imports:
isortwith--profile black -l 88 --trailing-comma --multi-line 3. Standard library first, third party next, local imports last, separated by blank lines. - Lint:
flake8with--max-line-length 88and--ignore E203,E501,W503,W504. The.flake8file is the source of truth. - Trailing whitespace, mixed line endings, end-of-file fixer: enforced by pre-commit hooks on Python files.
The full toolchain is configured in .pre-commit-config.yaml and pinned to immutable commit hashes (with a comment naming the human-readable version) — keep that pattern when bumping a hook.
Type hints
Functions on the public surface and most internal helpers carry typing annotations. The conventions:
Optional[X]rather thanX | None(the codebase still supports Python 3.8).Tuple,List,Dict,Iterable,Sequencefromtyping— not the baretuple/list/dictgenerics.Union[str, np.ndarray, torch.Tensor]is common for "audio-like" arguments.- Forward references in type hints use string literals (
"Whisper") plusif TYPE_CHECKING:imports to avoid runtime cycles. Seewhisper/transcribe.pyandwhisper/decoding.py.
Dataclasses
Configuration and result types are @dataclass(frozen=True) where they should not be mutated:
DecodingOptionsandDecodingResultinwhisper/decoding.py.ModelDimensionsinwhisper/model.py.WordTiminginwhisper/timing.py(mutable; updated in place bymerge_punctuations).
dataclasses.replace(options, **kwargs) is used to override fields without mutation — see how decode() accepts **kwargs and applies them to options.
Caching
@lru_cache(maxsize=None)is used liberally for expensive idempotent computations:mel_filtersinwhisper/audio.py,get_encodingandget_tokenizerinwhisper/tokenizer.py.@cached_propertyis used onTokenizerfor derived special-token IDs (eot,sot,transcribe,translate,no_speech,timestamp_begin,all_language_tokens,non_speech_tokens).
Pure-PyTorch dtype handling
The codebase deliberately runs the same module in fp16, fp32, or bf16 by overriding forward to cast weights to the activation dtype. See LayerNorm, Linear, and Conv1d subclasses in whisper/model.py. This avoids a parallel set of half-precision modules.
Optional GPU acceleration with CPU fallback
Two places use this pattern:
result = None
if x.is_cuda:
try:
result = gpu_kernel(x)
except (RuntimeError, subprocess.CalledProcessError):
warnings.warn("Failed to launch Triton kernels, ...")
if result is None:
result = cpu_implementation(x)Both dtw() and median_filter() in whisper/timing.py follow this. Errors specifically caught are RuntimeError (Triton compile/launch) and subprocess.CalledProcessError (Triton's nvcc shell-out). Don't swallow other exceptions.
Forward hooks for KV caching
Whisper.install_kv_cache_hooks() installs forward hooks on every MultiHeadAttention.key / value linear projection. The hook either records the output for the first token, or concatenates new outputs onto the cached tensor for subsequent tokens. cleanup_caching() removes the hooks via RemovableHandle.remove(). This pattern keeps the model code itself ignorant of caching.
A similar hook pattern is used in whisper/timing.py:find_alignment to harvest cross-attention QKs from block.cross_attn for DTW alignment, with disable_sdpa() ensuring the manual attention path runs (so the QK tensor is actually populated).
Logit filtering as composable objects
Sampling-time constraints are expressed as LogitFilter subclasses (SuppressBlank, SuppressTokens, ApplyTimestampRules) in whisper/decoding.py. Each implements apply(logits, tokens) and modifies logits in place. DecodingTask accumulates a list and runs them in order before the token decoder picks the next token. Add new constraints by subclassing LogitFilter.
CLI argument parsing
cli() in whisper/transcribe.py uses argparse.ArgumentDefaultsHelpFormatter and helper coercers from whisper/utils.py:
str2boolfor boolean flags (accepts only"True"/"False").optional_int/optional_floatfor--max_line_width,--patience, etc.
When you add a CLI flag, plumb it through to transcribe() via **args; transcribe() then forwards unrelated kwargs into DecodingOptions(**decode_options).
Result writers
Every output format extends whisper.utils.ResultWriter. Concrete subclasses set extension and implement write_result(result, file, options=None, **kwargs). get_writer("all", ...) returns a callable that fans out to every concrete writer. Add new formats by subclassing and registering in the writers dict.
Testing patterns
- Use the JFK fixture for end-to-end audio tests; don't add new media unless required.
- Use
@pytest.mark.parametrizefor tokenizer / number-normalizer / DTW size variations. - Mark CUDA-only tests with
@pytest.mark.requires_cuda. - Seed RNGs through the
randomfixture intests/conftest.pyrather than callingrandom.seeddirectly in each test.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.