{"id":13827501,"url":"https://github.com/jxmorris12/language_tool_python","last_synced_at":"2026-01-02T15:26:05.492Z","repository":{"id":37649555,"uuid":"260348092","full_name":"jxmorris12/language_tool_python","owner":"jxmorris12","description":"a free python grammar checker 📝✅","archived":false,"fork":false,"pushed_at":"2025-04-08T10:57:40.000Z","size":699,"stargazers_count":457,"open_issues_count":17,"forks_count":65,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-04-11T20:43:44.816Z","etag":null,"topics":["grammar","grammar-checker","grammar-parser","languagetool","nlp","python","spellchecker"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jxmorris12.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-05-01T00:31:21.000Z","updated_at":"2025-04-08T10:57:44.000Z","dependencies_parsed_at":"2024-11-07T18:32:57.588Z","dependency_job_id":"af204629-0f9c-432b-9379-c6d57000dfd8","html_url":"https://github.com/jxmorris12/language_tool_python","commit_stats":{"total_commits":471,"total_committers":23,"mean_commits":20.47826086956522,"dds":0.653927813163482,"last_synced_commit":"cde9d6552f980da5d545dd760ef7642e7a4eb4ba"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jxmorris12%2Flanguage_tool_python","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jxmorris12%2Flanguage_tool_python/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jxmorris12%2Flanguage_tool_python/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jxmorris12%2Flanguage_tool_python/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jxmorris12","download_url":"https://codeload.github.com/jxmorris12/language_tool_python/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254140768,"owners_count":22021220,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["grammar","grammar-checker","grammar-parser","languagetool","nlp","python","spellchecker"],"created_at":"2024-08-04T09:01:59.724Z","updated_at":"2026-01-02T15:26:05.485Z","avatar_url":"https://github.com/jxmorris12.png","language":"Python","readme":"# `language_tool_python`: a grammar checker for Python 📝\n\n[![language tool python on pypi](https://badge.fury.io/py/language-tool-python.svg)](https://pypi.org/project/language-tool-python/)\n[![Documentation Status](https://readthedocs.org/projects/language-tool-python/badge/?version=latest)](https://language-tool-python.readthedocs.io/en/latest/)\n[![Test with PyTest](https://github.com/jxmorris12/language_tool_python/workflows/Test%20with%20PyTest/badge.svg)](https://github.com/jxmorris12/language_tool_python/actions)\n[![Coverage Status](https://raw.githubusercontent.com/jxmorris12/language_tool_python/master/coverage-badge.svg)](https://github.com/jxmorris12/language_tool_python/actions)\n[![Downloads](https://static.pepy.tech/badge/language-tool-python)](https://pepy.tech/project/language-tool-python)\n[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](LICENSE)\n[![Contributions Welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/jxmorris12/language_tool_python/pulls)\n\nCurrent LanguageTool version: **6.8-SNAPSHOT**\n\nThis is a Python wrapper for [LanguageTool](https://languagetool.org). LanguageTool is an open-source grammar tool, also known as the spellchecker for OpenOffice. This library allows you to detect grammar errors and spelling mistakes through a Python script or through a command-line interface.\n\n## Documentation\n\nThe full documentation is available at: [https://language-tool-python.readthedocs.io/en/latest/](https://language-tool-python.readthedocs.io/en/latest/)\n\n## Local and Remote Servers\n\nBy default, `language_tool_python` will download a LanguageTool server `.jar` and run that in the background to detect grammar errors locally. However, LanguageTool also offers a [Public HTTP Proofreading API](https://dev.languagetool.org/public-http-api) that is supported as well. Follow the link for rate limiting details. (Running locally won't have the same restrictions.)\n\n### Using `language_tool_python` locally\n\nLocal server is the default setting. To use this, just initialize a LanguageTool object:\n\n```python\nimport language_tool_python\ntool = language_tool_python.LanguageTool('en-US')  # use a local server (automatically set up), language English\n```\n\n### Using `language_tool_python` with the public LanguageTool remote server\n\nThere is also a built-in class for querying LanguageTool's public servers. Initialize it like this:\n\n```python\nimport language_tool_python\ntool = language_tool_python.LanguageToolPublicAPI('es') # use the public API, language Spanish\n```\n\n### Using `language_tool_python` with the another remote server\n\nFinally, you're able to pass in your own remote server as an argument to the `LanguageTool` class:\n\n```python\nimport language_tool_python\ntool = language_tool_python.LanguageTool('ca-ES', remote_server='https://language-tool-api.mywebsite.net')  # use a remote server API, language Catalan\n```\n\n### Apply a custom list of matches with `utils.correct`\n\nIf you want to decide which `Match` objects to apply to your text, use `tool.check` (to generate the list of matches) in conjunction with `language_tool_python.utils.correct` (to apply the list of matches to text). Here is an example of generating, filtering, and applying a list of matches. In this case, spell-checking suggestions for uppercase words are ignored:\n\n```python\n\u003e\u003e\u003e s = \"Department of medicine Colombia University closed on August 1 Milinda Samuelli\"\n\u003e\u003e\u003e is_bad_rule = lambda rule: rule.message == 'Possible spelling mistake found.' and len(rule.replacements) and rule.replacements[0][0].isupper()\n\u003e\u003e\u003e import language_tool_python\n\u003e\u003e\u003e tool = language_tool_python.LanguageTool('en-US')\n\u003e\u003e\u003e matches = tool.check(s)\n\u003e\u003e\u003e matches = [rule for rule in matches if not is_bad_rule(rule)]\n\u003e\u003e\u003e language_tool_python.utils.correct(s, matches)\n'Department of medicine Colombia University closed on August 1 Melinda Sam'\n```\n\n### Apply a specific suggestion of a match with `Match.select_replacement` and `utils.correct`\n\nIf you want to apply a particular suggestion from a `Match`, use `Match.select_replacement` (to select a replacement with its index) in conjunction with `language_tool_python.utils.correct` (to apply selected replacements from the `Match` list to the text). Here is an example of generating, selecting replacements, and applying the list of matches. In this case, the third replacement (book) is selected.\n\n```python\n\u003e\u003e\u003e import language_tool_python\n\u003e\u003e\u003e s = \"There is a bok on the table.\" \n\u003e\u003e\u003e tool = language_tool_python.LanguageTool('en-US')\n\u003e\u003e\u003e matches = tool.check(s)\n\u003e\u003e\u003e matches\n[Match({'rule_id': 'MORFOLOGIK_RULE_EN_US', 'message': 'Possible spelling mistake found.', 'replacements': ['BOK', 'OK', 'book', 'box'], 'offset_in_context': 11, 'context': 'There is a bok on the table.', 'offset': 11, 'error_length': 3, 'category': 'TYPOS', 'rule_issue_type': 'misspelling', 'sentence': 'There is a bok on the table.'})]\n\u003e\u003e\u003e matches[0].select_replacement(2) \n\u003e\u003e\u003e patched_text = language_tool_python.utils.correct(s, matches)    \n\u003e\u003e\u003e patched_text\n'There is a book on the table.'\n```\n\n### Determine whether a text is grammatically correct\n\nIf you want to determine whether a text is grammatically correct, you can use the `classify_matches` function from `language_tool_python.utils`. It will return a `TextStatus` enum value indicating whether the text is correct, faulty, or garbage. Here is an example:\n\n```python\n\u003e\u003e\u003e import language_tool_python\n\u003e\u003e\u003e from language_tool_python.utils import classify_matches\n\u003e\u003e\u003e tool = language_tool_python.LanguageTool('en-US')\n\u003e\u003e\u003e matches = tool.check('This is a cat.')\n\u003e\u003e\u003e matches_1 = tool.check('This is a cats.')\n\u003e\u003e\u003e matches_2 = tool.check('fabafbafzabfabfz')\n\u003e\u003e\u003e classify_matches(matches)\n\u003cTextStatus.CORRECT: 'correct'\u003e\n\u003e\u003e\u003e classify_matches(matches_1)\n\u003cTextStatus.FAULTY: 'faulty'\u003e\n\u003e\u003e\u003e classify_matches(matches_2)\n\u003cTextStatus.GARBAGE: 'garbage'\u003e\n```\n\n## Example usage\n\nFrom the interpreter:\n\n```python\n\u003e\u003e\u003e import language_tool_python\n\u003e\u003e\u003e tool = language_tool_python.LanguageTool('en-US')\n\u003e\u003e\u003e text = 'A sentence with a error in the Hitchhiker’s Guide tot he Galaxy'\n\u003e\u003e\u003e matches = tool.check(text)\n\u003e\u003e\u003e len(matches)\n2\n...\n\u003e\u003e\u003e tool.close() # Call `close()` to shut off the server when you're done.\n```\n\nCheck out some ``Match`` object attributes:\n\n```python\n\u003e\u003e\u003e matches[0].rule_id, matches[0].replacements # ('EN_A_VS_AN', ['an'])\n('EN_A_VS_AN', ['an'])\n\u003e\u003e\u003e matches[1].rule_id, matches[1].replacements\n('TOT_HE', ['to the'])\n```\n\nPrint a ``Match`` object:\n\n```python\n\u003e\u003e\u003e print(matches[1])\nLine 1, column 51, Rule ID: TOT_HE[1]\nMessage: Did you mean 'to the'?\nSuggestion: to the\n...\n```\n\nAutomatically apply suggestions to the text:\n\n```python\n\u003e\u003e\u003e tool.correct(text)\n'A sentence with an error in the Hitchhiker’s Guide to the Galaxy'\n```\n\nFrom the command line:\n\n```bash\n$ echo 'This are bad.' \u003e example.txt\n$ language_tool_python example.txt\nexample.txt:1:1: THIS_NNS[3]: Did you mean 'these'?\n```\n\n## Closing LanguageTool\n\n`language_tool_python` runs a LanguageTool Java server in the background. It will shut the server off when garbage collected, for example when a created `language_tool_python.LanguageTool` object goes out of scope. However, if garbage collection takes awhile, the process might not get deleted right away. If you're seeing lots of processes get spawned and not get deleted, you can explicitly close them:\n\n\n```python\nimport language_tool_python\ntool = language_tool_python.LanguageToolPublicAPI('de-DE') # starts a process\n# do stuff with `tool`\ntool.close() # explicitly shut off the LanguageTool\n```\n\nYou can also use a context manager (`with .. as`) to explicitly control when the server is started and stopped:\n\n```python\nimport language_tool_python\n\nwith language_tool_python.LanguageToolPublicAPI('de-DE') as tool:\n  # do stuff with `tool`\n# no need to call `close() as it will happen at the end of the with statement\n```\n\n## Client-Server Model\n\nYou can run LanguageTool on one host and connect to it from another.  This is useful in some distributed scenarios. Here's a simple example:\n\n#### server\n\n```python\n\u003e\u003e\u003e import language_tool_python\n\u003e\u003e\u003e tool = language_tool_python.LanguageTool('en-US', host='0.0.0.0')\n\u003e\u003e\u003e tool._url\n'http://0.0.0.0:8081/v2/'\n```\n\n#### client\n```python\n\u003e\u003e\u003e import language_tool_python\n\u003e\u003e\u003e lang_tool = language_tool_python.LanguageTool('en-US', remote_server='http://127.0.0.1:8081')\n\u003e\u003e\u003e\n\u003e\u003e\u003e\n\u003e\u003e\u003e lang_tool.check('helo darknes my old frend')\n[Match({'rule_id': 'UPPERCASE_SENTENCE_START', 'message': 'This sentence does not start with an uppercase letter.', 'replacements': ['Helo'], 'offset_in_Context': 0, 'context': 'helo darknes my old frend', 'offset': 0, 'error_length': 4, 'category': 'CASING', 'rule_issue_type': 'typographical', 'sentence': 'helo darknes my old frend'}), Match({'rule_id': 'MORFOLOGIK_RULE_EN_US', 'message': 'Possible spelling mistake found.', 'replacements': ['darkness', 'darkens', 'darkies'], 'offset_in_context': 5, 'context': 'helo darknes my old frend', 'offset': 5, 'error_length': 7, 'category': 'TYPOS', 'rule_issue_type': 'misspelling', 'sentence': 'helo darknes my old frend'}), Match({'rule_id': 'MORFOLOGIK_RULE_EN_US', 'message': 'Possible spelling mistake found.', 'replacements': ['friend', 'trend', 'Fred', 'freed', 'Freud', 'Friend', 'fend', 'fiend', 'frond', 'rend', 'fr end'], 'offset_in_context': 20, 'context': 'helo darknes my old frend', 'offset': 20, 'error_length': 5, 'category': 'TYPOS', 'rule_issue_type': 'misspelling', 'sentence': 'helo darknes my old frend'})]\n\u003e\u003e\u003e\n```\n\n## Configuration\n\nLanguageTool offers lots of built-in configuration options.\n\n### Example: Enabling caching\nHere's an example of using the configuration options to enable caching. Some users have reported that this helps performance a lot.\n```python\nimport language_tool_python\ntool = language_tool_python.LanguageTool('en-US', config={ 'cacheSize': 1000, 'pipelineCaching': True })\n```\n\n\n### Example: Setting maximum text length\n\nHere's an example showing how to configure LanguageTool to set a maximum length on grammar-checked text. Will throw an error (which propagates to Python as a `language_tool_python.LanguageToolError`) if text is too long.\n```python\nimport language_tool_python\ntool = language_tool_python.LanguageTool('en-US', config={ 'maxTextLength': 100 })\n```\n\n### Full list of configuration options\n\nHere's a full list of configuration options:\n\n```\n'maxTextLength' - maximum text length, longer texts will cause an error (optional)\n'maxTextHardLength' - maximum text length, applies even to users with a special secret 'token' parameter (optional)\n'maxCheckTimeMillis' - maximum time in milliseconds allowed per check (optional)\n'maxErrorsPerWordRate' - checking will stop with error if there are more rules matches per word (optional)\n'maxSpellingSuggestions' - only this many spelling errors will have suggestions for performance reasons (optional,\n                          affects Hunspell-based languages only)\n'maxCheckThreads' - maximum number of threads working in parallel (optional)\n'cacheSize' - size of internal cache in number of sentences (optional, default: 0)\n'cacheTTLSeconds' - how many seconds sentences are kept in cache (optional, default: 300 if 'cacheSize' is set)\n'requestLimit' - maximum number of requests per requestLimitPeriodInSeconds (optional)\n'requestLimitInBytes' - maximum aggregated size of requests per requestLimitPeriodInSeconds (optional)\n'timeoutRequestLimit' - maximum number of timeout request (optional)\n'requestLimitPeriodInSeconds' - time period to which requestLimit and timeoutRequestLimit applies (optional)\n'languageModel' - a directory with '1grams', '2grams', '3grams' sub directories per language which contain a Lucene index\n                  each with ngram occurrence counts; activates the confusion rule if supported (optional)\n'fasttextModel' - a model file for better language detection (optional), see\n                  https://fasttext.cc/docs/en/language-identification.html\n'fasttextBinary' - compiled fasttext executable for language detection (optional), see\n                  https://fasttext.cc/docs/en/support.html\n'maxWorkQueueSize' - reject request if request queue gets larger than this (optional)\n'rulesFile' - a file containing rules configuration, such as .languagetool.cfg (optional)\n'blockedReferrers' - a comma-separated list of HTTP referrers (and 'Origin' headers) that are blocked and will not be served (optional)\n'premiumOnly' - activate only the premium rules (optional)\n'disabledRuleIds' - a comma-separated list of rule ids that are turned off for this server (optional)\n'pipelineCaching' - set to 'true' to enable caching of internal pipelines to improve performance\n'maxPipelinePoolSize' - cache size if 'pipelineCaching' is set\n'pipelineExpireTimeInSeconds' - time after which pipeline cache items expire\n'pipelinePrewarming' - set to 'true' to fill pipeline cache on start (can slow down start a lot)\n'trustXForwardForHeader' - set this to 'true' if you run the server behind a reverse proxy and want the\n                           request limit to work on the original IP addresses provided by the 'X-forwarded-for' HTTP header,\n                           usually set by the proxy\n'suggestionsEnabled' - if suggestions should be generated for spell check errors (optional, default: true)\n\nSpellcheck-only languages: You can add simple spellcheck-only support for languages that LT doesn't\n                           support by defining two optional properties:\n  'lang-xx' - set name of the language, use language code instead of 'xx', e.g. lang-tr=Turkish\n  'lang-xx-dictPath' - absolute path to the hunspell .dic file, use language code instead of 'xx', e.g.\n                       lang-tr-dictPath=/path/to/tr.dic. Note that the same directory also needs to\n                       contain a common_words.txt file with the most common 10,000 words (used for\n                       better language detection)\n```\n\n## Installation\n\nTo install via pip:\n\n```bash\n$ pip install --upgrade language_tool_python\n```\n\n### What rules does LanguageTool have?\n\nSearching for a specific rule to enable or disable? Curious the breadth of rules LanguageTool applies? This page contains a massive list of all 5,000+ grammatical rules that are programmed into LanguageTool: https://community.languagetool.org/rule/list?lang=en\u0026offset=30\u0026max=10\n\n### Customizing Download URL or Path\n\nIf LanguageTool is already installed on your system, you can defined the following environment variable:\n```bash\n$ export LTP_JAR_DIR_PATH = /path/to/the/language/tool/jar/files\n```\n\nOverwise, `language_tool_python` can download LanguageTool for you automatically.\n\nTo overwrite the host part of URL that is used to download LanguageTool-{version}.zip:\n\n```bash\n$ export LTP_DOWNLOAD_HOST = [alternate URL]\n```\n\nThis can be used to downgrade to an older version, for example, or to download from a mirror.\n\nAnd to choose the specific folder to download the server to:\n\n```bash\n$ export LTP_PATH = /path/to/save/language/tool\n```\n\nThe default download path is `~/.cache/language_tool_python/`. The LanguageTool server is about 200 MB, so take that into account when choosing your download folder. (Or, if you you can't spare the disk space, use a remote URL!)\n\n## Prerequisites\n\n- [Python 3.9+](https://www.python.org)\n- [LanguageTool](https://www.languagetool.org) (Java 8.0 or higher for version \u003c= 6.5, Java 17.0 or higher for version \u003e= 6.6)\n\nThe installation process should take care of downloading LanguageTool (it may\ntake a few minutes). Otherwise, you can manually download\n[LanguageTool-stable.zip](https://www.languagetool.org/download/LanguageTool-stable.zip) and unzip it\ninto where the ``language_tool_python`` package resides.\n\n### LanguageTool Version\n\nLanguageTool versions under 6.0 are no longer downloadable from the LanguageTool website. If you need to use an older version, you can download it from the [LanguageTool GitHub tags page](https://github.com/languagetool-org/languagetool/tags) and build it yourself.\n\n### Acknowledgements\n\nThis is a fork of https://github.com/myint/language-check/ that produces more easily parsable\nresults from the command-line.\n","funding_links":[],"categories":["Python"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjxmorris12%2Flanguage_tool_python","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjxmorris12%2Flanguage_tool_python","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjxmorris12%2Flanguage_tool_python/lists"}