Open-Source Wikis

/

Whisper

/

How to contribute

/

Patterns and conventions

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: isort with --profile black -l 88 --trailing-comma --multi-line 3. Standard library first, third party next, local imports last, separated by blank lines.
  • Lint: flake8 with --max-line-length 88 and --ignore E203,E501,W503,W504. The .flake8 file 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 than X | None (the codebase still supports Python 3.8).
  • Tuple, List, Dict, Iterable, Sequence from typing — not the bare tuple/list/dict generics.
  • Union[str, np.ndarray, torch.Tensor] is common for "audio-like" arguments.
  • Forward references in type hints use string literals ("Whisper") plus if TYPE_CHECKING: imports to avoid runtime cycles. See whisper/transcribe.py and whisper/decoding.py.

Dataclasses

Configuration and result types are @dataclass(frozen=True) where they should not be mutated:

  • DecodingOptions and DecodingResult in whisper/decoding.py.
  • ModelDimensions in whisper/model.py.
  • WordTiming in whisper/timing.py (mutable; updated in place by merge_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_filters in whisper/audio.py, get_encoding and get_tokenizer in whisper/tokenizer.py.
  • @cached_property is used on Tokenizer for 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:

  • str2bool for boolean flags (accepts only "True" / "False").
  • optional_int / optional_float for --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.parametrize for tokenizer / number-normalizer / DTW size variations.
  • Mark CUDA-only tests with @pytest.mark.requires_cuda.
  • Seed RNGs through the random fixture in tests/conftest.py rather than calling random.seed directly in each test.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Patterns and conventions – Whisper wiki | Factory