CLI usage
On this page
- Checking files
- Checking a repository outside transformers
- Selecting rules
- Reading the docs from the terminal
- Output formats
- Version
- Running as a module
- Cache
- Python API
With no path argument, mlinter resolves paths relative to the current directory, so run it from the root of a transformers checkout. Pass a path to check any other directory — see Checking a repository outside transformers.
Checking files
# Check all model integration files
mlinter
# Only check files changed against a git base ref
mlinter --changed-only --base-ref origin/main
--changed-only is what CI uses on pull requests. It diffs against the base ref and lints only the
matching files, which keeps a run proportional to the size of the change rather than the size of the
library.
Checking a repository outside transformers
Model code shipped on the Hub with trust_remote_code lives in a flat repository rather than under
src/transformers/models/, but it has to honour the same conventions: a model that skips post_init
or hardcodes a dimension breaks AutoModel.from_pretrained in ways that are hard to trace back. Give
mlinter the files or directories to check and it stops assuming the transformers layout:
# Check a cloned Hub model repository
mlinter ~/models/LLaDA-8B-Instruct
# Check one file, or several paths at once
mlinter ~/models/LLaDA-8B-Instruct/modeling_llada.py
mlinter src/transformers/models/llama tests/models/llama
A directory is searched recursively for model integration files (modeling_*.py, modular_*.py,
configuration_*.py, processing_*.py, image_processing_*.py, video_processing_*.py,
feature_extraction_*.py, test_tokenization_*.py); a file named explicitly is checked as given.
Since the search is recursive and takes several paths at once, the layout does not matter: a GitHub
project that keeps its model files in some directory of its own is checked by naming that directory,
or by naming each one when they are scattered. Rules gate on the file name, so a file named something
else — model.py, say — runs no rules, and mlinter says so rather than reporting a clean run. A path
that does not exist is an error: the run stops with exit code 2 and names it, rather than quietly
checking the rest. Files generated from a modular_*.py source are skipped here as they are in a
checkout, so the modular file is the one reported on. --changed-only composes with paths: it narrows
the git diff to the paths you passed.
test_tokenization_*.py is the only test file discovered, in a checkout or out of one: TRF042
is the only rule that reads a test file. test_modeling_*.py and test_processing_*.py are walked
once a rule targets them.
Rules that resolve other models (a sibling configuration_*.py, a test file under tests/models/,
another model’s directory) find nothing outside a transformers checkout and stay quiet, as do
per-model allowlists and cutoff dates, which are keyed on a src/transformers/models/<model>/ path.
Everything a single file can be judged on still applies.
No transformers checkout is needed either way: the rules ship inside the package, so
pip install -U transformers-mlinter is all it takes to check against the current rule set.
Selecting rules
# List all available TRF rules and their default state
mlinter --list-rules
# Enable additional rules on top of the defaults
mlinter --enable-rules TRF003
# Enable every TRF rule, including ones disabled by default
mlinter --enable-all-trf-rules
# Use a custom rules TOML instead of the bundled mlinter/rules.toml
mlinter --rules-toml /path/to/custom-rules.toml
A custom rules file must declare the same top-level version = 1 as the bundled one, and every rule it
names must have a matching trf*.py module in the installed package.
Rules that have been removed from mlinter are the one exception: they must be marked deprecated = true
(or dropped from the file). mlinter then ignores them. A custom file that still lists a removed rule as
active fails with exit code 2 and names the rule, rather than silently linting nothing under that id.
Reading the docs from the terminal
# Show detailed documentation for one rule
mlinter --rule TRF001
This prints the same “what it does”, “why is this bad”, and diff example that the rule pages on this site are generated from.
Output formats
# Emit GitHub Actions error annotations
mlinter --github-annotations
With --github-annotations, violations are printed as ::error workflow commands, so they appear
inline on the diff of a pull request instead of only in the job log.
# Also write every finding to a JSON file
mlinter --output-json findings.json
--output-json writes the findings alongside the normal output, including the description and diff of
each rule that fired. The file is written even when there are no violations, so a consumer never has to
distinguish “clean run” from “no file produced”, and the exit code is unaffected. The transformers CI
uses it to upload findings as an artifact and post them as inline review comments.
Progress output is animated when attached to a terminal; --no-progress disables it, which is what you
want in a log.
Version
mlinter --version
When installed from a git checkout or a git+https://... URL, the version includes a short commit hash
suffix such as 1.2.3+g1a2b3c4.
Running as a module
python -m mlinter
Equivalent to the mlinter entry point, and useful when the script directory is not on PATH.
Cache
The lint cache is stored in the user cache directory rather than next to the installed package:
| Platform | Location |
|---|---|
| Linux | $XDG_CACHE_HOME/mlinter/.mlinter_cache.json |
| macOS | ~/Library/Caches/mlinter/.mlinter_cache.json |
| Windows | %LOCALAPPDATA%\mlinter\.mlinter_cache.json |
A file is skipped when its content hash, the set of enabled rules, the hash of the rules TOML, and the
contents of any companion configuration_*.py all match the cached entry. Editing a config file
therefore re-checks the modeling files that read it.
One cache serves every repository you check, so entries are keyed on the absolute path: two model
repositories that each hold a modeling_llada.py get an entry apiece rather than one shadowing the
other.
Disable the cache with --no-cache.
Python API
Import the supported API from the package root:
from mlinter import TRF001, analyze_file, model_dir_name, render_rules_reference
File discovery is part of that API, so a tool that lints a repository of its own does not have to reimplement the patterns:
from pathlib import Path
from mlinter import analyze_file, iter_modeling_files
for path in iter_modeling_files(search_paths=[Path("~/models/LLaDA-8B-Instruct").expanduser()]):
violations = analyze_file(path, path.read_text(encoding="utf-8"))
search_paths takes the same files and directories as the command line; without it, discovery walks
src/transformers/models and tests/models relative to the current directory. resolve_search_paths
validates a list of paths the way the CLI does, raising ValueError naming any that do not exist.
mlinter.mlinter and mlinter._helpers are implementation modules and may change without a
compatibility promise.
