language_tool_python is a Python interface/wrapper to LanguageTool, an open-source grammar, style, and spell checker.
It can:
- run a local LanguageTool Java server,
- call LanguageTool public API,
- call your own remote LanguageTool server,
- be used from Python code and from a CLI.
Default local download target: latest snapshot (currently 6.8-SNAPSHOT).
- Docs: https://language-tool-python.readthedocs.io/en/latest/
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- Python
>=3.9(tested up to 3.14) - Java (to run local LanguageTool server):
- LanguageTool
< 6.6: Java>=9 - LanguageTool
>= 6.6(default): Java>=17
- LanguageTool
pip install --upgrade language_tool_pythonimport language_tool_python
with language_tool_python.LanguageTool("en-US") as tool:
text = "A sentence with a error in the Hitchhiker's Guide tot he Galaxy"
matches = tool.check(text)
print(matches)
print(tool.correct(text))import language_tool_python
with language_tool_python.LanguageToolPublicAPI("es") as tool:
matches = tool.check("Se a hecho un esfuerzo.")
print(matches)import language_tool_python
with language_tool_python.LanguageTool(
"en-US",
remote_server="https://your-lt-server.example.com",
) as tool:
print(tool.check("This are bad."))Use this parameter to force which LanguageTool package is used when running a local server.
import language_tool_python
with language_tool_python.LanguageTool(
"en-US",
language_tool_download_version="6.7",
) as tool:
print(tool.check("This are bad."))Accepted formats:
latest(default): latest snapshot configured by this package (6.8-SNAPSHOTat the moment)YYYYMMDD: snapshot by date (example:20260201)X.Y: release version (example:6.7,4.0)
Notes:
- Only relevant when using a local server (no
remote_server). - Versions below
4.0are not supported.
Use this parameter to pass proxy settings to requests when calling a remote LanguageTool server.
import language_tool_python
with language_tool_python.LanguageTool(
"en-US",
remote_server="https://your-lt-server.example.com",
proxies={
"http": "http://proxy.example.com:8080",
"https": "http://proxy.example.com:8080",
},
) as tool:
print(tool.check("This are bad."))Notes:
proxiesworks only withremote_server.- Passing
proxieswithoutremote_serverraisesValueError.
matches = tool.check("This is noot okay.")Each item is a Match object with these fields:
rule_idmessagereplacementsoffset_in_context,context,offset,error_lengthcategory,rule_issue_typesentence
corrected = tool.correct("This is noot okay.")
# Uses first suggestion for each matchtext = "There is a bok on the table."
matches = tool.check(text)
# Keep a specific suggestion for first match
matches[0].select_replacement(2)
patched = language_tool_python.utils.correct(text, matches)matches = tool.check_matching_regions(
'He said "I has a problem" but she replied "It are fine".',
r'"[^"]*"',
)from language_tool_python.utils import classify_matches
status = classify_matches(tool.check("This is a cats."))
# TextStatus.CORRECT / TextStatus.FAULTY / TextStatus.GARBAGEYou can tune checks per instance:
tool.language = "en" # Can also be set from constructor (`LanguageTool("en")`)
tool.mother_tongue = "fr" # Can also be set from constructor (`LanguageTool("en", mother_tongue="fr")`)
tool.disabled_rules.update({"MORFOLOGIK_RULE_EN_US"})
tool.enabled_rules.update({"EN_A_VS_AN"})
tool.enabled_rules_only = False
tool.disabled_categories.update({"CASING"})
tool.enabled_categories.update({"GRAMMAR"})
tool.preferred_variants.update({"en-GB"})
tool.picky = TrueSpellchecking control:
tool.disable_spellchecking()
tool.enable_spellchecking()
# Equivalent to:
tool.disabled_categories.update({"TYPOS"})
tool.disabled_categories.difference_update({"TYPOS"})You can register domain-specific words:
with language_tool_python.LanguageTool(
"en-US",
new_spellings=["my_product_name", "my_team_term"],
new_spellings_persist=False,
) as tool:
print(tool.check("my_product_name is released"))new_spellings_persist=True(default): keeps words in the local LT spelling file.new_spellings_persist=False: session-only, words are removed onclose().
For local servers only, pass a config dictionary. Example:
with language_tool_python.LanguageTool(
"en-US",
config={
"cacheSize": 1000,
"pipelineCaching": True,
"maxTextLength": 50000,
},
) as tool:
print(tool.check("Text to inspect"))Supported keys:
maxTextLength,maxTextHardLength,maxCheckTimeMillismaxErrorsPerWordRate,maxSpellingSuggestions,maxCheckThreadscacheSize,cacheTTLSecondsrequestLimit,requestLimitInBytes,timeoutRequestLimit,requestLimitPeriodInSecondslanguageModel,fasttextModel,fasttextBinarymaxWorkQueueSize,rulesFile,blockedReferrerspremiumOnly,disabledRuleIdspipelineCaching,maxPipelinePoolSize,pipelineExpireTimeInSeconds,pipelinePrewarmingtrustXForwardForHeader,suggestionsEnabled- spellcheck-only language keys:
lang-<code>lang-<code>-dictPath
Notes:
remote_serverandconfigcannot be used together.proxiescan only be used withremote_server.
Entry point:
language_tool_python [OPTIONS] FILE [FILE ...]Use - as file to read from stdin.
Examples:
# Check a file
language_tool_python -l en-US README.md
# Check stdin
echo "This are bad." | language_tool_python -l en-US -
# Auto-apply suggestions
language_tool_python -l en-US --apply input.txt
# Use only selected rules
language_tool_python -l en-US --enabled-only --enable MORFOLOGIK_RULE_EN_US input.txt
# Use remote LT server
language_tool_python -l en-US --remote-host 127.0.0.1 --remote-port 8081 input.txtMain options:
-l, --language CODE-m, --mother-tongue CODE-d, --disable RULES-e, --enable RULES--enabled-only-p, --picky-a, --apply-s, --spell-check-off--ignore-lines REGEX--remote-host HOST,--remote-port PORT-c, --encoding--verbose--version
Exit codes:
0: no issues2: issues found
LTP_PATH: directory used to store downloaded LanguageTool packages.- default:
~/.cache/language_tool_python/
- default:
LTP_JAR_DIR_PATH: use an existing local LanguageTool directory (skip download).LTP_DOWNLOAD_HOST_SNAPSHOT: override snapshot download host.- default:
https://internal1.languagetool.org/snapshots/
- default:
LTP_DOWNLOAD_HOST_RELEASE: override release download host.- default:
https://languagetool.org/download/
- default:
LTP_DOWNLOAD_HOST_ARCHIVE: override archive download host.- default:
https://languagetool.org/download/archive/
- default:
Example:
export LTP_PATH=/path/to/cache
export LTP_JAR_DIR_PATH=/path/to/LanguageTool-6.8-SNAPSHOTWhen using a local server, prefer a context manager or explicit close():
with language_tool_python.LanguageTool("en-US") as tool:
...
# or
tool = language_tool_python.LanguageTool("en-US")
...
tool.close()You can run LT on one process/host and connect from another client:
# Server side
server_tool = language_tool_python.LanguageTool("en-US")
# Client side
client_tool = language_tool_python.LanguageTool(
"en-US",
remote_server=f"http://127.0.0.1:{server_tool.port}",
)Main exceptions in language_tool_python.exceptions:
LanguageToolErrorServerErrorJavaErrorPathErrorRateLimitError
# Install dev dependencies
uv sync --group tests --group docs --group types
# Lint / format / types
uvx ruff@0.14.5 check .
uvx ruff@0.14.5 format .
uvx mypy@1.18.2
# Tests
pytestGPL-3.0-only. See LICENSE.
This project is based on the original language-check project:
https://github.com/myint/language-check/