././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1628227
proselint-0.13.0/LICENSE.md 0000644 0000000 0000000 00000002764 00000000000 012116 0 ustar 00 Copyright © 2014–2015, Jordan Suchow, Michael Pacer, and Lara A. Ross
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1628227
proselint-0.13.0/README.md 0000644 0000000 0000000 00000026423 00000000000 011767 0 ustar 00

[](https://houndci.com)
[](https://codeclimate.com/repos/5538989ee30ba0793100090f/feed)
[](https://codecov.io/gh/amperser/proselint)
[](https://en.wikipedia.org/wiki/BSD_licenses)
Writing is notoriously hard, even for the best writers, and it's not for lack of good advice — a tremendous amount of knowledge about the craft is strewn across usage guides, dictionaries, technical manuals, essays, pamphlets, websites, and the hearts and minds of great authors and editors. But poring over Strunk & White hardly makes one a better writer — it turns you into neither Strunk nor White. And nobody has the capacity to apply all the advice from *Garner’s Modern English Usage*, an 1100-page usage guide, to everything they write. In fact, the whole notion that one becomes a better writer by reading advice on writing rests on untenable assumptions about learning and memory. The traditional formats of knowledge about writing are thus essentially inert, waiting to be transformed.
We devised a simple solution: `proselint`, a linter for English prose. A linter is a computer program that, akin to a spell checker, scans through a file and detects issues — like how a real lint roller helps you get unwanted lint off of your shirt.
`proselint` places the world's greatest writers and editors by your side, where they whisper suggestions on how to improve your prose. You’ll be guided by advice inspired by Bryan Garner, David Foster Wallace, Chuck Palahniuk, Steve Pinker, Mary Norris, Mark Twain, Elmore Leonard, George Orwell, Matthew Butterick, William Strunk, Elwyn White, Philip Corbett, Ernest Gowers, and the editorial staff of the world’s finest literary magazines and newspapers, among others. Our goal is to aggregate knowledge about best practices in writing and to make that knowledge immediately accessible to all authors in the form of a linter for prose; all in a neat command-line utility that you can integrate into other tools, scripts, and workflows.
### Installation
To get this up and running, install it using [pip]:
```bash
pip install proselint
```
[pip]: https://packaging.python.org/installing/#use-pip-for-installing
#### Fedora
```bash
sudo dnf install proselint
```
#### Debian
```bash
sudo apt install python3-proselint
```
#### Ubuntu
```bash
sudo add-apt-repository universe
sudo apt install python3-proselint
```
### Plugins for other software
`proselint` is available on:
- A [demo editor](http://proselint.com/write)
- [Sublime Text](https://github.com/amperser/proselint/tree/main/plugins/sublime/SublimeLinter-contrib-proselint)
- [Atom Editor](https://github.com/smockle/linter-proselint) (thanks to [Clay Miller](https://github.com/smockle)).
- [Emacs via Flycheck](http://www.flycheck.org/).
- Vim via [ALE](https://github.com/w0rp/ale) or [Syntastic](https://github.com/vim-syntastic/syntastic) (thanks to @lcd047, @Carreau, and [Daniel M. Capella](https://github.com/polyzen))
- [Phabricator's `arc` CLI](https://github.com/google/arc-proselint) (thanks to [Jeff Verkoeyen](https://github.com/jverkoey))
- [Danger](https://github.com/dbgrandi/danger-prose) (thanks to [David Grandinetti](https://github.com/dbgrandi) and [Orta Therox](https://github.com/orta))
- [Visual Studio Code](https://github.com/ppeszko/vscode-proselint) (thanks to [Patryk Peszko](https://github.com/ppeszko))
- [coala](https://github.com/coala-analyzer/bear-docs/blob/master/docs/ProseLintBear.rst) (thanks to the [coala Development Group](https://github.com/coala-analyzer))
- [IntelliJ](https://github.com/kropp/intellij-proselint) (by [Victor Kropp](https://github.com/kropp))
- [pre-commit](https://pre-commit.com/) (by [Andy Airey](https://github.com/aairey))
- [Statick](https://github.com/sscpac/statick-md)
### Usage
Suppose you have a document `text.md` with the following text:
```
John is very unique.
```
You can run `proselint` over the document using the command line:
```bash
proselint text.md
```
This prints a list of suggestions to stdout, one per line. Each suggestion has the form:
```bash
text.md:::
```
For example,
```bash
text.md:0:10: wallace.uncomparables Comparison of an uncomparable: 'unique' cannot be compared.
```
The command-line utility can also print suggestions in JSON using the `--json` flag. In this case, the output is considerably richer:
```jsonc
{
// Type of check that output this suggestion.
check: "wallace.uncomparables",
// Message to describe the suggestion.
message: "Comparison of an uncomparable: 'unique' cannot be compared.",
// The person or organization giving the suggestion.
source: "David Foster Wallace"
// URL pointing to the source material.
source_url: "http://www.telegraph.co.uk/a/9715551"
// Line where the error starts.
line: 0,
// Column where the error starts.
column: 10,
// Index in the text where the error starts.
start: 10,
// Index in the text where the error ends.
end: 21,
// length from start -> end
extent: 11,
// How important is this? Can be "suggestion", "warning", or "error".
severity: "warning",
// Possible replacements.
replacements: [
{
value: "unique"
}
]
}
```
To run the linter as part of another Python program, you can use the `lint` function in `proselint.tools`:
```python
import proselint
suggestions = proselint.tools.lint("This sentence is very unique")
```
This will return a list of suggestions:
```python
[('weasel_words.very', "Substitute 'damn' every time you're inclined to write 'very;' your editor will delete it and the writing will be just as it should be.", 0, 17, 17, 22, 5, 'warning', None), ('uncomparables.misc', "Comparison of an uncomparable: 'very unique.' is not comparable.", 0, 17, 17, 29, 12, 'warning', None)]
```
### Checks
You can disable any of the checks by modifying `$XDG_CONFIG_HOME/proselint/config`. If `$XDG_CONFIG_HOME` is not set or empty, `~/.config/proselint/config` will be used. Additionally, for compatibility reasons, the legacy configuration `~/.proselintrc` will be checked if `$XDG_CONFIG_HOME/proselint/config` does not exist.
```json
{
"checks": {
"typography.diacritical_marks": false
}
}
```
| ID | Description |
| ----- | --------------- |
| `airlinese.misc` | Avoiding jargon of the airline industry |
| `annotations.misc` | Catching annotations left in the text |
| `archaism.misc` | Avoiding archaic forms |
| `cliches.hell` | Avoiding a common cliché |
| `cliches.misc` | Avoiding clichés |
| `consistency.spacing` | Consistent sentence spacing |
| `consistency.spelling` | Consistent spelling |
| `corporate_speak.misc` | Avoiding corporate buzzwords |
| `cursing.filth` | Words to avoid |
| `cursing.nfl` | Avoiding words banned by the NFL |
| `dates_times.am_pm` | Using the right form for the time of day |
| `dates_times.dates` | Stylish formatting of dates |
| `hedging.misc` | Not hedging |
| `hyperbole.misc` | Not being hyperbolic |
| `jargon.misc` | Avoiding miscellaneous jargon |
| `lgbtq.offensive_terms` | Avoding offensive LGBTQ terms |
| `lgbtq.terms` | Misused LGBTQ terms |
| `lexical_illusions.misc` | Avoiding lexical illusions |
| `links.broken` | Linking only to existing sites |
| `malapropisms.misc` | Avoiding common malapropisms |
| `misc.apologizing` | Being confident |
| `misc.back_formations` | Avoiding needless backformations |
| `misc.bureaucratese` | Avoiding bureaucratese |
| `misc.but` | Avoid starting a paragraph with "But..." |
| `misc.capitalization` | Capitalizing only what ought to be capitalized |
| `misc.chatspeak` | Avoiding lolling and other chatspeak |
| `misc.commercialese` | Avoiding jargon of the commercial world |
| `misc.currency` | Avoiding redundant currency symbols |
| `misc.debased` | Avoiding debased language |
| `misc.false_plurals` | Avoiding false plurals |
| `misc.illogic` | Avoiding illogical forms |
| `misc.inferior_superior` | Superior to, not than |
| `misc.latin` | Avoiding overuse of Latin phrases |
| `misc.many_a` | Many a singular |
| `misc.metaconcepts` | Avoiding overuse of metaconcepts |
| `misc.narcissism` | Talking about the subject, not its study |
| `misc.phrasal_adjectives` | Hyphenating phrasal adjectives |
| `misc.preferred_forms` | Miscellaneous preferred forms |
| `misc.pretension` | Avoiding being pretentious |
| `misc.professions` | Calling jobs by the right name |
| `misc.punctuation` | Using punctuation assiduously |
| `misc.scare_quotes` | Using scare quotes only when needed |
| `misc.suddenly` | Avoiding the word suddenly |
| `misc.tense_present` | Advice from Tense Present |
| `misc.waxed` | Waxing poetic |
| `misc.whence` | Using "whence" |
| `mixed_metaphors.misc` | Not mixing metaphors |
| `mondegreens.misc` | Avoiding mondegreen |
| `needless_variants.misc` | Using the preferred form |
| `nonwords.misc` | Avoid using nonwords |
| `oxymorons.misc` | Avoiding oxymorons |
| `psychology.misc` | Avoiding misused psychological terms |
| `redundancy.misc` | Avoiding redundancy and saying things twice |
| `redundancy.ras_syndrome` | Avoiding RAS syndrome |
| `skunked_terms.misc` | Avoid using skunked terms |
| `spelling.able_atable` | -able vs. -atable |
| `spelling.able_ible` | -able vs. -ible |
| `spelling.athletes` | Spelling of athlete names |
| `spelling.em_im_en_in` | -em vs. -im and -en vs. -in |
| `spelling.er_or` | -er vs. -or |
| `spelling.in_un` | in- vs. un- |
| `spelling.misc` | Spelling words corectly |
| `security.credit_card` | Keeping credit card numbers secret |
| `security.password` | Keeping passwords secret |
| `sexism.misc` | Avoiding sexist language |
| `terms.animal_adjectives` | Animal adjectives |
| `terms.denizen_labels` | Calling denizens by the right name |
| `terms.eponymous_adjectives` | Calling people by the right name |
| `terms.venery` | Call groups of animals by the right name |
| `typography.diacritical_marks` | Using dïacríticâl marks |
| `typography.exclamation` | Avoiding overuse of exclamation |
| `typography.symbols` | Using the right symbols |
| `uncomparables.misc` | Not comparing uncomparables |
| `weasel_words.misc` | Avoiding weasel words |
| `weasel_words.very` | Avoiding the word "very" |
### Contributing
Interested in contributing to `proselint`? Great — there are plenty of ways you can help. Read more on [our website], where we describe how you can help us build `proselint` into the greatest writing tool in the world.
- [Issue Tracker](http://github.com/amperser/proselint/issues)
- [Source Code](http://github.com/amperser/proselint)
[our website]: http://proselint.com/contributing/
### Support
If you run into a problem, please [open an issue](http://github.com/amperser/proselint/issues) in or send an email to hello@amperser.com.
### Running Automated Tests
Automated tests are included in the `proselint/tests` directory. To run these tests locally, you can use `./utils`.
### License
The project is licensed under the BSD license.
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/__init__.py 0000644 0000000 0000000 00000000174 00000000000 014633 0 ustar 00 # flake8: noqa
"""Proselint applies advice from great writers to your writing."""
from . import tools
__all__ = ("tools")
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/__main__.py 0000644 0000000 0000000 00000000216 00000000000 014611 0 ustar 00 """
__main__.py.
This lets you run python -m proselint.
"""
from .command_line import proselint
if __name__ == '__main__':
proselint()
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/__init__.py 0000644 0000000 0000000 00000000101 00000000000 016061 0 ustar 00 """All the checks are organized into modules and places here."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/airlinese/__init__.py 0000644 0000000 0000000 00000000021 00000000000 020035 0 ustar 00 """Airlinese."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/airlinese/misc.py 0000644 0000000 0000000 00000001057 00000000000 017243 0 ustar 00 """Airlinese.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: Airlinese
date: 2014-06-10 12:31:19
categories: writing
---
Airlinese.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "airlinese.misc"
msg = "'{}' is airlinese."
airlinese = [
"enplan(?:e|ed|ing|ement)",
"deplan(?:e|ed|ing|ement)",
"taking off momentarily",
]
return existence_check(text, airlinese, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/annotations/__init__.py 0000644 0000000 0000000 00000000023 00000000000 020421 0 ustar 00 """Annotations."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/annotations/misc.py 0000644 0000000 0000000 00000001173 00000000000 017624 0 ustar 00 """Annotation left in text.
---
layout: post
source: SublimeLinter-annotations
source_url: http://bit.ly/16Q7H41
title: archaism
date: 2014-06-10 12:31:19
categories: writing
---
Annotation left in text.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "annotations.misc"
msg = "Annotation left in text."
annotations = [
"FIXME",
"FIX ME",
"TODO",
"todo",
"ERASE THIS",
"FIX THIS",
]
return existence_check(
text, annotations, err, msg, ignore_case=False, join=True)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/archaism/__init__.py 0000644 0000000 0000000 00000000020 00000000000 017650 0 ustar 00 """Archaism."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/archaism/misc.py 0000644 0000000 0000000 00000003436 00000000000 017062 0 ustar 00 """Archaism.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: archaism
date: 2014-06-10 12:31:19
categories: writing
---
Archaism.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "archaism.misc"
msg = "'{}' is archaic."
archaisms = [
"alack",
"anent",
# "anon",
"begat",
"belike",
"betimes",
"boughten",
"brocage",
"brokage",
"camarade",
"chiefer",
"chiefest",
"Christiana",
"completely obsolescent",
"cozen",
"divers",
"deflexion",
"durst",
"fain",
"forsooth",
"foreclose from",
"haply",
"howbeit",
"illumine",
"in sooth",
"maugre",
"meseems",
"methinks",
"nigh",
"peradventure",
"perchance",
"saith",
"shew",
"sistren",
"spake",
"to wit",
"verily",
"whilom",
"withal",
"wot",
"enclosed please find",
"please find enclosed",
"enclosed herewith",
"enclosed herein",
"inforce",
"ex postfacto",
"foreclose from",
"forewent",
"for ever",
# "designer", when used to mean a plotter against Christ
# "demean", when used to mean "to behave" in legal contexts
# "by the bye", # variant, modern is "by the by"
# "comptroller" # in British English
# "abortive" Abortive is archaic in reference to abortions of fetuses,
# except in the sense “causing an abortion.”
]
return existence_check(text, archaisms, err, msg, join=True)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/cliches/__init__.py 0000644 0000000 0000000 00000000025 00000000000 017500 0 ustar 00 """Avoid cliches."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/cliches/hell.py 0000644 0000000 0000000 00000001021 00000000000 016662 0 ustar 00 """Too much yelling.
---
layout: post
source: ???
source_url: ???
title: yelling
date: 2014-06-10 12:31:19
categories: writing
---
Never use the phrase 'all hell broke loose'.
"""
from proselint.tools import existence_check, max_errors, memoize
@max_errors(1)
@memoize
def check_repeated_exclamations(text):
"""Check the text."""
err = "leonard.hell"
msg = "Never use the words 'all hell broke loose'."
regex = r"all hell broke loose"
return existence_check(text, [regex], err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/cliches/misc.py 0000644 0000000 0000000 00000061366 00000000000 016713 0 ustar 00 """Cliches are cliché."""
from proselint.tools import existence_check, memoize
@memoize
def check_cliches_garner(text):
"""Check the text.
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
"""
err = "cliches.garner"
msg = "'{}' is cliché."
cliches = [
"a fate worse than death",
"alas and alack",
"at the end of the day",
"bald-faced lie",
"between a rock and a hard place",
"between Scylla and Charybdis",
"between the devil and the deep blue sea",
"betwixt and between",
"blissful ignorance",
"blow a fuse",
"bulk large",
"but that's another story",
"cast aspersions",
"chase a red herring",
"comparing apples and oranges",
"compleat",
"conspicuous by its absence",
"crystal clear",
"cutting edge",
"decision-making process",
"dubious distinction",
"duly authorized",
"eyes peeled",
"far be it from me",
"fast and loose",
"fills the bill",
"first and foremost",
"for free",
"get with the program",
"gilding the lily",
"have a short fuse",
"he's got his hands full",
"his own worst enemy",
"his work cut out for him",
"hither and yon",
"Hobson's choice",
"horns of a dilemma",
"if you catch my drift",
"in light of",
"in the final analysis",
"in the last analysis",
"innocent bystander",
"it's not what you know, it's who you know",
"last but not least",
"make a mockery of",
"male chauvinism",
"moment of truth",
"more in sorrow than in anger",
"more sinned against than sinning",
"my better half",
"nip in the bud",
"olden days",
"on the same page",
"presidential timber",
"pulled no punches",
"quantum jump",
"quantum leap",
"redound to one's credit",
"redound to the benefit of",
"sea change",
"shirked his duties",
"six of one, half a dozen of the other",
"stretched to the breaking point",
"than you can shake a stick at",
"the cream of the crop",
"the cream rises to the top",
"the straw that broke the camel's back",
"thick as thieves",
"thinking outside the box",
"thought leaders?",
"throw the baby out with the bathwater",
"various and sundry",
"viable alternative",
"wax eloquent",
"wax poetic",
"we've got a situation here",
"whet (?:the|your) appetite",
"wool pulled over our eyes",
"writ large",
]
return existence_check(text, cliches, err, msg, join=True)
@memoize
def check_cliches_write_good(text):
"""Check the text.
source: write-good
source_url: https://github.com/btford/write-good
"""
err = "cliches.write_good"
msg = "'{}' is a cliché."
cliches = [
"a chip off the old block",
"a clean slate",
"a dark and stormy night",
"a far cry",
"a fine kettle of fish",
"a loose cannon",
"a penny saved is a penny earned",
"a tough row to hoe",
"a word to the wise",
"ace in the hole",
"acid test",
"add insult to injury",
"against all odds",
"air your dirty laundry",
"all fun and games",
"all in a day's work",
"all talk, no action",
"all thumbs",
"all your eggs in one basket",
"all's fair in love and war",
"all's well that ends well",
"almighty dollar",
"American as apple pie",
"an axe to grind",
"another day, another dollar",
"armed to the teeth",
"as luck would have it",
"as old as time",
"as the crow flies",
"at loose ends",
"at my wits end",
"avoid like the plague",
"babe in the woods",
"back against the wall",
"back in the saddle",
"back to square one",
"back to the drawing board",
"bad to the bone",
"badge of honor",
"bald faced liar",
"ballpark figure",
"banging your head against a brick wall",
"baptism by fire",
"barking up the wrong tree",
"bat out of hell",
"be all and end all",
"beat a dead horse",
"beat around the bush",
"been there, done that",
"beggars can't be choosers",
"behind the eight ball",
"bend over backwards",
"benefit of the doubt",
"bent out of shape",
"best thing since sliced bread",
"bet your bottom dollar",
"better half",
"better late than never",
"better mousetrap",
"better safe than sorry",
"between a rock and a hard place",
"beyond the pale",
"bide your time",
"big as life",
"big cheese",
"big fish in a small pond",
"big man on campus",
"bigger they are the harder they fall",
"bird in the hand",
"bird's eye view",
"birds and the bees",
"birds of a feather flock together",
"bit the hand that feeds you",
"bite the bullet",
"bite the dust",
"bitten off more than he can chew",
"black as coal",
"black as pitch",
"black as the ace of spades",
"blast from the past",
"bleeding heart",
"blessing in disguise",
"blind ambition",
"blind as a bat",
"blind leading the blind",
"blood is thicker than water",
"blood sweat and tears",
"blow off steam",
"blow your own horn",
"blushing bride",
"boils down to",
"bolt from the blue",
"bone to pick",
"bored stiff",
"bored to tears",
"bottomless pit",
"boys will be boys",
"bright and early",
"brings home the bacon",
"broad across the beam",
"broken record",
"brought back to reality",
"bull by the horns",
"bull in a china shop",
"burn the midnight oil",
"burning question",
"burning the candle at both ends",
"burst your bubble",
"bury the hatchet",
"busy as a bee",
"by hook or by crook",
"call a spade a spade",
"called onto the carpet",
"calm before the storm",
"can of worms",
"can't cut the mustard",
"can't hold a candle to",
"case of mistaken identity",
"cat got your tongue",
"cat's meow",
"caught in the crossfire",
"caught red-handed",
"checkered past",
"chomping at the bit",
"cleanliness is next to godliness",
"clear as a bell",
"clear as mud",
"close to the vest",
"cock and bull story",
"cold shoulder",
"come hell or high water",
"cool as a cucumber",
"cool, calm, and collected",
"cost a king's ransom",
"count your blessings",
"crack of dawn",
"crash course",
"creature comforts",
"cross that bridge when you come to it",
"crushing blow",
"cry like a baby",
"cry me a river",
"cry over spilt milk",
"crystal clear",
"curiosity killed the cat",
"cut and dried",
"cut through the red tape",
"cut to the chase",
"cute as a bugs ear",
"cute as a button",
"cute as a puppy",
"cuts to the quick",
"dark before the dawn",
"day in, day out",
"dead as a doornail",
"devil is in the details",
"dime a dozen",
"divide and conquer",
"dog and pony show",
"dog days",
"dog eat dog",
"dog tired",
"don't burn your bridges",
"don't count your chickens",
"don't look a gift horse in the mouth",
"don't rock the boat",
"don't step on anyone's toes",
"don't take any wooden nickels",
"down and out",
"down at the heels",
"down in the dumps",
"down the hatch",
"down to earth",
"draw the line",
"dressed to kill",
"dressed to the nines",
"drives me up the wall",
"dull as dishwater",
"dyed in the wool",
"eagle eye",
"ear to the ground",
"early bird catches the worm",
"easier said than done",
"easy as pie",
"eat your heart out",
"eat your words",
"eleventh hour",
"even the playing field",
"every dog has its day",
"every fiber of my being",
"everything but the kitchen sink",
"eye for an eye",
"face the music",
"facts of life",
"fair weather friend",
"fall by the wayside",
"fan the flames",
"feast or famine",
"feather your nest",
"feathered friends",
"few and far between",
"fifteen minutes of fame",
"filthy vermin",
"fine kettle of fish",
"fish out of water",
"fishing for a compliment",
"fit as a fiddle",
"fit the bill",
"fit to be tied",
"flash in the pan",
"flat as a pancake",
"flip your lid",
"flog a dead horse",
"fly by night",
"fly the coop",
"follow your heart",
"for all intents and purposes",
"for the birds",
"for what it's worth",
"force of nature",
"force to be reckoned with",
"forgive and forget",
"fox in the henhouse",
"free and easy",
"free as a bird",
"fresh as a daisy",
"full steam ahead",
"fun in the sun",
"garbage in, garbage out",
"gentle as a lamb",
"get a kick out of",
"get a leg up",
"get down and dirty",
"get the lead out",
"get to the bottom of",
"get your feet wet",
"gets my goat",
"gilding the lily",
"give and take",
"go against the grain",
"go at it tooth and nail",
"go for broke",
"go him one better",
"go the extra mile",
"go with the flow",
"goes without saying",
"good as gold",
"good deed for the day",
"good things come to those who wait",
"good time was had by all",
"good times were had by all",
"greased lightning",
"greek to me",
"green thumb",
"green-eyed monster",
"grist for the mill",
"growing like a weed",
"hair of the dog",
"hand to mouth",
"happy as a clam",
"happy as a lark",
"hasn't a clue",
"have a nice day",
"have high hopes",
"have the last laugh",
"haven't got a row to hoe",
"head honcho",
"head over heels",
"hear a pin drop",
"heard it through the grapevine",
"heart's content",
"heavy as lead",
"hem and haw",
"high and dry",
"high and mighty",
"high as a kite",
"hit paydirt",
"hold your head up high",
"hold your horses",
"hold your own",
"hold your tongue",
"honest as the day is long",
"horns of a dilemma",
"horse of a different color",
"hot under the collar",
"hour of need",
"I beg to differ",
"icing on the cake",
"if the shoe fits",
"if the shoe were on the other foot",
"in a jam",
"in a jiffy",
"in a nutshell",
"in a pig's eye",
"in a pinch",
"in a word",
"in hot water",
"in the gutter",
"in the nick of time",
"in the thick of it",
"in your dreams",
"it ain't over till the fat lady sings",
"it goes without saying",
"it takes all kinds",
"it takes one to know one",
"it's a small world",
"it's only a matter of time",
"ivory tower",
"Jack of all trades",
"jockey for position",
"jog your memory",
"joined at the hip",
"judge a book by its cover",
"jump down your throat",
"jump in with both feet",
"jump on the bandwagon",
"jump the gun",
"jump to conclusions",
"just a hop, skip, and a jump",
"just the ticket",
"justice is blind",
"keep a stiff upper lip",
"keep an eye on",
"keep it simple, stupid",
"keep the home fires burning",
"keep up with the Joneses",
"keep your chin up",
"keep your fingers crossed",
"kick the bucket",
"kick up your heels",
"kick your feet up",
"kid in a candy store",
"kill two birds with one stone",
"kiss of death",
"knock it out of the park",
"knock on wood",
"knock your socks off",
"know him from Adam",
"know the ropes",
"know the score",
"knuckle down",
"knuckle sandwich",
"knuckle under",
"labor of love",
"ladder of success",
"land on your feet",
"lap of luxury",
"last but not least",
"last hurrah",
"last-ditch effort",
"law of the jungle",
"law of the land",
"lay down the law",
"leaps and bounds",
"let sleeping dogs lie",
"let the cat out of the bag",
"let the good times roll",
"let your hair down",
"let's talk turkey",
"letter perfect",
"lick your wounds",
"lies like a rug",
"life's a bitch",
"life's a grind",
"light at the end of the tunnel",
"lighter than a feather",
"lighter than air",
"like clockwork",
"like father like son",
"like taking candy from a baby",
"like there's no tomorrow",
"lion's share",
"live and learn",
"live and let live",
"long and short of it",
"long lost love",
"look before you leap",
"look down your nose",
"look what the cat dragged in",
"looking a gift horse in the mouth",
"looks like death warmed over",
"loose cannon",
"lose your head",
"lose your temper",
"loud as a horn",
"lounge lizard",
"loved and lost",
"low man on the totem pole",
"luck of the draw",
"luck of the Irish",
"make hay while the sun shines",
"make money hand over fist",
"make my day",
"make the best of a bad situation",
"make the best of it",
"make your blood boil",
"man of few words",
"man's best friend",
"mark my words",
"meaningful dialogue",
"missed the boat on that one",
"moment in the sun",
"moment of glory",
"moment of truth",
"money to burn",
"more power to you",
"more than one way to skin a cat",
"movers and shakers",
"moving experience",
"naked as a jaybird",
"naked truth",
"neat as a pin",
"needle in a haystack",
"needless to say",
"neither here nor there",
"never look back",
"never say never",
"nip and tuck",
"nip it in the bud",
"no guts, no glory",
"no love lost",
"no pain, no gain",
"no skin off my back",
"no stone unturned",
"no time like the present",
"no use crying over spilled milk",
"nose to the grindstone",
"not a hope in hell",
"not a minute's peace",
"not in my backyard",
"not playing with a full deck",
"not the end of the world",
"not written in stone",
"nothing to sneeze at",
"nothing ventured nothing gained",
"now we're cooking",
"off the top of my head",
"off the wagon",
"off the wall",
"old hat",
"older and wiser",
"older than dirt",
"older than Methuselah",
"on a roll",
"on cloud nine",
"on pins and needles",
"on the bandwagon",
"on the money",
"on the nose",
"on the rocks",
"on the spot",
"on the tip of my tongue",
"on the wagon",
"on thin ice",
"once bitten, twice shy",
"one bad apple doesn't spoil the bushel",
"one born every minute",
"one brick short",
"one foot in the grave",
"one in a million",
"one red cent",
"only game in town",
"open a can of worms",
"open and shut case",
"open the flood gates",
"opportunity doesn't knock twice",
"out of pocket",
"out of sight, out of mind",
"out of the frying pan into the fire",
"out of the woods",
"out on a limb",
"over a barrel",
"over the hump",
"pain and suffering",
"pain in the",
"panic button",
"par for the course",
"part and parcel",
"party pooper",
"pass the buck",
"patience is a virtue",
"pay through the nose",
"penny pincher",
"perfect storm",
"pig in a poke",
"pile it on",
"pillar of the community",
"pin your hopes on",
"pitter patter of little feet",
"plain as day",
"plain as the nose on your face",
"play by the rules",
"play your cards right",
"playing the field",
"playing with fire",
"pleased as punch",
"plenty of fish in the sea",
"point with pride",
"poor as a church mouse",
"pot calling the kettle black",
"pretty as a picture",
"pull a fast one",
"pull your punches",
"pulling your leg",
"pure as the driven snow",
"put it in a nutshell",
"put one over on you",
"put the cart before the horse",
"put the pedal to the metal",
"put your best foot forward",
"put your foot down",
"quick as a bunny",
"quick as a lick",
"quick as a wink",
"quick as lightning",
"quiet as a dormouse",
"rags to riches",
"raining buckets",
"raining cats and dogs",
"rank and file",
"rat race",
"reap what you sow",
"red as a beet",
"red herring",
"reinvent the wheel",
"rich and famous",
"rings a bell",
"ripe old age",
"ripped me off",
"rise and shine",
"road to hell is paved with good intentions",
"rob Peter to pay Paul",
"roll over in the grave",
"rub the wrong way",
"ruled the roost",
"running in circles",
"sad but true",
"sadder but wiser",
"salt of the earth",
"scared stiff",
"scared to death",
"sealed with a kiss",
"second to none",
"see eye to eye",
"seen the light",
"seize the day",
"set the record straight",
"set the world on fire",
"set your teeth on edge",
"sharp as a tack",
"shoot for the moon",
"shoot the breeze",
"shot in the dark",
"shoulder to the wheel",
"sick as a dog",
"sigh of relief",
"signed, sealed, and delivered",
"sink or swim",
"six of one, half a dozen of another",
"skating on thin ice",
"slept like a log",
"slinging mud",
"slippery as an eel",
"slow as molasses",
"smart as a whip",
"smooth as a baby's bottom",
"sneaking suspicion",
"snug as a bug in a rug",
"sow wild oats",
"spare the rod, spoil the child",
"speak of the devil",
"spilled the beans",
"spinning your wheels",
"spitting image of",
"spoke with relish",
"spread like wildfire",
"spring to life",
"squeaky wheel gets the grease",
"stands out like a sore thumb",
"start from scratch",
"stick in the mud",
"still waters run deep",
"stitch in time",
"stop and smell the roses",
"straight as an arrow",
"straw that broke the camel's back",
"strong as an ox",
"stubborn as a mule",
"stuff that dreams are made of",
"stuffed shirt",
"sweating blood",
"sweating bullets",
"take a load off",
"take one for the team",
"take the bait",
"take the bull by the horns",
"take the plunge",
"takes one to know one",
"takes two to tango",
"the more the merrier",
"the real deal",
"the real McCoy",
"the red carpet treatment",
"the same old story",
"there is no accounting for taste",
"thick as a brick",
"thick as thieves",
"thin as a rail",
"think outside of the box",
"third time's the charm",
"this day and age",
"this hurts me worse than it hurts you",
"this point in time",
"three sheets to the wind",
"through thick and thin",
"throw in the towel",
"tie one on",
"tighter than a drum",
"time and time again",
"time is of the essence",
"tip of the iceberg",
"tired but happy",
"to coin a phrase",
"to each his own",
"to make a long story short",
"to the best of my knowledge",
"toe the line",
"tongue in cheek",
"too good to be true",
"too hot to handle",
"too numerous to mention",
"touch with a ten foot pole",
"tough as nails",
"trial and error",
"trials and tribulations",
"tried and true",
"trip down memory lane",
"twist of fate",
"two cents worth",
"two peas in a pod",
"ugly as sin",
"under the counter",
"under the gun",
"under the same roof",
"under the weather",
"until the cows come home",
"unvarnished truth",
"up the creek",
"uphill battle",
"upper crust",
"upset the applecart",
"vain attempt",
"vain effort",
"vanquish the enemy",
"vested interest",
"waiting for the other shoe to drop",
"wakeup call",
"warm welcome",
"watch your p's and q's",
"watch your tongue",
"watching the clock",
"water under the bridge",
"weather the storm",
"weed them out",
"week of Sundays",
"went belly up",
"wet behind the ears",
"what goes around comes around",
"what you see is what you get",
"when it rains, it pours",
"when push comes to shove",
"when the cat's away",
"when the going gets tough, the tough get going",
"white as a sheet",
"whole ball of wax",
"whole hog",
"whole nine yards",
"wild goose chase",
"will wonders never cease?",
"wisdom of the ages",
"wise as an owl",
"wolf at the door",
"words fail me",
"work like a dog",
"world weary",
"worst nightmare",
"worth its weight in gold",
"wrong side of the bed",
"yanking your chain",
"yappy as a dog",
"years young",
"you are what you eat",
"you can run but you can't hide",
"you only live once",
"you're the boss ",
"young and foolish",
"young and vibrant",
]
return existence_check(text, cliches, err, msg, join=True)
@memoize
def check_cliches_gnu_diction(text):
"""Check the text.
source: GNU diction
source_url: https://directory.fsf.org/wiki/Diction
"""
err = "cliches.gnu_diction"
msg = "'{}' is a cliché."
list = [
"a matter of concern",
"all things being equal",
"as a last resort",
"attached hereto",
"by no means",
"conspicuous by its absence",
"easier said than done",
"enclosed herewith",
"if and when",
"in reference to",
"in short supply",
"in the foreseeable future",
"in the long run",
"in the matter of",
"it stands to reason",
"many and diverse",
"on the right track",
"par for the course",
"please feel free to",
"pursuant to your request",
"regarding the matter of",
"slowly but surely",
"this will acknowledge",
"we are pleased to advice",
"we regret to inform you",
"we wish to state",
"you are hereby advised that",
]
return existence_check(text, list, err, msg, join=True, ignore_case=True)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/consistency/__init__.py 0000644 0000000 0000000 00000000042 00000000000 020426 0 ustar 00 """Various consistency checks."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/consistency/spacing.py 0000644 0000000 0000000 00000001202 00000000000 020312 0 ustar 00 """Mixed one vs. two spaces after a period.
---
layout: post
source: Consistency.
source_url: ???
title: Mixed use of 1 vs. 2 spaces after a period.
date: 2014-06-10 12:31:19
categories: writing
---
Points out instances where there are two conventions, 1 vs. 2 spaces after
a period, in the same document.
"""
from proselint.tools import consistency_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "consistency.spacing"
msg = "Inconsistent spacing after period (1 vs. 2 spaces)."
regex = [r"[\.\?!] [A-Z]", r"[\.\?!] [A-Z]"]
return consistency_check(text, [regex], err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/consistency/spelling.py 0000644 0000000 0000000 00000002652 00000000000 020515 0 ustar 00 """Inconsistent spelling.
---
layout: post
source: Intelligent Editing Ltd.
source_url: http://bit.ly/1x3hYj7
title: Inconsistent spelling
date: 2014-06-10 12:31:19
categories: writing
---
Intelligent Editing Ltd. says:
> Some words have more than one correct spelling. American, British, Australian
and Canadian English all have their own preferences. Even within those, there
can be multiple spellings. For example, in the UK 'realise' is often preferred.
However, 'realize' has been used in British-English for centuries and is
preferred in the Oxford English Dictionary. However, no matter which spelling
is preferred, one thing is always wrong: you mustn't use two different
spellings in the same document.
"""
from proselint.tools import consistency_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "consistency.spelling"
msg = "Inconsistent spelling of '{}' (vs. '{}')."
word_pairs = [
["advisor", "adviser"],
# ["analyse", "analyze"],
["centre", "center"],
["colour", "color"],
["emphasise", "emphasize"],
["finalise", "finalize"],
["focussed", "focused"],
["labour", "labor"],
["learnt", "learned"],
["organise", "organize"],
["organised", "organized"],
["organising", "organizing"],
["recognise", "recognize"],
]
return consistency_check(text, word_pairs, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/corporate_speak/__init__.py 0000644 0000000 0000000 00000000027 00000000000 021251 0 ustar 00 """Corporate-speak."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/corporate_speak/misc.py 0000644 0000000 0000000 00000002363 00000000000 020452 0 ustar 00 """Corporate speak.
---
layout: post
source: Travis Bradberry for Inc.com
source_url: http://bit.ly/1IxWnto
title: corporate speak
date: 2014-06-10 12:31:19
categories: writing
---
Avoid these cases of business jargon.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "corporate_speak.misc"
msg = "Minimize your use of corporate catchphrases like this one."
list = [
"at the end of the day",
"back to the drawing board",
"hit the ground running",
"get the ball rolling",
"low-hanging fruit",
"thrown under the bus",
"think outside the box",
"let's touch base",
"get my manager's blessing",
"it's on my radar",
"ping me",
"i don't have the bandwidth",
"no brainer",
"par for the course",
"bang for your buck",
"synergy",
"move the goal post",
"apples to apples",
"win-win",
"circle back around",
"all hands on deck",
"take this offline",
"drill-down",
"elephant in the room",
"on my plate",
]
return existence_check(text, list, err, msg, ignore_case=True)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/cursing/__init__.py 0000644 0000000 0000000 00000000017 00000000000 017541 0 ustar 00 """Cursing."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/cursing/filth.py 0000644 0000000 0000000 00000001255 00000000000 017115 0 ustar 00 """Filthy words.
---
layout: post
source: George Carlin
source_url: https://youtu.be/kyBH5oNQOS0
title: filthy words
date: 2014-06-10 12:31:19
categories: writing
---
Filthy words.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "cursing.filth"
msg = """Nobody ever tells you this as a kid, but you're supposed to avoid
this word."""
list = [
"shit",
"piss",
"fuck",
"cunt",
"cocksucker",
"motherfucker",
"tits",
"fart",
"turd",
"twat",
]
return existence_check(text, list, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/cursing/nfl.py 0000644 0000000 0000000 00000057175 00000000000 016602 0 ustar 00 """Words the NFL won't print on a jersey.
---
layout: post
source: The National Football League
source_url: http://bit.ly/1ISK0rb
title: words the NFL won't print on a jersey
date: 2014-06-10 12:31:19
categories: writing
---
Words the NFL won't print on a jersey.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "cursing.nfl"
msg = "The NFL won't print this word on a jersey."
list = [
"420",
"666",
"2 on 1",
"3rd eye",
"3rd leg",
"3rdeye",
"3rdleg",
"3some",
"4 twenty",
"4twenty",
"60 nine",
"60nine",
"a.s.s.",
"anal",
"anal annie",
"anal sex",
"analannie",
"analsex",
"anus",
"arse",
"ass",
"ass bagger",
"ass blaster",
"ass clown",
"ass cowboy",
"ass fuck",
"ass fucker",
"ass hole",
"ass holes",
"ass hore",
"ass jockey",
"ass kiss",
"ass kisser",
"ass klown",
"ass lick",
"ass licker",
"ass lover",
"ass man",
"ass monkey",
"ass munch",
"ass muncher",
"ass packer",
"ass pirate",
"ass puppies",
"ass ranger",
"ass whore",
"ass wipe",
"assbagger",
"assblaster",
"assclown",
"asscowboy",
"assfuck",
"assfucker",
"asshole",
"assholes",
"asshore",
"assjockey",
"asskiss",
"asskisser",
"assklown",
"asslick",
"asslicker",
"asslover",
"assman",
"assmonkey",
"assmunch",
"assmuncher",
"asspacker",
"asspirate",
"asspuppies",
"assranger",
"asswhore",
"asswipe",
"athletes foot",
"athletesfoot",
"axing the weasel",
"b hard",
"back door",
"back door man",
"backdoor",
"backdoorman",
"backseat",
"bad ass",
"bad fuck",
"badfuck",
"ball licker",
"ball sack",
"balllicker",
"balls",
"ballsack",
"banging",
"barely legal",
"barelylegal",
"barf",
"barf face",
"barface",
"barfface",
"bastard",
"bazongas",
"bazooms",
"beastality",
"beastiality",
"beat off",
"beat your meat",
"beatoff",
"beat-off",
"beatyourmeat",
"bi",
"bi sexual",
"biatch",
"big ass",
"big bitch",
"big bitch",
"big butt",
"bigass",
"bigbastard",
"bigbutt",
"bisexual",
"bi-sexual",
"bitch",
"bitches",
"bitchin",
"bitchy",
"bite me",
"biteme",
"black out",
"blackout",
"blow job",
"blowjob",
"bm",
"boner",
"bong",
"boobies",
"boobs",
"boody",
"breast",
"breast job",
"breast lover",
"breast man",
"breastjob",
"breastlover",
"breastman",
"budweiser",
"bull crap",
"bull dike",
"bull dyke",
"bull shit",
"bullcrap",
"bulldike",
"bulldyke",
"bullshit",
"bumble fuck",
"bumblefuck",
"bumfuck",
"bunghole",
"butch babes",
"butch dike",
"butch dyke",
"butchbabes",
"butchdike",
"butchdyke",
"butt bang",
"butt fuck",
"butt fucker",
"butt fuckers",
"butt head",
"butt man",
"butt plug",
"butt stain",
"buttbang",
"butt-bang",
"buttface",
"buttfuck",
"butt-fuck",
"buttfucker",
"butt-fucker",
"buttfuckers",
"butt-fuckers",
"butthead",
"buttman",
"buttpirate",
"buttplug",
"buttstain",
"camel toe",
"cameltoe",
"carpet muncher",
"carpetmuncher",
"carruth",
"cherry popper",
"cherrypopper",
"chick slick",
"chickslick",
"clam digger",
"clam diver",
"clamdigger",
"clamdiver",
"clit",
"clitoris",
"cock",
"cock block",
"cock blocker",
"cock cowboy",
"cock fight",
"cock knob",
"cock licker",
"cock lover",
"cock nob",
"cock queen",
"cock rider",
"cock smith",
"cock sucker",
"cock tail",
"cock tease",
"cockblock",
"cockblocker",
"cockcowboy",
"cockfight",
"cockhead",
"cockknob",
"cocklicker",
"cocklover",
"cocknob",
"cockqueen",
"cockrider",
"cocks man",
"cocksman",
"cocksmith",
"cocksucer",
"cocksucker",
"cocktail",
"cocktease",
"cocky",
"condom",
"copulate",
"corn hole",
"cornhole",
"crabs",
"crack",
"crack pipe",
"crack whore",
"crackpipe",
"crackwhore",
"crack-whore",
"crap",
"crappy",
"creamy",
"crotch",
"crotch jockey",
"crotch monkey",
"crotch rot",
"crotchjockey",
"crotchmonkey",
"crotchrot",
"cum",
"cum bubble",
"cum fest",
"cum jockey",
"cum quat",
"cum queen",
"cum shot",
"cumbubble",
"cumfest",
"cumjockey",
"cumm",
"cumming",
"cumquat",
"cumqueen",
"cumshot",
"cunnilingus",
"cunt",
"cunt fuck",
"cunt fucker",
"cunt licker",
"cuntfuck",
"cuntfucker",
"cuntlicker",
"cyber sex",
"cyber slimer",
"cybersex",
"cyberslimer",
"dahmer",
"damn",
"damn it",
"damnit",
"datnigga",
"dd",
"deap throat",
"deaper",
"deapthroat",
"deep throat",
"deeper",
"deepthroat",
"defecate",
"deposit",
"devil",
"dick brain",
"dick fart",
"dick for brains",
"dick head",
"dick lick",
"dick licker",
"dick likcer",
"dick wad",
"dick weed",
"dickbrain",
"dickforbrains",
"dickhead",
"dickless",
"dicklick",
"dicklicker",
"dickman",
"dickwad",
"dickweed",
"dike",
"dildo",
"dip stick",
"dipstick",
"dirty ho",
"dix",
"dixie dike",
"dixie dyke",
"dixiedike",
"dixiedyke",
"do me",
"doggie style",
"doggiestyle",
"doggy stlye",
"doggystyle",
"dome",
"dong",
"dope",
"double d",
"doubled",
"drag queen",
"dragqueen",
"dragqween",
"dre",
"drip dick",
"dripdick",
"drunk",
"drunken",
"dumb ass",
"dumb bitch",
"dumb fuck",
"dumbass",
"dumbbitch",
"dumbfuck",
"easy slut",
"easyslut",
"eat me",
"eat pussy",
"eatballs",
"eatme",
"eatpussy",
"ejaculate",
"erection",
"evl",
"excrement",
"f toyota",
"f.i.n.e.",
"f.u.c.k.",
"face fucker",
"facefucker",
"faggot",
"fagot",
"fairy",
"fanny fucker",
"fannyfucker",
"fart",
"fast fuck",
"fastfuck",
"fat ass",
"fat fuck",
"fat fucker",
"fatass",
"fatfuck",
"fatfucker",
"fatso",
"fellatio",
"femme",
"finger food",
"finger fuck",
"finger fucker",
"fingerfood",
"fingerfuck",
"fingerfucker",
"fist fuck",
"fist fucker",
"fistfuck",
"fistfucker",
"fisting",
"flasher",
"flatulence",
"floggin the dolphin",
"fondle",
"foot fuck",
"foot fucker",
"foot licker",
"footaction",
"footfuck",
"footfucker",
"footlicker",
"footstar",
"fore skin",
"foreskin",
"fornicate",
"four 20",
"four twenty",
"four20",
"fourtwenty",
"freak fuck",
"freakfuck",
"freaky fucker",
"freakyfucker",
"free 4 all",
"free for all",
"free fuck",
"free4all",
"freeforall",
"freefuck",
"fuck",
"fuck bag",
"fuck buddy",
"fuck face",
"fuck fest",
"fuck freak",
"fuck friend",
"fuck head",
"fuck her",
"fuck it",
"fuck knob",
"fuck me",
"fuck me hard",
"fuck monkey",
"fuck off",
"fuck pig",
"fuck them",
"fuck whore",
"fuck you",
"fucka",
"fuckable",
"fuckbag",
"fuckbuddy",
"fucked",
"fucked up",
"fuckedup",
"fucker",
"fuckers",
"fuckface",
"fuckfest",
"fuckfreak",
"fuckfriend",
"fuckhead",
"fuckher",
"fuckin",
"fuckin a",
"fuckin nuts",
"fuckin right",
"fuckina",
"fucking",
"fucking a",
"fucking bitch",
"fucking nuts",
"fuckingbitch",
"fuckinnuts",
"fuckinright",
"fuckit",
"fuckknob",
"fuckme",
"fuckmehard",
"fuckmonkey",
"fuckoff",
"fuckpig",
"fuckwhore",
"fuckyou",
"fudge pakcers",
"fun fuck",
"funfuck",
"fuuck",
"g unit",
"gang bang",
"gang banger",
"gangbang",
"gangbanger",
"gay",
"gay ass",
"gay mutha fuckin queer",
"gay pride",
"gaymuthafuckinwhore",
"genital",
"get it on",
"getiton",
"giehn",
"give head",
"givehead",
"glazed donut",
"glazeddonut",
"go me",
"go to hell",
"god",
"god damed mutha fucka",
"god damit",
"god damn",
"god damned",
"god manit",
"goddamit",
"goddamn",
"goddamned",
"goddamnes",
"goddamnit",
"goddamnmuthafucker",
"gonorrehea",
"gonzagas",
"gook",
"got jesus",
"got2haveit",
"gotohell",
"g-unit",
"hand job",
"handjob",
"hard on",
"harder",
"hardon",
"harem",
"he hate me",
"head fuck",
"head lights",
"headfuck",
"headlights",
"hehateme",
"hell",
"hell no",
"hell yes",
"hellno",
"hellyes",
"hen house",
"henhouse",
"herpes",
"hershey hi way",
"hersheyhighway",
"hersheyhiway",
"hershy high way",
"ho",
"ho mo",
"hobo",
"hole",
"hole stuffer",
"holestuffer",
"homo",
"homo bangers",
"homo sexual",
"homobangers",
"homosexual",
"honkers",
"honkey",
"hooker",
"hookers",
"hooters",
"hore",
"horney",
"horny",
"horseshit",
"hose job",
"hosejob",
"hoser",
"hostage",
"hot damn",
"hot pussy",
"hot to trot",
"hot2trot",
"hotdamn",
"hotpussy",
"hottotrot",
"hussy",
"hustler",
"i love beer",
"i luv beer",
"id ten t",
"id10t",
"idiot",
"idoit",
"in the ass",
"in the buff",
"ingin",
"insest",
"inter course",
"inter racial",
"intercourse",
"interracial",
"intheass",
"inthebuff",
"jack the ripper",
"jackass",
"jackoff",
"jacktheripper",
"jap",
"jap crap",
"japcrap",
"jerk off",
"jerkoff",
"jesus chirst",
"jesuschrist",
"jism",
"jiz",
"jiz juice",
"jizim",
"jizjuice",
"jizz",
"jizzim",
"joint",
"juggalo",
"jugs",
"k mart",
"kill",
"killer",
"killing",
"kiss ass",
"kissass",
"kkk",
"kmart",
"knockers",
"koon",
"kotex",
"krap",
"krappy",
"kum",
"kum bubble",
"kum quat",
"kumbubble",
"kumbullbe",
"kumquat",
"kunt",
"ky",
"ky jelly",
"lactate",
"lady boog",
"laid",
"lap dance",
"lapdance",
"lesbain",
"lesbayn",
"lesbian",
"lesbin",
"lesbo",
"lez",
"lez be",
"lez be friends",
"lezbe",
"lezbefriends",
"lezbo",
"lezz",
"lezzo",
"lick me",
"licker",
"lickme",
"limp dick",
"limpdick",
"limy",
"live sex",
"livesex",
"loaded gun",
"loadedgun",
"lolita",
"looser",
"lotion",
"love bone",
"love goo",
"love gun",
"love juice",
"love muscle",
"love pistol",
"love rocket",
"lovebone",
"lovegoo",
"lovegun",
"lovejuice",
"lovemuscle",
"lovepistol",
"loverocket",
"low life",
"lowlife",
"lube job",
"lubejob",
"lucky camel toe",
"luckycammeltoe",
"magic wand",
"magicwand",
"mams",
"man hater",
"man paste",
"manhater",
"manpaste",
"mary jane",
"maryjane",
"mastabate",
"mastabater",
"master blaster",
"masterbate",
"masterblaster",
"mastrabator",
"mattress princess",
"mattressprincess",
"meat beatter",
"meatbeatter",
"molest",
"molester",
"molestor",
"money shot",
"moneyshot",
"mother fucker",
"mother love bone",
"motherfuck",
"motherfucker",
"motherlovebone",
"muff",
"muff dive",
"muff diver",
"muff licker",
"muffdive",
"muffdiver",
"muffin diver",
"muffindiver",
"mufflikcer",
"murder",
"mutha fucker",
"naked",
"nasty bitch",
"nasty ho",
"nasty slut",
"nasty whore",
"nastybitch",
"nastyho",
"nastyslut",
"nastywhore",
"neon deon",
"nig",
"niger",
"nigga",
"nigger",
"nipple",
"nipple ring",
"nipplering",
"nit tit",
"nittit",
"no fucking way",
"no sex",
"nofuckingway",
"nookie",
"nooner",
"nude",
"nut fucker",
"nutfucker",
"oicu812",
"on the rag",
"ontherag",
"orgasm",
"orgy",
"ou812",
"oui",
"p i m p",
"pearl necklace",
"pearlnecklace",
"pecker",
"pee",
"peep show",
"peepshow",
"peepshpw",
"penetration",
"penis",
"penthouse",
"period",
"phque",
"pimp",
"pimp simp",
"pimped",
"pimper",
"pimpjuic",
"pimpjuice",
"pimpsimp",
"piss",
"piss head",
"pissed",
"pisser",
"pisshead",
"play boy",
"play girl",
"playboy",
"playgirl",
"pocket pool",
"pocketpool",
"polack",
"poon tang",
"poontang",
"poop",
"pooper",
"poor white trash",
"poorwhitetrash",
"popimp",
"porch monkey",
"porchmonkey",
"porn",
"porn flick",
"porn king",
"porn princess",
"pornflick",
"pornking",
"porno",
"pornprincess",
"pot",
"premature",
"prick",
"prick head",
"prickhead",
"primetime",
"prostitute",
"pubic",
"pubic lice",
"pubiclice",
"pud",
"pud boy",
"pudboy",
"pudd",
"pudd boy",
"puddboy",
"pun tang",
"puntang",
"purina princess",
"purinapricness",
"pussy",
"pussy cat",
"pussy eater",
"pussy fucker",
"pussy licker",
"pussy lips",
"pussy lover",
"pussy pounder",
"pussycat",
"pussyeater",
"pussyfucker",
"pussylicker",
"pussylips",
"pussylover",
"pussypounder",
"putt pirate",
"pwt",
"queef",
"queer",
"quickie",
"rae carruth",
"rape",
"rapist",
"rear end",
"rear entry",
"rearend",
"rearentry",
"rectum",
"red light",
"redlight",
"reefer",
"rent a fuck",
"rentafuck",
"retard",
"retarded",
"ribbed",
"rim job",
"rimjob",
"roach",
"robber",
"s and m",
"s&m",
"samckdaddy",
"sandm",
"satan",
"schlong",
"screw",
"screw you",
"screwyou",
"scrotum",
"semen",
"sex",
"sex farm",
"sex hound",
"sex house",
"sex kitten",
"sex pot",
"sex slave",
"sex to go",
"sex toy",
"sex toys",
"sex whore",
"sexfarm",
"sexhound",
"sexhouse",
"sexkitten",
"sexpot",
"sexslave",
"sextogo",
"sextoy",
"sextoys",
"sexual",
"sexwhore",
"sexy",
"sexy biatch",
"sexy bitch",
"sexy moma",
"sexy slim",
"sexymoma",
"sexy-slim",
"shag",
"shaggin",
"shagging",
"shawtypimp",
"shit",
"shit dick",
"shit eater",
"shit face",
"shit for brains",
"shit fuck",
"shit fucker",
"shit happens",
"shit head",
"shit out of luck",
"shit stain",
"shit4brains",
"shitdick",
"shiteater",
"shitface",
"shitforbrains",
"shitfuck",
"shitfucker",
"shithapens",
"shithappens",
"shithead",
"shitoutofluck",
"shits",
"shitstain",
"shitter",
"shitting",
"shitty",
"short fuck",
"shortfuck",
"showtime",
"six six six",
"sixsixsix",
"sixty 9",
"sixty nine",
"sixty9",
"sixtynine",
"skank",
"skank bitch",
"skank fuck",
"skank whore",
"skankbitch",
"skankfuck",
"skankwhore",
"skanky bitch",
"skanky whore",
"skankybitch",
"skankywhore",
"skin flute",
"skinflute",
"skum",
"skum bag",
"skumbag",
"slant",
"slant eye",
"slanteye",
"slave",
"slave driver",
"slavedriver",
"sleeze bag",
"sleeze ball",
"sleezebag",
"sleezeball",
"slide it in",
"slideitin",
"slime",
"slime ball",
"slime bucket",
"slimeball",
"slimebucket",
"slut",
"slut wear",
"slut whore",
"sluts",
"slutt",
"slutting",
"slutty",
"slutwear",
"slutwhore",
"smack daddy",
"smack the monkey",
"smackthemonkey",
"smagma",
"smart ass",
"snatch",
"snatch patch",
"snatchpatch",
"sniper",
"snot",
"sob",
"sodomite",
"sodomy",
"son of a bitch",
"sonofabitch",
"sonofbitch",
"spank the monkey",
"spankthemonkey",
"sperm",
"sperm bag",
"sperm hearder",
"sperm herder",
"spermacide",
"spermbag",
"spermhearder",
"spermherder",
"spic",
"spick",
"spit",
"spitter",
"split tail",
"split tial",
"splittail",
"stagg",
"strap on",
"strapon",
"stringer",
"strip club",
"stripclub",
"stroke",
"stroking",
"stupid",
"stupid fuck",
"stupid fucker",
"stupidfuck",
"stupidfucker",
"suck",
"suck dick",
"suck me",
"suck my ass",
"suck my dick",
"suck my tit",
"suck off",
"suckdick",
"sucker",
"suckme",
"suckmyass",
"suckmydick",
"suckmytit",
"suckoff",
"suicide",
"swallow",
"swallower",
"swalow",
"sweetness",
"swign dixx",
"swing dixx",
"swingin dixx",
"swinging dicks",
"syphilis",
"tampon",
"tang",
"testicle",
"testicles",
"third eye",
"third leg",
"thirdeye",
"thirdleg",
"three some",
"threesome",
"tit",
"tit bit nipply",
"tit fuck",
"tit fucker",
"tit fuckin",
"tit job",
"tit licker",
"tit lover",
"titbitnipply",
"titfuck",
"titfucker",
"titfuckin",
"titjob",
"titlicker",
"titlover",
"tits",
"titties",
"titty",
"toilet",
"toilet bowl",
"tongethruster",
"tongue",
"tongue thruster",
"tongue tramp",
"tonguethrust",
"tonguetramp",
"toung thruster",
"tounge baller",
"tounge thrust",
"trailer trash",
"trailertrash",
"tramp",
"tri sexual",
"triple x",
"triplex",
"trisexual",
"trojan",
"trots",
"tunnel of love",
"tunneloflove",
"turd",
"two bit whore",
"two on one",
"twobitwhore",
"unfuckable",
"up the ass",
"up the butt",
"upskirt",
"uptheass",
"upthebutt",
"urinate",
"urine",
"uterus",
"vagina",
"vaginal",
"vd",
"vibrater",
"vibrator",
"virgin",
"virgin breaker",
"virginbreaker",
"vulva",
"waysted",
"weenie",
"wet spot",
"wetspot",
"whacker",
"whiskey dick",
"whiskeydick",
"whisky dick",
"whiskydick",
"white trash",
"whitetrash",
"whore",
"whore fucker",
"whore house",
"whorefucker",
"whorehouse",
"wigger",
"willie wanker",
"williewanker",
"wuutang",
"xxx",
"yellow man",
"yellowman"
]
return existence_check(text, list, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/cursing/nword.py 0000644 0000000 0000000 00000001045 00000000000 017135 0 ustar 00 """On 'the N word'.
---
layout: post
source: Louis CK
source_url: https://youtu.be/dF1NUposXVQ?t=30s
title: the 'n-word'
date: 2014-06-10 12:31:19
categories: writing
---
Take responsibility with the shitty words you wanna say.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "cursing.nword"
msg = "Take responsibility for the shitty words you want to say."
list = [
"the n-word",
]
return existence_check(text, list, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/dates_times/__init__.py 0000644 0000000 0000000 00000000027 00000000000 020371 0 ustar 00 """Dates and times."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/dates_times/am_pm.py 0000644 0000000 0000000 00000002717 00000000000 017733 0 ustar 00 """a.m. / p.m.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: a.m. & p.m.
date: 2014-06-10 12:31:19
categories: writing
---
"""
from proselint.tools import existence_check, memoize
@memoize
def check_lowercase_periods(text):
"""Check the text."""
err = "dates_times.am_pm.lowercase_periods"
msg = "With lowercase letters, the periods are standard."
return existence_check(text, [r"\d{1,2} ?[ap]m"], err, msg,
ignore_case=False)
@memoize
def check_spacing(text):
"""Check the text."""
err = "dates_times.am_pm.spacing"
msg = "It's standard to put a space before 'a.m.' or 'p.m.'."
return existence_check(text, [r"\d{1,2}[ap]\.?m\.?"], err, msg)
@memoize
def check_midnight_noon(text):
"""Check the text."""
err = "dates_times.am_pm.midnight_noon"
msg = ("12 a.m. and 12 p.m. are wrong and confusing."
" Use 'midnight' or 'noon'.")
return existence_check(text, [r"12 ?[ap]\.?m\.?"], err, msg)
@memoize
def check_redundancy(text):
"""Check the text."""
err = "dates_times.am_pm.midnight_noon"
msg = ("'a.m.' is always morning; 'p.m.' is always night.")
list = [
r"\d{1,2} ?a\.?m\.? in the morning",
r"\d{1,2} ?p\.?m\.? in the evening",
r"\d{1,2} ?p\.?m\.? at night",
r"\d{1,2} ?p\.?m\.? in the afternoon",
]
return existence_check(text, list, err, msg, join=True)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/dates_times/dates.py 0000644 0000000 0000000 00000003213 00000000000 017732 0 ustar 00 """Dates.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: dates
date: 2014-06-10 12:31:19
categories: writing
---
Dates.
"""
import calendar
from proselint.tools import existence_check, memoize
@memoize
def check_decade_apostrophes_short(text):
"""Check the text for dates of the form X0's."""
err = "dates_times.dates"
msg = "Apostrophes aren't needed for decades."
regex = r"\d0\'s"
return existence_check(
text, [regex], err, msg, excluded_topics=["50 Cent"])
@memoize
def check_decade_apostrophes_long(text):
"""Check the text for dates of the form XXX0's."""
err = "dates_times.dates"
msg = "Apostrophes aren't needed for decades."
regex = r"\d\d\d0\'s"
return existence_check(text, [regex], err, msg)
@memoize
def check_dash_and_from(text):
"""Check the text."""
err = "dates_times.dates"
msg = "When specifying a date range, write 'from X to Y'."
regex = r"[fF]rom \d+[^ \t\n\r\f\va-zA-Z0-9_\.]\d+"
return existence_check(text, [regex], err, msg)
def check_month_year_comma(text):
"""Check the text."""
err = "dates_times.dates"
msg = "When specifying a month and year, no comma is needed."
regex = r"(?:" + "|".join(calendar.month_name[1:]) + r"), \d{3,}"
return existence_check(text, [regex], err, msg)
@memoize
def check_month_of_year(text):
"""Check the text."""
err = "dates_times.dates"
msg = "When specifying a month and year, 'of' is unnecessary."
regex = r"(?:" + "|".join(calendar.month_name[1:]) + r") of \d{3,}"
return existence_check(text, [regex], err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/hedging/__init__.py 0000644 0000000 0000000 00000000017 00000000000 017474 0 ustar 00 """Hedging."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/hedging/misc.py 0000644 0000000 0000000 00000001030 00000000000 016664 0 ustar 00 """Hedging.
---
layout: post
source: Pinker's book on writing
source_url: ???
title: hedging
date: 2014-06-10 12:31:19
categories: writing
---
Points out hedging.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "hedging.misc"
msg = "Hedging. Just say it."
narcissism = [
"I would argue that",
", so to speak",
"to a certain degree",
]
return existence_check(text, narcissism, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/hyperbole/__init__.py 0000644 0000000 0000000 00000000021 00000000000 020053 0 ustar 00 """Hyperbole."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/hyperbole/misc.py 0000644 0000000 0000000 00000000742 00000000000 017261 0 ustar 00 """Hyperbolic language.
---
layout: post
source: ???
source_url: ???
title: hyperbolic language
date: 2014-06-10 12:31:19
categories: writing
---
Hyperbolic language.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "hyperbolic.misc"
msg = "'{}' is hyperbolic."
words = [
r"[a-z]*[!]{2,}",
r"[a-z]*\?{2,}"
]
return existence_check(text, words, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/inprogress/capitalization_errors.py 0000644 0000000 0000000 00000001315 00000000000 023134 0 ustar 00 """Password in plain text.
---
layout: post
source: ???
source_url: ???
title: Capitalization of abbreviations
date: 2014-06-10 12:31:19
categories: writing
---
In Hybrid Zones, p 255 in a citation Hughes & Huges Systems Experts and
Computers: The Systems Approach in Management and Engineering: World War Ii
and After.
World War Ii should have correct capitalization.
"""
from proselint.tools import blacklist, memoize
@memoize
def check(text):
"""Check the text."""
err = "MSC104"
msg = "Don't fail to capitalize roman numeral abbreviations."
pwd_regex = " (I(i*)|i*)"
password = [
f"World War{pwd_regex}",
]
return blacklist(text, password, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/inprogress/example_check.py 0000644 0000000 0000000 00000000674 00000000000 021324 0 ustar 00 """First line is always wrong.
---
layout: post
source: Nobody
source_url: ???
title: Firse line is always wrong.
date: 2014-06-10 12:31:19
categories: writing
---
The first line always is always wrong.
"""
from proselint.tools import reverse
def check(text):
"""Check the text."""
error_code = "example.first"
msg = "First line always has an error."
reverse(text)
return [(1, 1, error_code, msg)]
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/jargon/__init__.py 0000644 0000000 0000000 00000000016 00000000000 017346 0 ustar 00 """Jargon."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/jargon/misc.py 0000644 0000000 0000000 00000001231 00000000000 016542 0 ustar 00 """Cliches.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: a vs. an
date: 2014-06-10 12:31:19
categories: writing
---
Cliches are cliché.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "jargon.misc"
msg = "'{}' is jargon. Can you replace it with something more standard?"
jargon = [
"in the affirmative",
"in the negative",
"agendize",
"per your order",
"per your request",
"disincentivize",
]
return existence_check(text, jargon, err, msg, join=True)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/lexical_illusions/__init__.py 0000644 0000000 0000000 00000000031 00000000000 021605 0 ustar 00 """Lexical illusions."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/lexical_illusions/misc.py 0000644 0000000 0000000 00000001365 00000000000 021014 0 ustar 00 """Lexical illusions.
---
layout: post
source: write-good
source_url: https://github.com/btford/write-good
title: Lexical illusion present
date: 2014-06-10 12:31:19
categories: writing
---
A lexical illusion is when a word word is unintentionally repeated twice, and
and this happens most often between line breaks.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "lexical_illusions.misc"
msg = "There's a lexical illusion here: a word is repeated."
regex = r"\b(\w+)(\b\s\1)+\b"
exceptions = [r"^had had$", r"^that that$"]
return existence_check(text, [regex], err, msg, exceptions=exceptions,
require_padding=False)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/lgbtq/__init__.py 0000644 0000000 0000000 00000000015 00000000000 017176 0 ustar 00 """GLAAD."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/lgbtq/offensive_terms.py 0000644 0000000 0000000 00000002073 00000000000 020643 0 ustar 00 """GLAAD.
---
layout: post
source: GLAAD Media Reference Guide - 9th Edition
source_url: http://www.glaad.org/reference
title: GLAAD Guidelines
date: 2016-07-06
categories: writing
---
This check looks for offensive terms related to LGBTQ issues and
raises an error marking them as offensive. The New York Times and
Associated Press have also adopted this style guide.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Flag offensive words based on the GLAAD reference guide."""
err = "glaad.offensive_terms"
msg = "Offensive term. Remove it or consider the context."
list = [
"fag",
"faggot",
"dyke",
"sodomite",
"homosexual agenda",
"gay agenda",
"transvestite",
"homosexual lifestyle",
"gay lifestyle"
# homo - may create false positives without additional context
# FIXME use topic detetor to decide whether "homo" is offensive
]
return existence_check(text, list, err, msg, join=True, ignore_case=False)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/lgbtq/terms.py 0000644 0000000 0000000 00000002345 00000000000 016601 0 ustar 00 """GLAAD.
---
layout: post
source: GLAAD Media Reference Guide - 9th Edition
source_url: http://www.glaad.org/reference
title: GLAAD Guidelines
date: 2016-07-06
categories: writing
---
This check looks for possibly offensive terms related to LGBTQ issues and
makes more acceptable recommendations. TheNew York Times and
Associated Press have also adopted this style guide.
"""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""Suggest preferred forms given the reference document."""
err = "glaad.terms"
msg = "Possibly offensive term. Consider using '{}' instead of '{}'."
list = [
["gay man", ["homosexual man"]],
["gay men", ["homosexual men"]],
["lesbian", ["homosexual woman"]],
["lesbians", ["homosexual women"]],
["gay people", ["homosexual people"]],
["gay couple", ["homosexual couple"]],
["sexual orientation", ["sexual preference"]],
["openly gay", ["admitted homosexual", "avowed homosexual"]],
["equal rights", ["special rights"]]
]
return preferred_forms_check(text, list, err, msg, ignore_case=False)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/links/__init__.py 0000644 0000000 0000000 00000000024 00000000000 017205 0 ustar 00 """Broken links."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/links/broken.py 0000644 0000000 0000000 00000003021 00000000000 016726 0 ustar 00 """Checks that links are viable.
---
layout: post
source: SublimeLinter-annotations
source_url: http://bit.ly/16Q7H41
title: broken links
date: 2014-06-10 12:31:19
categories: writing
---
Check that links are not broken.
"""
import re
import urllib.request as urllib_request # for Python 3
from socket import error as SocketError
from future import standard_library
from proselint.tools import memoize
standard_library.install_aliases()
@memoize
def check(text):
"""Check the text."""
err = "links.valid"
msg = "Broken link: {}"
regex = re.compile(
r"""(?i)\b((?:https?://|www\d{0,3}[.]
|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+
|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)
|[^\s`!()\[\]{};:\'".,<>?\xab\xbb\u201c\u201d\u2018\u2019\u21a9]))""",
re.U | re.X)
errors = []
for m in re.finditer(regex, text):
url = m.group(0).strip()
if "http://" not in url and "https://" not in url:
url = "http://" + url
if is_broken_link(url):
errors.append((m.start(), m.end(), err, msg.format(url), None))
return errors
@memoize
def is_broken_link(url):
"""Determine whether the link returns a 404 error."""
try:
request = urllib_request.Request(
url, headers={'User-Agent': 'Mozilla/5.0'})
urllib_request.urlopen(request).read()
return False
except urllib_request.URLError:
return True
except SocketError:
return True
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/malapropisms/__init__.py 0000644 0000000 0000000 00000000025 00000000000 020575 0 ustar 00 """Malaproprisms."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/malapropisms/misc.py 0000644 0000000 0000000 00000001076 00000000000 020000 0 ustar 00 """Malaproprisms.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: Malaproprisms
date: 2014-06-10 12:31:19
categories: writing
---
Archaism.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "malapropisms.misc"
msg = "'{}' is a malapropism."
illogics = [
"the infinitesimal universe",
"a serial experience",
"attack my voracity",
]
return existence_check(text, illogics, err, msg, offset=1)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/__init__.py 0000644 0000000 0000000 00000000066 00000000000 017026 0 ustar 00 """Miscellaneous advice not otherwise categorized."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/apologizing.py 0000644 0000000 0000000 00000001026 00000000000 017606 0 ustar 00 """Excessive apologizing.
---
layout: post
source: Pinker's book on writing
source_url: ???
title: excessive apologizing
date: 2014-06-10 12:31:19
categories: writing
---
Points out excessive apologizing.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "pinker.apologizing"
msg = "Excessive apologizing."
narcissism = [
"More research is needed",
]
return existence_check(text, narcissism, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/back_formations.py 0000644 0000000 0000000 00000001064 00000000000 020427 0 ustar 00 """Back-formations.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: back-formations
date: 2014-06-10 12:31:19
categories: writing
---
Back-formations.
"""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "misc.back_formations"
msg = "Back-formation. '{}' is the preferred form."
list = [
["improper", ["improprietous"]],
]
return preferred_forms_check(text, list, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/bureaucratese.py 0000644 0000000 0000000 00000001063 00000000000 020117 0 ustar 00 """Bureaucratese.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: bureaucratese
date: 2014-06-10 12:31:19
categories: writing
---
Bureaucratese.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "misc.bureaucratese"
msg = "'{}' is bureaucratese."
bureaucratese = [
"meet with your approval",
"meets with your approval",
]
return existence_check(text, bureaucratese, err, msg, join=True)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/but.py 0000644 0000000 0000000 00000001007 00000000000 016055 0 ustar 00 """Don't start a paragraph with 'But'.
---
layout:
source: Justin Jungé
source_url:
title:
date: 2016-03-10 12:31:19
categories: writing
---
Paragraphs should not start with certain bad words.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Do not start a paragraph with a 'But'."""
err = "misc.but"
msg = "No paragraph should start with a 'But'."
regex = r"(^|([\n\r]+))(\s*)But"
return existence_check(text, [regex], err, msg, ignore_case=False)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/capitalization.py 0000644 0000000 0000000 00000004725 00000000000 020310 0 ustar 00 """Incorrect capitalization.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: incorrect captalization
date: 2014-06-10 12:31:19
categories: writing
---
Incorrect capitalization.
"""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "misc.captalization"
msg = "Incorrect capitalization. '{}' is the preferred form."
list = [
["Stone Age", ["stone age"]],
["space age", ["Space Age"]],
["the American West", ["the American west"]],
["Mother Nature", ["mother nature"]],
]
return preferred_forms_check(text, list, err, msg, ignore_case=False)
# @memoize
# def check_seasons(text):
# """Suggest the preferred forms."""
# err = "MAU102"
# msg = "Seasons shouldn't be capitalized. '{}' is the preferred form."
# list = [
# # ["winter", ["Winter"]],
# # ["fall", ["Fall"]],
# # ["summer", ["Summer"]],
# # ["spring", ["Spring"]],
# ]
# return preferred_forms_check(text, list, err, msg, ignore_case=False)
@memoize
def check_months(text):
"""Suggest the preferred forms."""
err = "MAU102"
msg = "Months should be capitalized. '{}' is the preferred form."
list = [
["January", ["january"]],
["February", ["february"]],
# ["March", ["march"]],
["April", ["april"]],
# ["May", ["may"]],
["June", ["june"]],
["July", ["july"]],
["August", ["august"]],
["September", ["september"]],
["October", ["october"]],
["November", ["november"]],
["December", ["december"]],
]
return preferred_forms_check(text, list, err, msg, ignore_case=False)
@memoize
def check_days(text):
"""Suggest the preferred forms."""
err = "MAU102"
msg = "Days of the week should be capitalized. '{}' is the preferred form."
list = [
["Monday", ["monday"]],
["Tuesday", ["tuesday"]],
["Wednesday", ["wednesday"]],
["Thursday", ["thursday"]],
["Friday", ["friday"]],
["Saturday", ["saturday"]],
["Sunday", ["sunday"]],
]
return preferred_forms_check(text, list, err, msg, ignore_case=False)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/chatspeak.py 0000644 0000000 0000000 00000001376 00000000000 017237 0 ustar 00 """Chatspeak.
---
layout: post
source: ???
source_url: ???
title: textese
date: 2014-06-10 12:31:19
categories: writing
---
Chatspeak.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "misc.chatspeak"
msg = "'{}' is chatspeak. Write it out."
words = [
"2day",
"4U",
"AFAIK",
"AFK",
"AFK",
"ASAP",
"B4",
"brb",
"btw",
"cya",
"GR8",
"lol",
"LOL",
"LUV",
"OMG",
"rofl",
"roftl",
"sum1",
"SWAK",
"THNX",
"THX",
"TTYL",
"XOXO"
]
return existence_check(text, words, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/commercialese.py 0000644 0000000 0000000 00000002354 00000000000 020101 0 ustar 00 """Commercialese.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: commercialese
date: 2014-06-10 12:31:19
categories: writing
---
Commercialese.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "misc.commercialese"
msg = "'{}' is commercialese."
commercialese = [
"acknowledging yours of",
"beg to advise",
"enclosed herewith",
"enclosed please find",
"further to yours of",
"further to your letter",
"in regard to",
r"inst\.",
"in the amount of",
"of even date",
"pending receipt of",
"please be advised that",
"please return same",
"pleasure of a reply",
r"prox\.",
"pursuant to your request",
"regarding the matter",
"regret to inform",
"thanking you in advance",
"the undersigned",
"this acknowledges your letter",
r"ult\."
"we are pleased to note",
"with regard to",
"your favor has come to hand",
"yours of even date"
]
return existence_check(text, commercialese, err, msg, join=True)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/composition.py 0000644 0000000 0000000 00000006636 00000000000 017643 0 ustar 00 """Elementary Rules of Usage.
---
layout: post
source: Strunk & White
source_url: ???
title: Elementary Principles of Composition
date: 2014-06-10 12:31:19
categories: writing
---
Strunk & White say:
1. Choose a suitable design and hold to it.
* MDPNB: Sounds like a principle of `consistency`.
2. Make the paragraph the unit of composition.
* MDPNB: This can be generalized to say something about variability in the
length of paragraphs and sentences. When any device is too often used it
becomes a mannerism.
* MDPNB: Sounds like a principle of `variation`.
3. Use the active voice.
4. Put statements in positive form.
* MDPNB: In some cases this will apply as an invective against the use of
a double negative.
* Ex: He was not very often on time. -> He usually came late.
* Ex:
4.1. Placing negative and positive in opposition makes for a stronger
structure.
* Ex. Not charity, but simple justice.
* Not that I loved Caesar less, but that I loved Rome more.
4.2. Do not use unnecessary auxiliaries or conditionals.
5. Use definite, specific, concrete language.
* A period of unfavorable weather set in. ->It rained every day for a week.
6. Omit needless words.
* `The fact that` is particularly pernicious.
* `who is, which was` and the like are often superfluous
7. Avoid a succession of loose sentences.
* MDPNB Principle of brevity. Take 2.
8. Express coordinate ideas in similar form.
* MDPNB: Principle of parallel structure.
* MDPNB: This one will be hard...
9. Keep related words together.
* MDPNB: Principle of localism in semantics.
10. In summaries, keep to one tense.
* MDPNB: Principle of temporal consistency.
11. Place the emphatic word of a sentence at the end.
* MDPNB: Principle of recency.
"""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "strunk_white.composition"
msg = "Try '{}' instead of '{}'."
bad_forms = [
# Put statements in positive form
["dishonest", ["not honest"]],
["trifling", ["not important"]],
["forgot", ["did not remember"]],
["ignored", ["did not pay (any )?attention to"]],
["distrusted", ["did not have much confidence in"]],
# Omit needless words
["whether", ["the question as to whether"]],
["no doubt", ["there is no doubt but that"]],
["used for fuel", ["used for fuel purposes"]],
["he", ["he is a man who"]],
["hastily", ["in a hasty manner"]],
["this subject", ["this is a subject that"]],
["Her story is strange.", ["Her story is a strange one."]],
["because", ["the reason why is that"]],
["because / since", ["owing to the fact that"]],
["although / though", ["in spite of the fact that"]],
["remind you / notify you",
["call your attention to the fact that"]],
["I did not know that / I was unaware that",
["I was unaware of the fact that"]],
["his failure", ["the fact that he had not succeeded"]],
["my arrival", ["the fact that i had arrived"]]
]
return preferred_forms_check(text, bad_forms, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/currency.py 0000644 0000000 0000000 00000000762 00000000000 017124 0 ustar 00 """Currency.
---
layout: post
source: SublimeLinter-annotations
source_url: http://bit.ly/16Q7H41
title: symbols
date: 2014-06-10 12:31:19
categories: writing
---
Symbols.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "misc.currency"
msg = "Incorrect use of symbols in {}."
symbols = [
r"\$[\d]* ?(?:dollars|usd|us dollars)"
]
return existence_check(text, symbols, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/debased.py 0000644 0000000 0000000 00000001157 00000000000 016660 0 ustar 00 """Debased language.
---
layout: post
source: ???
source_url: ???
title: yelling
date: 2014-06-10 12:31:19
categories: writing
---
Too much yelling.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "misc.debased"
msg = "Bad usage, debased language, a continuous temptation."
list = [
"a not unjustifiable assumption",
"leaves much to be desired",
"would serve no purpose",
"a consideration which we should do well to bear in mind",
]
return existence_check(text, list, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/errata.md 0000644 0000000 0000000 00000000112 00000000000 016505 0 ustar 00 ? Page 82. Inconsistent spelling of "back-formations" as "backformation".
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/false_plurals.py 0000644 0000000 0000000 00000001455 00000000000 020126 0 ustar 00 """False plurals.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: False plurals.
date: 2014-06-10 12:31:19
categories: writing
---
Using the incorrect form of the plural.
"""
from proselint.tools import existence_check, memoize, preferred_forms_check
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "misc.false_plurals.examples"
msg = "The plural is {}"
preferences = [
["talismans", ["talismen"]],
["phenomena", ["phenomenons"]],
]
return preferred_forms_check(text, preferences, err, msg)
@memoize
def check_kudos(text):
"""Check the text."""
err = "misc.false_plurals.kudos"
msg = "Kudos is singular."
return existence_check(text, ["many kudos"], err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/greylist.py 0000644 0000000 0000000 00000001675 00000000000 017140 0 ustar 00 """Use of greylisted words.
---
layout: post
source: Strunk & White
source_url: ???
title: Use of greylisted words
date: 2014-06-10 12:31:19
categories: writing
---
Strunk & White say:
"""
import re
from proselint.tools import memoize
@memoize
def check(text):
"""Check the text."""
err = "strunk_white.greylist"
msg = "Use of '{}'. {}"
bad_words = [
"obviously",
"utilize"
]
explanations = {
"obviously":
"This is obviously an inadvisable word to use.",
"utilize":
r"Do you know anyone who *needs* to utilize the word utilize?"
}
errors = []
for word in bad_words:
occ = [m for m in re.finditer(word, text.lower())]
for o in occ:
errors.append((
o.start(),
o.end(),
err,
msg.format(word, explanations[word]),
None))
return errors
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/illogic.py 0000644 0000000 0000000 00000002511 00000000000 016706 0 ustar 00 """Illogic.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: Illogic
date: 2014-06-10 12:31:19
categories: writing
---
Archaism.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "misc.illogic"
msg = "'{}' is illogical."
illogics = [
"preplan",
"more than .{1,10} all",
"appraisal valuations?",
"(?:i|you|he|she|it|y'all|all y'all|you all|they) could care less",
"least worst",
"much-needed gaps?",
"much-needed voids?",
"no longer requires oxygen",
"without scarcely",
]
return existence_check(text, illogics, err, msg, offset=1)
@memoize
def check_coin_a_phrase_from(text):
"""Check the text."""
err = "misc.illogic.coin"
msg = "You can't coin an existing phrase. Did you mean 'borrow'?"
regex = "to coin a phrase from"
return existence_check(text, [regex], err, msg, offset=1)
@memoize
def check_without_your_collusion(text):
"""Check the textself."""
err = "misc.illogic.collusion"
msg = "It's impossible to defraud yourself. Try 'aquiescence'."
regex = "without your collusion"
return existence_check(
text, [regex], err, msg, require_padding=False, offset=-1)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/inferior_superior.py 0000644 0000000 0000000 00000001274 00000000000 021036 0 ustar 00 """Inferior / Superior.
---
layout: post
source: Fowler's Modern English Usage
source_url: bit.ly/1YBG8QJ
title: Inferior / Superior
date: 2016-03-10 17:27:37
categories: writing
---
Corrects 'inferior/superior than' to 'inferior/superior to'.
"""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "misc.inferior_superior"
msg = "'Inferior' and 'superior' are not true comparatives. Use '{}'."
preferences = [
["inferior to", ["inferior than"]],
["superior to", ["superior than"]],
]
return preferred_forms_check(text, preferences, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/institution_name.py 0000644 0000000 0000000 00000001373 00000000000 020662 0 ustar 00 """Common errors with institution names.
---
layout: post
source: Institution's webpage
source_url: http://bit.ly/2en1zbv,
title: Institution Name
date: 2016-11-16 11:46:19
categories: writing
---
Institution names.
"""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check_vtech(text):
"""Suggest the correct name.
source: Virginia Tech Division of Student Affairs
source_url: http://bit.ly/2en1zbv
"""
err = "institution.vtech"
msg = "Incorrect name. Use '{}' instead of '{}'."
institution = [
["Virginia Polytechnic Institute and State University",
["Virginia Polytechnic and State University"]],
]
return preferred_forms_check(text, institution, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/latin.py 0000644 0000000 0000000 00000001367 00000000000 016403 0 ustar 00 """Back-formations.
---
layout: post
source: The sense of style
source_url: http://amzn.to/1EOUZ5g
title: back-formations
date: 2014-06-10 12:31:19
categories: writing
---
Back-formations.
"""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "pinker.latin"
msg = "Use English. '{}' is the preferred form."
list = [
["other things being equal", ["ceteris paribus"]],
["among other things", ["inter alia"]],
["in and of itself", ["simpliciter"]],
["having made the necessary changes", ["mutatis mutandis"]],
]
return preferred_forms_check(text, list, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/many_a.py 0000644 0000000 0000000 00000001265 00000000000 016535 0 ustar 00 """Many a singular.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: Many a singular.
date: 2014-06-10 12:31:19
categories: writing
---
The idiom 'many a' requires a singular verb.
"""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "misc.many_a"
msg = "'many a' requires a singular verb."
preferences = [
["is many a", ["are many a"]],
["has been many a", ["have been many a"]],
["was many a", ["were many a"]],
]
return preferred_forms_check(text, preferences, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/metaconcepts.py 0000644 0000000 0000000 00000001063 00000000000 017752 0 ustar 00 """Metaconcepts.
---
layout: post
source: Pinker's book on writing
source_url: ???
title: misuse of scare quotes
date: 2014-06-10 12:31:19
categories: writing
---
Point out misuse of scare quotes.
"""
# from proselint.tools import memoize, existence_check
# @memoize
# def check(text):
# """Suggest the preferred forms."""
# err = "pinker.metaconcepts"
# msg = "Misuse of 'scare quotes'. Delete them."
# narcissism = [
# "the 'take-home message'",
# ]
# return existence_check(text, narcissism, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/metadiscourse.py 0000644 0000000 0000000 00000001251 00000000000 020133 0 ustar 00 """Metadiscourse.
---
layout: post
source: Pinker's book on writing
source_url: ???
title: metadiscourse
date: 2014-06-10 12:31:19
categories: writing
---
Points out metadiscourse.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "pinker.metadiscourse"
msg = "Excessive metadiscourse."
metadiscourse = [
"The preceeding discussion",
"The rest of this article",
"This chapter discusses",
"The preceding paragraph demonstrated",
"The previous section analyzed",
]
return existence_check(text, metadiscourse, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/narcissism.py 0000644 0000000 0000000 00000001146 00000000000 017442 0 ustar 00 """Professional narcissism.
---
layout: post
source: Pinker's book on writing
source_url: ???
title: professional narcissism
date: 2014-06-10 12:31:19
categories: writing
---
Points out academic narcissism.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "pinker.narcissism"
msg = "Professional narcissism. Talk about the subject, not its study."
narcissism = [
"In recent years, an increasing number of [a-zA-Z]{3,}sts have",
]
return existence_check(text, narcissism, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/not_guilty.py 0000644 0000000 0000000 00000002045 00000000000 017463 0 ustar 00 """Not guilty beyond a reasonable doubt.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: Not guilty beyond a reasonable doubt.
date: 2016-03-09 15:50:31
categories: writing
---
This phrasing is ambiguous. The standard by which a jury decides criminal
charges is this: a defendant is guilty only if the evidence shows, beyond a
reasonable doubt, that he or she committed the crime. Otherwise, the defendant
is not guilty. Thus, we say that a defendant was not found "guilty beyond a
reasonable doubt."
If somebody is found not guilty, say "not guilty." Omit the standard
("beyond a reasonable doubt") to prevent a miscue.
Not guilty beyond a reasonable doubt
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "misc.not_guilty"
msg = "'not guilty beyond a reasonable doubt' is an ambiguous phrasing."
regex = r"not guilty beyond (a |any )?reasonable doubt"
return existence_check(text, [regex], err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/phrasal_adjectives.py 0000644 0000000 0000000 00000015446 00000000000 021132 0 ustar 00 """Phrasal adjectives.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: Phrasal adjectives
date: 2014-06-10 12:31:19
categories: writing
---
Phrasal adjectives.
"""
from proselint.tools import existence_check, memoize, preferred_forms_check
@memoize
def check_ly(text):
"""Check the text."""
err = "garner.phrasal_adjectives.ly"
msg = """No hyphen is necessary in phrasal adjectives with an adverb
ending in -ly, unless the -ly adverb is part of a longer
phrase"""
regex = r"\s[^\s-]+ly-"
return existence_check(text, [regex], err, msg,
require_padding=False, offset=-1)
@memoize
def check(text):
"""Check the text."""
err = "garner.phrasal_adjectives.examples"
msg = """Hyphenate '{1}', a phrasal adjective, as '{0}'."""
list = [
["across-the-board discounts", ["across the board discounts"]],
["acute-care treatment", ["acute care treatment"]],
["agreed-upon answer", ["agreed upon answer"]],
["big-ticket item", ["big ticket item"]],
["class-action lawyer", ["class action lawyer"]],
["criminal-law professor", ["criminal law professor"]],
["cut-and-dried issue", ["cut and dried issue"]],
["downward-sloping line", ["downward sloping line"]],
["English-language learners", ["English language learners"]],
["English-speaking people", ["English speaking people"]],
["even-numbered", ["even numbered"]],
["face-to-face meeting", ["fact to face meeting"]],
["fixed-rate mortgage", ["fixed rate mortgage"]],
["for-profit firm", ["for profit firm"]],
["foreign-sounding name", ["foreign sounding name"]],
["government-owned business", ["government owned business"]],
["hard-and-fast issue", ["hard and fast issue"]],
["head-on collision", ["head on collision"]],
["head-to-head battle", ["head to head battle"]],
["head-to-head competition", ["head to head competition"]],
["health-care coverage", ["heath care coverage"]],
["high-school student", ["high school student"]],
["hit-and-run statute", ["hit and run statute"]],
["HIV-negative person", ["HIV negative person"]],
["HIV-positive person", ["HIV positive person"]],
["information-technology personnel",
["information technology personnel"]],
["intellectual-property rights", ["intellectual property rights"]],
["interest-group pressures", ["interest group pressures"]],
["joint-stock company", ["joint stock company"]],
["kidney-dialysis machine", ["kidney dialysis machine"]],
["long-run costs", ["long run costs"]],
["long-term care", ["long term care"]],
["low-income housing", ["low income housing"]],
["mom-and-pop retail outlet", ["mom and pop retail outlet"]],
["mom-and-pop shop", ["mom and pop shop"]],
["national-security briefing", ["national security briefing"]],
["natural-gas pipeline", ["natural gas pipeline"]],
["no-fault accident", ["no fault accident"]],
["no-fault divorce", ["no fault divorce"]],
["no-fault insurance", ["no fault insurance"]],
["odd-numbered", ["odd numbered"]],
["office-supply store", ["office supply store"]],
["one-way flight", ["one way flight"]],
["one-way window", ["one way window"]],
["open-and-shut case", ["open and shut case"]],
["open-and-shut issue", ["open and shut issue"]],
["open-source community", ["open source community"]],
["optical-scan ballot", ["optical scan ballot"]],
["pension-fund investments", ["pension fund investments"]],
["private-sector employment", ["private sector employment"]],
["profit-seeking efforts", ["profit seeking efforts"]],
["punch-card ballot", ["punch card ballot"]],
["quality-adjusted price", ["quality adjusted price"]],
["razor-sharp intellect", ["razor sharp intellect"]],
["razor-sharp mind", ["razor sharp mind"]],
["razor-sharp mind", ["razor sharp mind"]],
["razor-sharp wit", ["razor sharp wit"]],
["larger-than-life personality", ["larger than life personality"]],
["real-estate prices", ["real estate prices"]],
["real-estate tycoon", ["real estate tycoon"]],
["right-wing militia", ["right wing militia"]],
["round-trip flight", ["round trip flight"]],
["search-and-rescue operation", ["search and rescue operation"]],
["second-largest army", ["second largest army"]],
["shell-shocked mothers", ["shell shocked mothers"]],
["shell-shocked soldiers", ["shell shocked soldiers"]],
["small-business loan", ["small business loan"]],
["small-business owner", ["small business owner"]],
["small-state senator", ["small state senator"]],
["small-animal veterinarian", ["small animal veterinarian"]],
["state-sponsored terrorism", ["state sponsored terrorism"]],
["state-sponsored violence", ["state sponsored violence"]],
["thumbs-up sign", ["thumbs up sign"]],
["time-honored tradition", ["time honored tradition"]],
["U.S.-led campaign", ["U.S. led campaign"]],
["upward-sloping line", ["upward sloping line"]],
["venture-backed company", ["venture backed company"]],
["well-publicized event", ["well publicized event"]],
["wire-transfer service", ["wire transfer service"]],
["yes-or-no question", ["yes or no question"]],
["zero-sum game", ["zero sum game"]],
["stained-glass ceiling", ["stained glass ceiling"]],
["stained-glass window", ["stained glass window"]],
["free-range chicken", ["free range chicken"]],
["free-range poultry", ["free range poultry"]],
["non-profit-making organization",
["non profit making organization",
"non-profit making organization",
"non profit-making organization"]],
# Harmony
["three-part harmony", ["three part harmony"]],
["four-part harmony", ["four part harmony"]],
["six-part harmony", ["six part harmony"]],
["eight-part harmony", ["eight part harmony"]],
# Losses and gains.
["first-quarter loss", ["first quarter loss"]],
["second-quarter loss", ["second quarter loss"]],
["third-quarter loss", ["third quarter loss"]],
["fourth-quarter loss", ["fourth quarter loss"]],
["first-quarter gain", ["first quarter gain"]],
["second-quarter gain", ["second quarter gain"]],
["third-quarter gain", ["third quarter gain"]],
["fourth-quarter gain", ["fourth quarter gain"]],
]
return preferred_forms_check(text, list, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/preferred_forms.py 0000644 0000000 0000000 00000016613 00000000000 020460 0 ustar 00 """Preferred forms.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: preferred forms
date: 2014-06-10 12:31:19
categories: writing
---
Points out preferred forms.
"""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "garner.preferred_forms"
msg = "'{}' is the preferred form."
preferences = [
# Obsolete words
["imprimatur", ["imprimature"]],
# Proper nouns
["Halloween", ["haloween", "hallowe'en"]],
["Khrushchev", ["Khruschev", "Kruschev"]],
["Ku Klux Klan", ["Klu Klux Klan"]],
["Pontius Pilate", ["Pontius Pilot"]],
# Plurals
["hippopotamuses", ["hippopotami"]],
["manifestos", ["manifesti"]],
# ["matrixes", ["matrices"]],
["mongooses", ["mongeese"]],
["narcissi", ["narcissuses"]],
["retinas", ["retinae"]],
["sopranos", ["soprani"]],
["titmice", ["titmouses"]],
# Hyphenated words
["long-standing", ["longstanding"]],
["sans serif", ["sans-serif", "sanserif"]],
["tortfeasor", ["tort feasor", "tort-feasor"]],
["transship", ["tranship", "trans-ship"]],
["transshipped", ["transhipped", "trans-shipped"]],
["transshipping", ["transhipping", "trans-shipping"]],
["non sequitur", ["non-sequitur"]],
# Misc
["attitude", ["mental attitude"]],
["Chief Justice of the United States",
["Chief Justice of the United States Supreme Court",
"Chief Justice of the Supreme Court of the United States."]],
["chitterlings", ["chitlings", "chitlins"]],
["combustion engine", ["combustible engine"]],
["during / throughout", ["for the duration of"]],
["foreclose on", ["foreclose againt"]],
["friend in common", ["mutual friend"]],
["in regard to", ["in regards to"]],
["infectious", ["infectuous"]],
["inferable", ["inferrable", "inferrible"]],
["knowing that", ["in light of the fact that"]],
["lanyard", ["laniard"]],
["largess", ["largesse"]],
["lasagna", ["lasagne"]],
["leery", ["leary"]],
["lend me her", ["loan me her"]],
["lend me his", ["loan me his"]],
["lend me their", ["loan me their"]],
["lend me your", ["loan me your"]],
["lent me her", ["loaned me her"]],
["lent me his", ["loaned me his"]],
["lent me their", ["loaned me their"]],
["lent me your", ["loaned me your"]],
["linguist", ["linguistician"]],
["matzo-ball", ["matzoh-ball",
"matza-ball",
"matzah-ball",
"matsah-ball"]],
["mayoralty", ["mayorality"]],
["mealy-mouthed", ["mealymouthed"]],
["mean-spirited", ["meanspirited"]],
["midwifed", ["midwived"]],
["moniker", ["monicker"]],
["musical revue", ["musical review"]],
["mustache", ["moustache"]],
["nonplussed", ["nonplused"]],
["nonplussing", ["nonplusing"]],
["non sequitur", ["nonsequitur"]],
["not nearly as", ["nowhere near as"]],
["off", ["off of"]],
["podiatrist", ["chiropodist"]],
["podiatry", ["chiropody"]],
["shoo-in", ["shoe-in"]],
["suicide", ["suicide victim"]],
["the highway median", ["the highway medium"]],
["vaipidity", ["vapidness"]],
["weather vane", ["weather vein", "weather vain"]],
["with regard to", ["with regards to"]],
# Idioms
["a couple of people", ["a couple people"]],
["all the time", ["all of the time"]],
["as follows", ["as follow"]],
["bulk large", ["bulk largely"]],
["burying the lede", ["burying the lead"]],
["came to naught", ["came to nought"]],
["come off it", ["come off of it"]],
["corroborating evidence", ["corroborative evidence"]],
["dear departed", ["dearly departed"]],
["default on a loan", ["default to a loan"]],
["draw an inference", ["make an inference"]],
["in the meantime", ["in the meanwhile"]],
["long distances", ["lengthy distances"]],
["madding crowd", ["maddening crowd"]],
["Magna Carta", ["Magna Charta"]],
["marriage of convenience", ["mariage de convenance"]],
["Meanwhile,", ["Meantime,"]],
["Midwest", ["Middle West"]],
["Midwestern", ["Middle Western"]],
["modi operandi", ["modes of operandi"]],
["modus operandi", ["mode of operandi"]],
["motion seconded", ["notion seconded"]],
["mucous membranes", ["mucus membranes"]],
["must pass muster", ["must past muster"]],
["neck-and-neck", ["neck-in-neck"]],
["no-holds-barred", ["no-holes-barred"]],
["oil magnate", ["oil magnet"]],
["punch up the lede", ["punch up the lead"]],
["railroad magnate", ["railroad magnet"]],
["seconded the motion", ["seconded the notion"]],
["statute of limitationas", ["statute of limits"]],
["take precedence over", ["take prescience over"]],
["the last two", ["both of the last two"]],
["the last two", ["both of the last"]],
["unorganic food", ["inorganic food"]],
["vale of tears", ["veil of tears"]],
["Venus flytrap", ["Venus's flytrap", "Venus' flytrap"]],
["was accused of", ["was accused with"]],
# Verbosity
["try to", ["make an attempt to"]],
["try to", ["make attempts to"]],
["try to", ["make efforts to"]],
["tried to", ["made an attempt to"]],
["tried to", ["made attempts to"]],
["tried to", ["made efforts to"]],
["modern", ["modern-day"]],
# Grammar
["be misled", ["be mislead"]],
["was misled", ["was mislead"]],
["were misled", ["were mislead"]],
# Euphemisms
["a search-and-destroy mission", ["armed reconnaissance"]],
["abortion", ["pregnancy termination"]],
["bisexual", ["sexually ambidextrous"]],
["exterminator", ["extermination engineer"]],
["firing", ["permanent layoff"]],
["rat-catcher", ["rodent operative"]],
# Tenses
["mistook", ["mistaked"]],
# Accents
["né", ["ne"]],
["née", ["nee"]],
]
return preferred_forms_check(text, preferences, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/pretension.py 0000644 0000000 0000000 00000001144 00000000000 017453 0 ustar 00 """Pretension.
---
layout: post
source: ???
source_url: ???
title: yelling
date: 2014-06-10 12:31:19
categories: writing
---
Never use the phrase 'all hell broke loose'.
"""
from proselint.tools import existence_check, max_errors, memoize
@max_errors(1)
@memoize
def check(text):
"""Check the text."""
err = "ogilvy.pretension"
msg = "Jargon words like this one are the hallmarks of a pretentious ass."
list = [
"reconceptualize",
"demassification",
"attitudinally",
"judgmentally",
]
return existence_check(text, list, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/professions.py 0000644 0000000 0000000 00000001021 00000000000 017631 0 ustar 00 """Profession.
---
layout: post
source:
source_url:
title: Professions
date: 2014-06-10 12:31:19
categories: writing
---
Professions.
"""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "misc.professions"
msg = "'{}' is the name of that job."
preferences = [
["cobbler", ["shoe repair guy"]],
["geometer", ["geometrist"]],
]
return preferred_forms_check(text, preferences, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/punctuation.py 0000644 0000000 0000000 00000000771 00000000000 017643 0 ustar 00 """Punctuation.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: dates
date: 2014-06-10 12:31:19
categories: writing
---
Dates.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "garner.punctuation"
msg = "Misplaced punctuation. It's 'et al.'"
list = [
"et. al",
"et. al."
]
return existence_check(text, list, err, msg, join=True)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/scare_quotes.py 0000644 0000000 0000000 00000001052 00000000000 017760 0 ustar 00 """Misuse of scare quotes.
---
layout: post
source: Pinker's book on writing
source_url: ???
title: misuse of scare quotes
date: 2014-06-10 12:31:19
categories: writing
---
Points out misuse of scare quotes.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "pinker.scare_quotes"
msg = "Misuse of 'scare quotes'. Delete them."
narcissism = [
"the 'take-home message'",
]
return existence_check(text, narcissism, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/suddenly.py 0000644 0000000 0000000 00000002712 00000000000 017116 0 ustar 00 """Suddenly.
---
layout: post
source: Reference for Writers
source_url: http://bit.ly/1E94vyD
title: suddenly
date: 2014-06-10 12:31:19
categories: writing
---
“Sudden” means quickly and without warning, but using the word “suddenly” both
slows down the action and warns your reader. Do you know what’s more effective
for creating the sense of the sudden? Just saying what happens.
When using “suddenly,” you communicate through the narrator that the action
seemed sudden. By jumping directly into the action, you allow the reader to
experience that suddenness first hand. “Suddenly” also suffers from being
nondescript, failing to communicate the nature of the action itself; providing
no sensory experience or concrete fact to hold on to. Just … suddenly.
Feel free to employ “suddenly” in situations where the suddenness is not
apparent in the action itself. For example, in “Suddenly, I don’t hate you
anymore,” the “suddenly” substantially changes the way we think about the
shift in emotional calibration.
"""
from proselint.tools import existence_check, max_errors, memoize
@max_errors(3)
@memoize
def check(text):
"""Advice on sudden vs suddenly."""
err = "misc.suddenly"
msg = "Suddenly is nondescript, slows the action, and warns your reader."
regex = "Suddenly,"
return existence_check(text, [regex], err, msg, require_padding=False,
offset=-1, ignore_case=False)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/tense_present.py 0000644 0000000 0000000 00000002043 00000000000 020142 0 ustar 00 """Tense present.
---
layout: post
source: DFW's Tense Present
source_url: http://bit.ly/1c85lgR
title: Tense present
date: 2014-06-10 12:31:19
categories: writing
---
Archaism.
"""
import re
from proselint.tools import memoize
@memoize
def check(text):
"""Check the text."""
err = "misc.tense_present"
msg = r"'{}'."
illogics = [
r"up to \d{1,3}% ?[-\u2014\u2013]{0,3} ?(?:or|and) more\W?",
"between you and I",
"on accident",
"somewhat of a",
"all it's own",
"reason is because",
"audible to the ear",
"in regards to",
"would of",
# "and so",
r"i ?(?:feel|am feeling|am|'m|'m feeling) nauseous",
]
errors = []
for i in illogics:
for m in re.finditer(fr"\s{i}\s", text, flags=re.U | re.I):
txt = m.group(0).strip()
errors.append((
m.start() + 1,
m.end(),
err,
msg.format(txt),
None))
return errors
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/usage.py 0000644 0000000 0000000 00000003743 00000000000 016400 0 ustar 00 """Elementary Rules of Usage.
---
layout: post
source: Strunk & White
source_url: ???
title: Elementary Rules of Usage
date: 2014-06-10 12:31:19
categories: writing
---
Strunk & White say:
1. Form the possessive singular of nouns by adding 's.
2. In a series of three or more terms with a conjunction, use a comma after
each term except the last.
3. Enclose parenthetic expressions between commas. ("This rule is difficult to
apply.")
4. Place a comma before a conjunction introducing an independent clause.
5. Do not join independent clauses with a comma; use a semi-colon. Or a period.
6. Do not break sentences in two. Do not use periods for the role of commas.
7. Use a colon after an independent clause if you introduce: a list of
particulars, an appositive, an application, or an illustrative quotation.
8. Use a dash to set off an abrupt break or interruption and to announce a
long appositive or summary.
9. The number of the subject determines the number of the verb. (MDPNB: This
will require nltk & syntactic parsing)
10. Use the proper case(grammatical gender) of pronouns.
* MDPNB: hard case: "Give this work to whoever looks idle." `whoever looks
idle` is the object of `to`.
11. A participial phrase at the beginning of a sentence must refer to the
grammatical subject.
"""
# from proselint.tools import memoize
# import re
# @memoize
# def check(text):
# err = "strunk_white.usage"
# msg = "Use of '{}'. {}"
# bad_words = [
# "obviously",
# "utilize"
# ]
# explanations = {
# "obviously":
# "This is obviously an inadvisable word to use.",
# "utilize":
# r"Do you know anyone who *needs* to utilize the word utilize?"
# }
# errors = []
# for word in bad_words:
# occ = [m for m in re.finditer(word, text.lower())]
# for o in occ:
# errors.append((o.start(), o.end(), err,
# msg.format(word, explanations[word])))
# return errors
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/waxed.py 0000644 0000000 0000000 00000003462 00000000000 016402 0 ustar 00 """Waxed lyrical.
---
layout: post
source: Fowler's Modern English Usage
source_url: bit.ly/1YBG8QJ
title: Waxed lyrical
date: 2016-03-10 14:48:42
categories: writing
---
Fowler's says:
Its primary meaning 'grow larger, increase' (as opposed to 'wane') leads
naturally to the sense 'pass into a specified state or mood, begin to use a
specified tone. In this meaning a following modifier must be an adj. not an
adverb ('He waxed enthusiastic [not enthusiastically] about Australia').
"""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "misc.waxed"
msg = "The modifier following 'waxed' must be an adj.: '{}' is correct"
waxes = ["wax", "waxes", "waxed", "waxing"]
modifiers = [("ebullient", "ebulliently"),
("ecstatic", "ecstatically"),
("eloquent", "eloquently"),
("enthusiastic", "enthusiastically"),
("euphoric", "euphorically"),
("indignant", "indignantly"),
("lyrical", "lyrically"),
("melancholic", "melancholically"),
("metaphorical", "metaphorically"),
("nostalgic", "nostalgically"),
("patriotic", "patriotically"),
("philosophical", "philosophically"),
("poetic", "poetically"),
("rhapsodic", "rhapsodically"),
("romantic", "romantically"),
("sentimental", "sentimentally")
]
def pairs(word):
return [[word + ' ' + pair[0], [word + ' ' + pair[1]]]
for pair in modifiers]
preferred = []
for word in waxes:
preferred += pairs(word)
return preferred_forms_check(text, preferred, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/misc/whence.py 0000644 0000000 0000000 00000000663 00000000000 016543 0 ustar 00 """From whence it came.
---
layout: post
source: unknown
source_url: unknown
title: whence
date: 2014-06-10 12:31:19
categories: writing
---
From whence it came.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "misc.whence"
msg = "The 'from' in 'from whence' is not needed."
return existence_check(text, ["from whence"], err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/mixed_metaphors/__init__.py 0000644 0000000 0000000 00000000027 00000000000 021260 0 ustar 00 """Mixed metaphors."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/mixed_metaphors/misc.py 0000644 0000000 0000000 00000002572 00000000000 020463 0 ustar 00 """Mixed metaphors."""
from proselint.tools import (existence_check, max_errors, memoize,
preferred_forms_check)
@max_errors(1)
@memoize
def check_bottleneck(text):
"""Avoid mixing metaphors about bottles and their necks.
source: Sir Ernest Gowers
source_url: http://bit.ly/1CQPH61
"""
err = "mixed_metaphors.misc.bottleneck"
msg = "Mixed metaphor — bottles with big necks are easy to pass through."
list = [
"biggest bottleneck",
"big bottleneck",
"large bottleneck",
"largest bottleneck",
"world-wide bottleneck",
"huge bottleneck",
"massive bottleneck",
]
return existence_check(text, list, err, msg)
@memoize
def check_misc(text):
"""Avoid mixing metaphors.
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
"""
err = "mixed_metaphors.misc.misc"
msg = "Mixed metaphor. Try '{}'."
preferences = [
["cream rises to the top", ["cream rises to the crop"]],
["fasten your seatbelts", ["button your seatbelts"]],
["a minute to decompress", ["a minute to decompose"]],
["sharpest tool in the shed", ["sharpest marble in the (shed|box)"]],
["not rocket science", ["not rocket surgery"]],
]
return preferred_forms_check(text, preferences, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/mondegreens/__init__.py 0000644 0000000 0000000 00000000023 00000000000 020372 0 ustar 00 """Mondegreens."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/mondegreens/misc.py 0000644 0000000 0000000 00000002052 00000000000 017572 0 ustar 00 """Mondegreens.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: mondegreens
date: 2014-06-10 12:31:19
categories: writing
---
Points out preferred form.
"""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "misc.mondegreens"
msg = "'{}' is the preferred form."
list = [
["a girl with kaleidoscope eyes", ["a girl with colitis goes by"]],
["a partridge in a pear tree", ["a part-red gingerbread tree"]],
["attorney and notary public", ["attorney and not a republic"]],
["beck and call", ["beckon call"]],
["for all intents and purposes", ["for all intensive purposes"]],
["laid him on the green", ["Lady Mondegreen"]],
["all of the other reindeer", ["Olive, the other reindeer"]],
["to the manner born", ["to the manor born"]],
]
return preferred_forms_check(text, list, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/needless_variants/__init__.py 0000644 0000000 0000000 00000000031 00000000000 021574 0 ustar 00 """Needless variants."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/needless_variants/misc.py 0000644 0000000 0000000 00000042226 00000000000 021004 0 ustar 00 """Needless variants.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: needless variants
date: 2014-06-10 12:31:19
categories: writing
---
Points out use of needless variants.
"""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "needless_variants.misc"
msg = "Needless variant. '{}' is the preferred form."
preferences = [
# Needless variants
["abolition", ["abolishment"]],
["accessory", ["accessary"]],
["accredit", ["accreditate"]],
["accrual", ["accruement"]],
["accumulate", ["cumulate"]],
["accused", ["accusee"]],
["acquaintance", ["acquaintanceship"]],
["acquittal", ["acquitment"]],
["administer", ["administrate"]],
["administered", ["administrated"]],
["administering", ["administrating"]],
["adulterous", ["adulterate"]],
["advisory", ["advisatory"]],
["advocate", ["advocator"]],
["alleger", ["allegator"]],
["allusive", ["allusory"]],
["ameliorate", ["meliorate"]],
["amorous", ["amative"]],
["amortization", ["amortizement"]],
["amphibology", ["amphiboly"]],
["anachronism", ["parachronism"]],
["anecdotist", ["anecdotalist"]],
["anilingus", ["anilinctus"]],
["anticipatory", ["anticipative"]],
["antithetical", ["antithetic"]],
["applicable", ["applicative"]],
["applicable", ["applicatory"]],
["applicator", ["applier"]],
["approbatory", ["approbative"]],
["arbitrageur", ["arbitrager"]],
["arsenious", ["arsenous"]],
["ascendancy", ["ascendance"]],
["ascendancy", ["ascendence"]],
["ascendancy", ["ascendency"]],
["authorial", ["auctorial"]],
["averment", ["averral"]],
["barbed wire", ["barbwire"]],
["beneficent", ["benefic"]],
["benign", ["benignant"]],
["bestowal", ["bestowment"]],
["betrothal", ["betrothment"]],
["blameworthiness", ["blamableness"]],
["buck naked", ["butt naked"]],
["captor", ["capturer"]],
["carte blanche", ["carta blanca"]],
["casualties", ["casualities"]],
["casualty", ["casuality"]],
["catch fire", ["catch on fire"]],
["catholically", ["catholicly"]],
["ceasefire", ["cease fire"]],
["cellphone", ["cell phone", "cell-phone"]],
["channel", ["channelize"]],
["chaplaincy", ["chaplainship"]],
["chrysalis", ["chrysalid"]],
["chrysalises", ["chrysalids"]],
["cigarette", ["cigaret"]],
["cliquish", ["cliquey", "cliquy"]],
["cognitive", ["cognitional"]],
["cohabit", ["cohabitate"]],
["cohabitant", ["cohabitor"]],
["collodion", ["collodium"]],
["collusive", ["collusory"]],
["commemorative", ["commemoratory"]],
["commonage", ["commonty"]],
["communicative", ["communicatory"]],
["compensatory", ["compensative"]],
["complacency", ["complacence"]],
["complicit", ["complicitous"]],
["compute", ["computate"]],
["comrade", ["camarade"]],
["conciliatory", ["conciliative"]],
["concomitance", ["concomitancy"]],
["condonation", ["condonance"]],
["confirmatory", ["confirmative"]],
["congruence", ["congruency"]],
["connote", ["connotate"]],
["consanguine", ["consanguineal"]],
["conspicuousness", ["conspicuity"]],
["conspirator", ["conspiratorialist"]],
["constitutionalist", ["constitutionist"]],
["contemporaneous", ["cotemporaneous"]],
["contemporary", ["cotemporary"]],
["contigency", ["contingence"]],
["contributory", ["contributary"]],
["contumacy", ["contumacity"]],
["convertible", ["conversible"]],
["conveyance", ["conveyal"]],
["corroborative", ["corroboratory"]],
["coworker", ["coemployee"]],
["curative", ["curatory"]],
["daredevilry", ["daredeviltry"]],
["deceptive", ["deceptious"]],
["defamatory", ["defamative"]],
["degenerative", ["degeneratory"]],
["delimit", ["delimitate"]],
["delusive", ["delusory"]],
["denunciation", ["denouncement"]],
["depositary", ["depositee"]],
["depreciatory", ["depreciative"]],
["deprivation", ["deprival"]],
["derogatory", ["derogative"]],
["destructible", ["destroyable"]],
["dethrone", ["disenthrone"]],
["detoxify", ["detoxicate"]],
["detractive", ["detractory"]],
["deuterogamy", ["digamy"]],
["deviance", ["deviancy"]],
["deviant", ["deviationist"]],
["digitize", ["digitalize"]],
["diminution", ["diminishment"]],
["diplomat", ["diplomatist"]],
["disciplinary", ["disciplinatory"]],
["discriminating", ["discriminant"]],
["disintegrative", ["disintegratory"]],
["dismissal", ["dismission"]],
["disorient", ["disorientate"]],
["disoriented", ["disorientated"]],
["disquiet", ["disquieten"]],
["dissociate", ["disassociate"]],
["distrait", ["distraite"]],
["divergence", ["divergency"]],
["divisible", ["dividable"]],
["doctrinaire", ["doctrinary"]],
["documentary", ["documental"]],
["domesticate", ["domesticize"]],
["doubt", ["misdoubt"]],
["duplicative", ["duplicatory"]],
["dutiful", ["duteous"]],
["educationist", ["educationalist"]],
["educative", ["educatory"]],
["empanel", ["impanel"]],
["encumbrance", ["cumbrance"]],
["endow", ["indow"]],
["endue", ["indue"]],
["enigmas", ["enigmatas"]],
["enlarge", ["enlargen"]],
["epic", ["epical"]],
["eroticism", ["erotism"]],
["ethicist", ["ethician"]],
["ex officio", ["ex officiis"]],
["exculpatory", ["exculpative"]],
["exigency", ["exigence"]],
["exigent", ["exigeant"]],
["exoticism", ["exotism"]],
["expediency", ["expedience"]],
["expedient", ["expediential"]],
["expedient", ["expediential"]],
["extendable", ["extensible"]],
["eyeing", ["eying"]],
["fief", ["fiefdom"]],
["flagrancy", ["flagrance"]],
["flatulence", ["flatulency"]],
["fraudulent", ["defraudulent"]],
["fraudulent", ["fraudful"]],
["funereal", ["funebrial"]],
["geographic", ["geographical"]],
["geometric", ["geometrical"]],
["goatherd", ["goatherder"]],
["grievance", ["aggrievance"]],
["gustatory", ["gustatorial"]],
["habit", ["habitude"]],
["henceforth", ["henceforward"]],
["hesitancy", ["hesitance"]],
["heterogeneous", ["heterogenous"]],
["hierarchical", ["hierarchic"]],
["hindmost", ["hindermost"]],
["honoree", ["honorand"]],
["hypostatize", ["hypostasize"]],
["hysterical", ["hysteric"]],
["idolize", ["idolatrize"]],
["impersonation", ["personation"]],
["impervious", ["imperviable"]],
["importunity", ["importunacy"]],
["impotence", ["impotency"]],
["imprimatur", ["imprimatura"]],
["improper", ["improprietous"]],
["incitement", ["incitation"]],
["inconsistency", ["inconsistence"]],
["incriminate", ["criminate"]],
["inculpatory", ["culpatory"]],
["incurrence", ["incurment"]],
["infrequent", ["unfrequent"]],
["inhibitory", ["inhibitive"]],
["innovative", ["innovational"]],
["inquisitorial", ["inquisitional"]],
["insistence", ["insistment"]],
["instillation", ["instillment"]],
["instinctive", ["instinctual"]],
["insubstantial", ["unsubstantial"]],
["insurer", ["insuror"]],
["insurrectionary", ["insurrectional"]],
["interpret", ["interpretate"]],
["intervention", ["intervenience"]],
["ironic", ["ironical"]],
["irrevocable", ["unrevokable"]],
["judgmental", ["judgmatic"]],
["jury-rigged", ["gerry-rigged"]],
["jury-rigged", ["jerry-rigged"]],
["kaffeeklatsch", ["Coffee klatsch", "coffee klatch"]],
["knickknack", ["nicknack"]],
["labyrinthine", ["labyrinthian"]],
["laudatory", ["laudative"]],
["legitimation", ["legitimatization"]],
["legitimation", ["legitimization"]],
["legitimize", ["legitimatize"]],
["lengthwise", ["lengthways"]],
["licorice", ["liquorice"]],
["life-size", ["life-sized"]],
["lithe", ["lithesome"]],
["loath", ["loth"]],
["lollypop", ["lollipop"]],
["lubricious", ["lubricous"]],
["mayhem", ["maihem"]],
["medical marijuana", ["medicinal marijuana"]],
["minimize", ["minimalize"]],
["monetize", ["monetarize"]],
["movable", ["moveable"]],
["murk", ["mirk"]],
["murky", ["mirky"]],
["narcissism", ["narcism"]],
["neglectful", ["neglective"]],
["negligence", ["negligency"]],
["neologist", ["neologizer"]],
["neurological", ["neurologic"]],
["nictitate", ["nictate"]],
["normality", ["normalcy"]],
["numbness", ["numbedness"]],
["omissible", ["omittable"]],
["onomatopoeic", ["onomatopoetic"]],
["opined", ["opinioned"]],
["optimal advantage", ["optimum advantage"]],
["orient", ["orientate"]],
["outsize", ["outsized"]],
["oversize", ["oversized"]],
["overthrow", ["overthrowal"]],
["pacifist", ["pacificist"]],
["parti-colored", ["parti-color"]],
["parti-colored", ["party-colored"]],
["participatory", ["participative"]],
["partner", ["copartner"]],
["partnership", ["copartnership"]],
# ["password", ["passcode"]], # FIXME
["patina", ["patine"]],
["pederast", ["paederast"]],
["pediatrician", ["pediatrist"]],
["pejorative", ["perjorative"]],
["penumbral", ["penumbrous"]],
["permissive", ["permissory"]],
["permute", ["permutate"]],
["pharmaceutical", ["pharmaceutic"]],
["pleurisy", ["pleuritis"]],
["policyholder", ["policy holder"]],
["policyholder", ["policyowner"]],
["politicize", ["politicalize"]],
["pre-Columbian", ["precolumbian"]],
["precedence", ["precedency"]],
["preceptorial", ["preceptoral"]],
["precipitancy", ["precipitance"]],
["precipitate", ["precipitant"]],
["preclusive", ["preclusory"]],
["prefectorial", ["prefectoral"]],
["preponderantly", ["preponderately"]],
["preservation", ["preserval"]],
["preventive", ["preventative"]],
["proconsulate", ["proconsulship"]],
["procreative", ["procreational"]],
["procurement", ["procurance"]],
["propulsion", ["propelment"]],
["propulsive", ["propulsory"]],
["prosecutory", ["prosecutive"]],
["protective", ["protectory"]],
["provocative", ["provocatory"]],
["prurience", ["pruriency"]],
["psychical", ["psychal"]],
["punitive", ["punitory"]],
["pygmy", ["pygmean", "pygmaen"]],
["quantify", ["quantitate"]],
["questionnaire", ["questionary"]],
["quiescence", ["quiescency"]],
["rabbi", ["rabbin"]],
["reasonableness", ["reasonability"]],
["recidivous", ["recidivistic"]],
["recriminatory", ["recriminative"]],
["recruitment", ["recruital"]],
["recurrence", ["recurrency"]],
["recusal", ["recusation"]],
["recusal", ["recusement"]],
["recusancy", ["recusance"]],
["redemptive", ["redemptory"]],
["referable", ["referrable"]],
["referable", ["referrible"]],
["refutative", ["refutatory"]],
["remission", ["remittal"]],
["remittance", ["remitment"]],
["renounceable", ["renunciable"]],
["renunciation", ["renouncement"]],
["reparative", ["reparatory"]],
["repudiatory", ["repudiative"]],
["requital", ["requitement"]],
["rescission", ["rescindment"]],
["restoration", ["restoral"]],
["reticence", ["reticency"]],
["retributive", ["retributional", "retributionary"]],
["review", ["reviewal"]],
["revision", ["revisal"]],
["revisionary", ["revisional"]],
["revocable", ["revokable", "revokeable"]],
["revolt", ["revolute"]],
["salience", ["saliency"]],
["salutary", ["salutiferous"]],
["sensory", ["sensatory"]],
["sessional", ["sessionary"]],
["shareholder", ["shareowner"]],
["sickly", ["sicklily"]],
["signatory", ["signator"]],
["slander", ["slanderize"]],
["societal", ["societary"]],
["sodomite", ["sodomist"]],
["solicit", ["solicitate"]],
["speculative", ["speculatory"]],
["spirituous", ["spiritous"]],
["statutory", ["statutorial"]],
["submersible", ["submergeable"]],
["submission", ["submittal"]],
["subtle", ["subtile"]],
["succubus", ["succuba"]],
["sufficiency", ["sufficience"]],
["supplicant", ["suppliant"]],
["surmise", ["surmisal"]],
["suspendable", ["suspendible"]],
["swathe", ["enswathe"]],
["synthesize", ["synthetize"]],
["systematize", ["systemize"]],
["T-shirt", ["tee-shirt"]],
["tactile", ["tactual"]],
["tangential", ["tangental"]],
["tautological", ["tautologous"]],
["thenceforth", ["thenceforward"]],
["transience", ["transiency"]],
["transposition", ["transposal"]],
["transposition", ["transposal"]],
["unalterable", ["inalterable"]],
["uncommunicative", ["incommunicative"]],
["uncontrollable", ["incontrollable"]],
["unenforceable", ["nonenforceable"]],
["unnavigable", ["innavigable"]],
["unreasonableness", ["unreasonability"]],
["unsolvable", ["insolvable"]],
["usurpation", ["usurpature"]],
["variational", ["variative"]],
["vegetative", ["vegetive"]],
["vindictive", ["vindicative"]],
["vituperative", ["vituperous"]],
["vociferous", ["vociferant"]],
["volitional", ["volitive"]],
["wolfish", ["wolvish"]],
["wolverine", ["wolverene"]],
["Zoroastrianism", ["Zoroastrism"]],
]
return preferred_forms_check(text, preferences, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/nonwords/__init__.py 0000644 0000000 0000000 00000000020 00000000000 017732 0 ustar 00 """Nonwords."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/nonwords/misc.py 0000644 0000000 0000000 00000004560 00000000000 017143 0 ustar 00 """Nonwords.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: nonwords
date: 2014-06-10 12:31:19
categories: writing
---
Nonwords.
"""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "nonwords.misc"
msg = "Nonword, try '{}'."
preferences = [
["doubtless' or 'undoubtedly", ["doubtlessly"]],
["analysis", ["analyzation"]],
["annoyance", ["annoyment"]],
["confirmand", ["confirmant"]],
["confirmands", ["confirmants"]],
["converse", ["conversate"]],
["cranded", ["crained"]],
["disbursement' or 'dispersal", ["dispersement"]],
["discomfort' or 'discomfiture", ["discomforture"]],
["effrontery", ["affrontery"]],
["forbearance", ["forebearance"]],
["improper", ["improprietous"]],
["inclement", ["inclimate"]],
["relatively low price' or 'affordability", ["relative inexpense"]],
["inimical", ["inimicable"]],
["regardless", ["irregardless"]],
["minimize", ["minimalize"]],
["minimized", ["minimalized"]],
["minimizes", ["minimalizes"]],
["minimizing", ["minimalizing"]],
# muchly
["optimize", ["optimalize"]],
["paralysis", ["paralyzation"]],
["pettifog", ["pettifogger"]],
["proper", ["proprietous"]],
["quell' or 'quash", ["squelch"]],
["seldom", ["seldomly"]],
# slinged
["thus", ["thusly"]],
["categorically", ["uncategorically"]],
["undoubtedly' or 'indubitably", ["undoubtably"]],
["unequivocal", ["unequivocable"]],
["mercilessly", ["unmercilessly"]],
["unrelentingly' or relentlessly", ["unrelentlessly"]],
]
return preferred_forms_check(text, preferences, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/oxymorons/__init__.py 0000644 0000000 0000000 00000000021 00000000000 020137 0 ustar 00 """Oxymorons."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/oxymorons/misc.py 0000644 0000000 0000000 00000002055 00000000000 017344 0 ustar 00 """Oxymorons.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: Oxymorons
date: 2014-06-10 12:31:19
categories: writing
---
Archaism.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "oxymorons.misc"
msg = "'{}' is an oxymoron."
oxymorons = [
"amateur expert",
"increasingly less",
"advancing backwards?",
"alludes explicitly to",
"explicitly alludes to",
"totally obsolescent",
"completely obsolescent",
"generally always",
"usually always",
"increasingly less",
"build down",
"conspicuous absence",
"exact estimate",
"found missing",
"intense apathy",
"mandatory choice",
"nonworking mother",
"organized mess",
# "pretty ugly",
# "sure bet",
# "executive secretary",
]
return existence_check(text, oxymorons, err, msg, offset=1, join=True)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/psychology/__init__.py 0000644 0000000 0000000 00000000031 00000000000 020263 0 ustar 00 """Advice on science."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/psychology/misc.py 0000644 0000000 0000000 00000002554 00000000000 017473 0 ustar 00 """Psychological and psychiatric terms to avoid.
---
layout: post
source: Scott O. Lilienfeld, et al.
source_url: http://dx.doi.org/10.3389/fpsyg.2015.01100
title: psychological and psychiatric terms to avoid
date: 2014-06-10 12:31:19
categories: writing
---
Psychological and psychiatric terms to avoid.
"""
from proselint.tools import existence_check, memoize, preferred_forms_check
@memoize
def check_lie_detector_test(text):
"""Suggest the preferred forms."""
err = "psychology.lie_detector"
msg = "Polygraph machines measure arousal, not lying per se. Try {}."
list = [
["polygraph test", ["lie detector test"]],
["polygraph machine", ["lie detector machine"]],
]
return preferred_forms_check(text, list, err, msg)
@memoize
def check_p_equals_zero(text):
"""Check for p = 0.000."""
err = "psychology.p_equals_zero"
msg = "Unless p really equals zero, you should use more decimal places."
list = [
"p = 0.00",
"p = 0.000",
"p = 0.0000",
]
return existence_check(text, list, err, msg, join=True)
@memoize
def check_mental_telepathy(text):
"""Check for 'mental telepathy'."""
err = "psychology.mental_telepathy"
msg = "This is redundant because all purported telepathy is mental."
return existence_check(text, ["mental telepathy"], err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/redundancy/__init__.py 0000644 0000000 0000000 00000000022 00000000000 020217 0 ustar 00 """Redundancy."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/redundancy/misc.py 0000644 0000000 0000000 00000060733 00000000000 017432 0 ustar 00 """Redundancy."""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "redundancy.wallace"
msg = "Redundancy. Use '{}' instead of '{}'."
redundancies = [
["rectangular", ["rectangular in shape"]],
["audible", ["audible to the ear"]],
]
return preferred_forms_check(text, redundancies, err, msg)
@memoize
def check_garner(text):
"""Suggest the preferred forms.
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
"""
err = "redundancy.garner"
msg = "Redundancy. Use '{}' instead of '{}'."
redundancies = [
["adequate", ["adequate enough"]],
["admitted", ["self-admitted"]],
["affidavit", ["sworn affidavit"]],
["agreement", ["mutual agreement"]],
["alumnus", ["former alumnus"]],
["antithetical", ["directly antithetical"]],
["approximately", ["approximately about"]],
["associate", ["associate together(?: in groups)?"]],
["bivouac", ["temporary bivouac", "bivouac camp"]],
["blend", ["blend together"]],
["but", ["but nevertheless"]],
["charged with...", ["accused of a charge"]],
["circumstances of", ["circumstances surrounding"]],
["circumstances", ["surrounding circumstances"]],
["close", ["close proximity"]],
["collaborate", ["collaborate together"]],
["collaborator", ["fellow collaborator"]],
["collaborators", ["fellow collaborators"]],
["collocated", ["collocated together"]],
["colleagues", ["fellow colleagues"]],
["combine", ["combine together"]],
["complacent", ["self-complacent"]],
["confessed", ["self-confessed"]],
["connect", ["connect together"]],
["consensus", ["(?:general )?consensus of opinion"]],
["consolidate", ["consolidate together"]],
["continues to", ["still continues to"]],
["contradictory", ["mutually contradictory"]],
["cooperation", ["mutual cooperation"]],
["couple", ["couple together"]],
["crisis", ["serious crisis"]],
["eliminate", ["entirely eliminate"]],
["especially", ["most especially"]],
["fact", ["actual fact"]],
["facts", ["true facts"]],
["forecast", ["future forecast"]],
["founding fathers", ["founding forefathers"]],
["free", ["free and gratis"]],
["free", ["free gratis"]],
["full", ["completely full"]],
["fundamentals", ["basic fundamentals"]],
["gift", ["free gift"]],
["innovation", ["new innovation"]],
["interact", ["interact with each other"]],
["large", ["large-size"]],
["meld", ["meld together"]],
["merge", ["merge together"]],
["mingle", ["mingle together"]],
["mix", ["mix together"]],
["mutual feelings", ["mutual feelings for eachother"]],
["mutual respect", ["mutual respect for each other"]],
["native citizen", ["native-born citizen"]],
["necessity", ["absolute necessity"]],
["obvious", ["blatantly obvious"]],
["pause", ["pause for a moment"]],
["planning", ["advance planning"]],
["plans", ["future plans"]],
["pooled", ["pooled together"]],
["potable water", ["potable drinking water"]],
["potable water", ["potable drinking water"]],
["recruit", ["new recruit"]],
["reelected", ["reelected for another term"]],
["refer", ["refer back"]],
["regress", ["regress back"]],
["repay them", ["repay them back"]],
["repay", ["repay back"]],
["repeat", ["repeat again"]],
["repeat", ["repeat back"]],
["repeat", ["repeat the same"]],
["repeated", ["repeated the same"]],
["reprieve", ["temporary reprieve"]],
["respite", ["brief respite"]],
["retirement", ["retiral", "retiracy"]],
["retreat", ["retreat back"]],
["return", ["return back"]],
["scrutinize", ["closely scrutinize"]],
["software", ["software program"]],
["surrounded", ["surrounded on all sides"]],
["the nation", ["the whole entire nation"]],
["throughout the", ["throughout the entire"]],
["timpani", ["timpani drum"]],
["twins", ["pair of twins"]],
["vacancy", ["unfilled vacancy"]],
["various", ["various different"]],
["veteran", ["former veteran"]],
["visible", ["visible to the eye"]],
["vocation", ["professional vocation"]],
["while", ["while at the same time"]],
]
return preferred_forms_check(text, redundancies, err, msg)
@memoize
def check_nordquist(text):
"""Suggest the preferred forms.
source: Richard Nordquist
source_url: http://grammar.about.com/bio/Richard-Nordquist-22176.htm
"""
err = "redundancy.nordquist"
msg = "Redundancy. Use '{}' instead of '{}'."
redundancies = [
["essential", ["absolutely essential"]],
["necessary", ["absolutely necessary"]],
["a.m.", ["a.m. in the morning"]],
["p.m.", ["p.m. at night"]],
]
return preferred_forms_check(text, redundancies, err, msg)
@memoize
def check_atd(text):
"""Check for redundancies from After the Deadline."""
err = "after_the_deadline.redundancy"
msg = "Redundancy. Use '{}' instead of '{}'."
redundancies = [
["Bō", ["Bo Staff"]],
["Challah", ["Challah bread"]],
["Hallah", ["Hallah bread"]],
["Challah", ["Challah bread"]],
["I", ["I myself", "I personally"]],
["Mount Fuji", ["Mount Fujiyama"]],
["Milky Way", ["Milky Way galaxy"]],
["Rio Grande", ["Rio Grande river"]],
["adage", ["old adage"]],
["add", ["add a further", "add an additional"]],
["advance", ["advance forward"]],
["alternative", ["alternative choice"]],
["amaretto", ["amaretto almond"]],
["annihilate", ["completely annihilate"]],
["anniversary", ["annual anniversary"]],
["anonymous", ["unnamed anonymous"]],
["as", ["equally as"]],
["ascend", ["ascend up"]],
["ask", ["ask the question"]],
["assemble", ["assemble together"]],
["at present the", ["at the present time the"]],
["at this point", ["at this point in time"]],
["attach", ["attach together"]],
["autumn", ["autumn season"]],
["bald", ["bald-headed"]],
["balsa", ["balsa wood"]],
["belongings", ["personal belongings"]],
["benefits", ["desirable benefits"]],
["bento", ["bento box"]],
["best", ["best ever"]],
["bit", ["tiny bit"]],
["blend", ["blend together"]],
["bond", ["common bond"]],
["bonus", ["added bonus", "extra bonus"]],
["bouquet", ["bouquet of flowers"]],
["breakthrough", ["major breakthrough"]],
["bride", ["new bride"]],
["brief", ["brief in duration"]],
["bruin", ["bruin bear"]],
["hot", ["burning hot"]],
["cacophony", ["cacophony of sound"]],
["cameo", ["brief cameo", "cameo appearance"]],
["cancel", ["cancel out"]],
["cash", ["cash money"]],
["chai", ["chai tea"]],
["chance", ["random chance"]],
["charm", ["personal charm"]],
["circle", ["circle around", "round circle"]],
["circulate", ["circulate around"]],
["classify", ["classify into groups"]],
["classmates", ["fellow classmates"]],
["cliche", ["old cliche", "overused cliche"]],
["climb", ["climb up"]],
["clock", ["time clock"]],
["collaborate", ["collaborate together"]],
["collaboration", ["joint collaboration"]],
["colleague", ["fellow colleague"]],
["combine", ["combine together"]],
["commute", ["commute back and forth"]],
["compete", ["compete with each other"]],
["comprise", ["comprise of"]],
["comprises", ["comprises of"]],
["conceived", ["first conceived"]],
["conclusion", ["final conclusion"]],
["confer", ["confer together"]],
["confrontation", ["direct confrontation"]],
# ["confused", ["confused state"]],
["connect", ["connect together", "connect up"]],
["consensus", ["consensus of opinion", "general consensus"]],
["consult", ["consult with"]],
["conversation", ["oral conversation"]],
["cool", ["cool down"]],
["cooperate", ["cooperate together"]],
["cooperation", ["mutual cooperation"]],
["copy", ["duplicate copy"]],
["core", ["inner core"]],
["cost", ["cost the sum of"]],
["could", ["could possibly"]],
["coupon", ["money-saving coupon"]],
["created", ["originally created"]],
["crisis", ["crisis situation"]],
["crouch", ["crouch down"]],
["currently", ["now currently"]],
["custom", ["old custom", "usual custom"]],
["danger", ["serious danger"]],
["dates", ["dates back"]],
["decision", ["definite decision"]],
["depreciate", ["depreciate in value"]],
["descend", ["descend down"]],
["destroy", ["totally destroy"]],
["destroyed", ["completely destroyed"]],
["destruction", ["total destruction"]],
["details", ["specific details"]],
["dilemma", ["difficult dilemma"]],
["disappear", ["disappear from sight"]],
["discovered", ["originally discovered"]],
["dive", ["dive down"]],
["done", ["over and done with"]],
["drawing", ["illustrated drawing"]],
["drop", ["drop down"]],
["dune", ["sand dune"]],
["during", ["during the course of"]],
["dwindle", ["dwindle down"]],
["dwindled", ["dwindled down"]],
["every", ["each and every"]],
["earlier", ["earlier in time"]],
["eliminate", ["completely eliminate", "eliminate altogether",
"entirely eliminate"]],
["ember", ["glowing ember"]],
["embers", ["burning embers"]],
["emergency", ["emergency situation", "unexpected emergency"]],
["empty", ["empty out"]],
["enclosed", ["enclosed herein"]],
["end", ["final end"]],
["engulfed", ["completely engulfed"]],
["enter", ["enter in", "enter into"]],
["equal", ["equal to one another"]],
["eradicate", ["eradicate completely"]],
["essential", ["absolutely essential"]],
["estimated at", ["estimated at about",
"estimated at approximately",
"estimated at around"]],
["etc.", ["and etc."]],
["evolve", ["evolve over time"]],
["exaggerate", ["over exaggerate"]],
["exited", ["exited from"]],
["experience", ["actual experience", "past experience"]],
["experts", ["knowledgeable experts"]],
["extradite", ["extradite back"]],
["face the consequences", ["face up to the consequences"]],
["face the fact", ["face up to the fact"]],
["face the challenge", ["face up to the challenge"]],
["face the problem", ["face up to the problem"]],
["facilitate", ["facilitate easier"]],
["fact", ["established fact"]],
["facts", ["actual facts", "hard facts", "true facts"]],
["fad", ["passing fad"]],
["fall", ["fall down"]],
["fall", ["fall season"]],
["feat", ["major feat"]],
["feel", ["feel inside"]],
["feelings", ["inner feelings"]],
["few", ["few in number"]],
["filled", ["completely filled", "filled to capacity"]],
["first", ["first of all"]],
["first time", ["first time ever"]],
["fist", ["closed fist"]],
["fly", ["fly through the air"]],
["focus", ["focus in", "main focus"]],
["follow", ["follow after"]],
["for example", ["as for example"]],
# ["foremost", ["first and foremost"]],
["forever", ["forever and ever"]],
["free", ["for free"]],
["friend", ["personal friend"]],
["friendship", ["personal friendship"]],
["full", ["full to capacity"]],
["fundamentals", ["basic fundamentals"]],
["fuse", ["fuse together"]],
["gather", ["gather together", "gather up"]],
["get up", ["get up on his feet", "get up on your feet"]],
["gift", ["free gift"]],
["gifts", ["free gifts"]],
["goal", ["ultimate goal"]],
# ["graduate", ["former graduate"]],
["grow", ["grow in size"]],
["guarantee", ["absolute guarantee"]],
["gunman", ["armed gunman"]],
["gunmen", ["armed gunmen"]],
["habitat", ["native habitat"]],
["had done", ["had done previously"]],
["halves", ["two equal halves"]],
# ["has", ["has got"]],
# ["have", ["have got"]],
["haven", ["safe haven"]],
# ["he", ["he himself"]],
["heat", ["heat up"]],
["history", ["past history"]],
["hoist", ["hoist up"]],
["hole", ["empty hole"]],
["honcho", ["head honcho"]],
["ice", ["frozen ice"]],
["ideal", ["perfect ideal"]],
["identical", ["same identical"]],
["identification", ["positive identification"]],
["imports", ["foreign imports"]],
["impulse", ["sudden impulse"]],
["in fact", ["in actual fact"]],
["in the yard", ["outside in the yard"]],
["inclusive", ["all inclusive"]],
["incredible", ["incredible to believe"]],
["incumbent", ["present incumbent"]],
# ["indicted", ["indicted on a charge"]],
["industry", ["private industry"]],
["injuries", ["harmful injuries"]],
["innovation", ["new innovation"]],
["innovative", ["innovative new", "new innovative"]],
# ["input", ["input into"]],
["instinct", ["natural instinct", "naturally instinct"]],
["integrate", ["integrate together",
"integrate with each other"]],
["interdependent", ["interdependent on each other",
"mutually interdependent"]],
["introduced", ["introduced for the first time"]],
["invention", ["new invention"]],
["kneel", ["kneel down"]],
["knots", ["knots per hour"]],
# ["last", ["last of all"]],
# ["later", ["later time"]],
["lift", ["lift up"]],
["lingers", ["still lingers"]],
["look to the future", ["look ahead to the future"]],
["love triangle", ["three-way love triangle"]],
["maintained", ["constantly maintained"]],
["manually", ["manually by hand"]],
["marina", ["boat marina"]],
["may", ["may possibly"]],
["meet", ["meet together", "meet with each other"]],
["memories", ["past memories"]],
["merge", ["merge together"]],
["merged", ["merged together"]],
["meshed", ["meshed together"]],
["midnight", ["twelve midnight"]],
["migraine", ["migraine headache"]],
["minestrone", ["minestrone soup"]],
["mix", ["mix together"]],
["moment", ["brief moment", "moment in time"]],
["monopoly", ["complete monopoly"]],
["mural", ["wall mural"]],
["mutual respect", ["mutual respect for each other"]],
["mutually dependent", ["mutually dependent on each other"]],
["mystery", ["unsolved mystery"]],
# ["naked", ["bare naked"]],
["nape", ["nape of her neck"]],
["necessary", ["absolutely necessary"]],
["never", ["never at any time"]],
["noon", ["12 noon", "12 o'clock noon", "high noon",
"twelve noon"]],
["nostalgia", ["nostalgia for the past"]],
["number of", ["number of different"]],
["opening", ["exposed opening"]],
["my opinion", ["my personal opinion"]],
["opposites", ["exact opposites", "polar opposites"]],
["opposite", ["exact opposite", "polar opposite"]],
["orbits", ["orbits around"]],
["outcome", ["final outcome"]],
["panacea", ["universal panacea"]],
["pending", ["now pending"]],
["penetrate", ["penetrate through"]],
["persists", ["still persists"]],
["pioneer", ["old pioneer"]],
["plan", ["plan ahead", "plan in advance",
"proposed plan"]],
["planning", ["advance planning", "forward planning"]],
["plans", ["future plans"]],
["plan", ["future plan"]],
["point", ["point in time"]],
["point", ["sharp point"]],
["postpone", ["postpone until later"]],
["pouring rain", ["pouring down rain"]],
["preview", ["advance preview"]],
["previously listed", ["previously listed above"]],
["probed", ["probed into"]],
["proceed", ["proceed ahead"]],
["prosthesis", ["artificial prosthesis"]],
# ["protrude", ["protrude out"]],
["proverb", ["old proverb"]],
# ["proximity", ["close proximity"]],
["put off", ["put off until later"]],
# ["raise", ["raise up"]],
["re-elect", ["re-elect for another term"]],
["reason is", ["reason is because"]],
["recur", ["recur again"]],
["recurrence", ["future recurrence"]],
["refer", ["refer back"]],
["reflect", ["reflect back"]],
# ["relevant", ["highly relevant"]],
["remain", ["continue to remain"]],
["remains", ["still remains"]],
["replica", ["exact replica"]],
["reply", ["reply back"]],
# ["requirements", ["necessary requirements"]],
["reservations", ["advance reservations"]],
["retreat", ["retreat back"]],
["revert", ["revert back"]],
["round", ["round in shape"]],
["rule of thumb", ["rough rule of thumb"]],
["rumor", ["unconfirmed rumor"]],
["rustic", ["rustic country"]],
["same", ["exact same", "precise same", "same exact"]],
["sanctuary", ["safe sanctuary"]],
["satisfaction", ["full satisfaction"]],
["scrutinize", ["scrutinize in detail"]],
["scrutiny", ["careful scrutiny", "close scrutiny"]],
["secret", ["secret that cannot be told"]],
["seek", ["seek to find"]],
["separated", ["separated apart from each other"]],
["share", ["share together"]],
["shiny", ["shiny in appearance"]],
["sincere", ["truly sincere"]],
["sink", ["sink down"]],
["skipped", ["skipped over"]],
# ["slow", ["slow speed"]],
# ["small", ["small size"]],
["soft", ["soft in texture", "soft to the touch"]],
["sole", ["sole of the foot"]],
["some time", ["some time to come"]],
["speck", ["small speck"]],
["speed", ["rate of speed"]],
["spell out", ["spell out in detail"]],
["spiked", ["spiked upward", "spiked upwards"]],
["spring", ["spring season"]],
["stranger", ["anonymous stranger"]],
["studio audience", ["live studio audience"]],
["subway", ["underground subway"]],
["sufficient", ["sufficient enough"]],
["summer", ["summer season"]],
["sure", ["absolutely sure"]],
["surprise", ["unexpected surprise"]],
["surround", ["completely surround"]],
["surrounded", ["surrounded on all sides"]],
["tall", ["tall in height", "tall in stature"]],
["telepathy", ["mental telepathy"]],
["ten", ["ten in number"]],
["these", ["these ones"]],
# ["they", ["they themselves"]],
["those", ["those ones"]],
["trench", ["open trench"]],
["truth", ["honest truth"]],
["tundra", ["frozen tundra"]],
["ultimatum", ["final ultimatum"]],
# ["undeniable", ["undeniable truth"]],
["undergraduate", ["undergraduate student"]],
# ["unintentional", ["unintentional mistake"]],
["vacillate", ["vacillate back and forth"]],
["veteran", ["former veteran"]],
["visible", ["visible to the eye"]],
["warn", ["warn in advance"]],
["warning", ["advance warning"]],
["water heater", ["hot water heater"]],
["in which we live", ["in which we live in"]],
["winter", ["winter season"]],
["witness", ["live witness"]],
["yakitori", ["yakitori chicken"]],
["yerba mate", ["yerba mate tea"]],
["yes", ["affirmative yes"]],
]
return preferred_forms_check(text, redundancies, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/redundancy/ras_syndrome.py 0000644 0000000 0000000 00000002432 00000000000 021174 0 ustar 00 """Redundant Acronym Syndrome (RAS) syndrome."""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "garner.redundancy.ras"
msg = "RAS syndrome. Use '{}' instead of '{}'."
redundancies = [
["ABM", ["ABM missile"]],
["ACT", ["ACT test"]],
["ABMs", ["ABM missiles"]],
["ABS", ["ABS braking system"]],
["ATM", ["ATM machine"]],
["CD", ["CD disc"]],
["CPI", ["CPI Index"]],
["GPS", ["GPS system"]],
["GUI", ["GUI interface"]],
["HIV", ["HIV virus"]],
["ISBN", ["ISBN number"]],
["LCD", ["LCD display"]],
["PDF", ["PDF format"]],
["PIN", ["PIN number"]],
["RAS", ["RAS syndrome"]],
["RIP", ["RIP in peace"]],
["RSVP", ["please RSVP"]],
["SALT", ["SALT talks"]],
["SAT", ["SAT test"]],
["UPC", ["UPC codes"]],
]
return preferred_forms_check(text, redundancies, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/security/__init__.py 0000644 0000000 0000000 00000000020 00000000000 017730 0 ustar 00 """Security."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/security/credit_card.py 0000644 0000000 0000000 00000001167 00000000000 020451 0 ustar 00 """Credit card number printed.
---
layout: post
source: ???
source_url: ???
title: credit card number printed
date: 2014-06-10 12:31:19
categories: writing
---
Credit card number printed.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "security.credit_card"
msg = "Don't put credit card numbers in plain text."
credit_card_numbers = [
r"4\d{15}",
r"5[1-5]\d{14}",
r"3[4,7]\d{13}",
r"3[0,6,8]\d{12}",
r"6011\d{12}",
]
return existence_check(text, credit_card_numbers, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/security/password.py 0000644 0000000 0000000 00000001246 00000000000 020046 0 ustar 00 """Password in plain text.
---
layout: post
source: ???
source_url: ???
title: password in plain text
date: 2014-06-10 12:31:19
categories: writing
---
Don't put pass
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "security.password"
msg = "Don't put passwords in plain text."
pwd_regex = r"[:]? [\S]{6,30}"
password = [
f"the password is{pwd_regex}",
f"my password is{pwd_regex}",
f"the password's{pwd_regex}",
f"my password's{pwd_regex}",
f"^[pP]assword{pwd_regex}",
]
return existence_check(text, password, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/sexism/__init__.py 0000644 0000000 0000000 00000000016 00000000000 017376 0 ustar 00 """Sexism."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/sexism/misc.py 0000644 0000000 0000000 00000004757 00000000000 016612 0 ustar 00 """Sexism.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: sexism
date: 2014-06-10 12:31:19
categories: writing
---
Points out sexist language.
"""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "sexism.misc"
msg = "Gender bias. Use '{}' instead of '{}'."
sexism = [
["anchor", ["anchorman", "anchorwoman"]],
["chair", ["chairman", "chairwoman"]],
["drafter", ["draftman", "draftwoman"]],
["ombuds", ["ombudsman", "ombudswoman"]],
["tribe member", ["tribesman", "tribeswoman"]],
["police officer", ["policeman", "policewoman"]],
["firefighter", ["fireman", "firewoman"]],
["mail carrier", ["mailman", "mailwoman"]],
["history", ["herstory"]],
["women", ["womyn"]],
["poet", ["poetess"]],
["author", ["authoress"]],
["waiter", ["waitress"]],
["lawyer", ["lady lawyer"]],
["doctor", ["woman doctor"]],
["bookseller", ["female booksalesman"]],
["air pilot", ["female airman"]],
["executor", ["executrix"]],
["prosecutor", ["prosecutrix"]],
["testator", ["testatrix"]],
["husband and wife", ["man and wife"]],
["chairs", ["chairmen and chairs"]],
["men and women", ["men and girls"]],
["comedian", ["comedienne"]],
["confidant", ["confidante"]],
["scientist", ["woman scientist"]],
["scientists", ["women scientists"]]
# ["hero", ["heroine"]]
]
errors = preferred_forms_check(text, sexism, err, msg, ignore_case=False)
msg = "Not a preferred form. Use '{}' instead of '{}'."
pref = [
["anchor", ["anchorperson"]],
["chair", ["chairperson"]],
["drafter", ["draftperson"]],
["ombuds", ["ombudsperson"]],
["tribe member", ["tribesperson"]],
["police officer", ["policeperson"]],
["firefighter", ["fireperson"]],
["mail carrier", ["mailperson"]],
]
for x in preferred_forms_check(text, pref, err, msg, ignore_case=False):
errors.append(x)
return errors
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/skunked_terms/__init__.py 0000644 0000000 0000000 00000000033 00000000000 020743 0 ustar 00 """Avoid skunked terms."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/skunked_terms/misc.py 0000644 0000000 0000000 00000001342 00000000000 020143 0 ustar 00 """Skunked terms.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: Skunked terms.
date: 2014-06-10 12:31:19
categories: writing
---
Archaism.
"""
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "skunked_terms.misc"
msg = """'{}' is a bit of a skunked term, impossible to use without issue.
Find some other way to say it."""
skunked_terms = [
"bona fides",
"deceptively",
"decimate",
"effete",
"fulsome",
"hopefully",
"impassionate",
"Thankfully,",
]
return existence_check(text, skunked_terms, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.182823
proselint-0.13.0/proselint/checks/spelling/__init__.py 0000644 0000000 0000000 00000000020 00000000000 017676 0 ustar 00 """Spelling."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/checks/spelling/able_atable.py 0000644 0000000 0000000 00000007127 00000000000 020371 0 ustar 00 """-able vs. -atable."""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""-able vs. -atable."""
err = "spelling.able_atable"
msg = "-able vs. -atable. '{}' is the preferred spelling."
preferences = [
["abbreviable", ["abbreviatable"]],
["abdicable", ["abdicatable"]],
["abrogable", ["abrogatable"]],
["accommodable", ["accommodatable"]],
["accumulable", ["accumulatable"]],
["activable", ["activatable"]],
["administrable", ["administratable"]],
["adulterable", ["adulteratable"]],
["affiliable", ["affiliatable"]],
["aggregable", ["aggregatable"]],
["agitable", ["agitatable"]],
["alienable", ["alienatable"]],
["alleviable", ["alleviatable"]],
["allocable", ["allocatable"]],
["ameliorable", ["amelioratable"]],
["annihilable", ["annihilatable"]],
["appreciable", ["appreciatable"]],
["appropriable", ["appropriatable"]],
["arbitrable", ["arbitratable"]],
["articulable", ["articulatable"]],
["calculable", ["calculatable"]],
["communicable", ["communicatable"]],
["compensable", ["compensatable"]],
["confiscable", ["confiscatable"]],
["corroborable", ["corroboratable"]],
["cultivable", ["cultivatable"]],
["delegable", ["delegatable"]],
["delineable", ["delineatable"]],
["demonstrable", ["demonstratable"]],
["detonable", ["detonatable"]],
["differentiable", ["differentiatable"]],
["eradicable", ["eradicatable"]],
["evacuable", ["evacuatable"]],
["evaluable", ["evaluatable"]],
["expropriable", ["expropriatable"]],
["generable", ["generatable"]],
["indicable", ["indicatable"]],
["inebriable", ["inebriatable"]],
["inextirpable", ["inextirpatable"]],
["inextricable", ["inextricatable"]],
["infatuable", ["infatuatable"]],
["infuriable", ["infuriatable"]],
["invalidable", ["invalidatable"]],
["investigable", ["investigatable"]],
["isolable", ["isolatable"]],
["litigable", ["litigatable"]],
["manipulable", ["manipulatable"]],
["medicable", ["medicatable"]],
["navigable", ["navigatable"]],
["obligable", ["obligatable"]],
["obviable", ["obviatable"]],
["operable", ["operatable"]],
["originable", ["originatable"]],
["participable", ["participatable"]],
["penetrable", ["penetratable"]],
["perpetrable", ["perpetratable"]],
["perpetuable", ["perpetuatable"]],
["predicable", ["predicatable"]],
["propagable", ["propagatable"]],
["regulable", ["regulatable"]],
["replicable", ["replicatable"]],
["repudiable", ["repudiatable"]],
["segregable", ["segregatable"]],
["separable", ["separatable"]],
["subjugable", ["subjugatable"]],
["vindicable", ["vindicatable"]],
["violable", ["violatable"]],
["vitiable", ["vitiatable"]]
]
return preferred_forms_check(text, preferences, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/checks/spelling/able_ible.py 0000644 0000000 0000000 00000016256 00000000000 020057 0 ustar 00 """-able vs. -ible."""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""-able vs. -ible."""
err = "spelling.able_ible"
msg = "-able vs. -ible. '{}' is the preferred spelling."
preferences = [
["actionable", ["actionible"]],
["addable", ["addible"]],
["admittable", ["admittible"]],
["advisable", ["advisible"]],
["affectable", ["affectible"]],
["allegeable", ["allegeible"]],
["analyzable", ["analyzible"]],
["annexable", ["annexible"]],
["arrestable", ["arrestible"]],
["ascendable", ["ascendible"]],
["assertable", ["assertible"]],
["assessable", ["assessible"]],
["averageable", ["averageible"]],
["bailable", ["bailible"]],
["blamable", ["blamible"]],
["changeable", ["changeible"]],
["chargeable", ["chargeible"]],
["circumscribable", ["circumscribible"]],
["commensurable", ["commensurible"]],
["committable", ["committible"]],
["condensable", ["condensible"]],
["connectable", ["connectible"]],
["contestable", ["contestible"]],
["contractable", ["contractible"]],
["conversable", ["conversible"]],
["convictable", ["convictible"]],
["correctable", ["correctible"]],
["definable", ["definible"]],
["detectable", ["detectible"]],
["diagnosable", ["diagnosible"]],
["discussable", ["discussible"]],
["endorsable", ["endorsible"]],
["enforceable", ["enforceible"]],
["evadable", ["evadible"]],
["excisable", ["excisible"]],
["excludable", ["excludible"]],
["expandable", ["expandible"]],
["extendable", ["extendible"]],
["extractable", ["extractible"]],
["ignitable", ["ignitible"]],
["immovable", ["immovible"]],
["improvable", ["improvible"]],
["includable", ["includible"]],
["inferable", ["inferible"]],
["inventable", ["inventible"]],
["investable", ["investible"]],
["lapsable", ["lapsible"]],
["lovable", ["lovible"]],
["mixable", ["mixible"]],
["movable", ["movible"]],
["noticeable", ["noticeible"]],
["offendable", ["offendible"]],
["patentable", ["patentible"]],
["persuadable", ["persuadible"]],
["preventable", ["preventible"]],
["processable", ["processible"]],
["protectable", ["protectible"]],
["ratable", ["ratible"]],
["redressable", ["redressible"]],
["referable", ["referible"]],
["retractable", ["retractible"]],
["revisable", ["revisible"]],
["rinsable", ["rinsible"]],
["salable", ["salible"]],
["suspendable", ["suspendible"]],
["tractable", ["tractible"]],
["transferable", ["transferible"]],
["transmittable", ["transmittible"]],
["willable", ["willible"]],
["accessible", ["accessable"]],
["adducible", ["adducable"]],
["admissible", ["admissable"]],
["audible", ["audable"]],
["avertible", ["avertable"]],
["collapsible", ["collapsable"]],
["collectible", ["collectable"]],
["combustible", ["combustable"]],
["compactible", ["compactable"]],
["compatible", ["compatable"]],
["comprehensible", ["comprehensable"]],
["compressible", ["compressable"]],
["concussible", ["concussable"]],
["conductible", ["conductable"]],
["contemptible", ["contemptable"]],
["controvertible", ["controvertable"]],
["convertible", ["convertable"]],
["corrodible", ["corrodable"]],
["corruptible", ["corruptable"]],
["credible", ["credable"]],
["deducible", ["deducable"]],
["deductible", ["deductable"]],
["defeasible", ["defeasable"]],
["defensible", ["defensable"]],
["descendible", ["descendable"]],
["destructible", ["destructable"]],
["diffusible", ["diffusable"]],
["digestible", ["digestable"]],
["discernible", ["discernable"]],
["dismissible", ["dismissable"]],
["divisible", ["divisable"]],
["edible", ["edable"]],
["educible", ["educable"]],
["eligible", ["eligable"]],
["erodible", ["erodable"]],
["exhaustible", ["exhaustable"]],
["expressible", ["expressable"]],
["fallible", ["fallable"]],
["feasible", ["feasable"]],
["flexible", ["flexable"]],
["forcible", ["forcable"]],
["fusible", ["fusable"]],
["gullible", ["gullable"]],
["horrible", ["horrable"]],
["impressible", ["impressable"]],
["inadmissible", ["inadmissable"]],
["incorrigible", ["incorrigable"]],
["indelible", ["indelable"]],
["inexpressible", ["inexpressable"]],
["intelligible", ["intelligable"]],
["interfusible", ["interfusable"]],
["invincible", ["invincable"]],
["irascible", ["irascable"]],
["irresistible", ["irresistable"]],
["legible", ["legable"]],
["negligible", ["negligable"]],
["omissible", ["omissable"]],
["oppressible", ["oppressable"]],
["ostensible", ["ostensable"]],
["perceptible", ["perceptable"]],
["perfectible", ["perfectable"]],
["permissible", ["permissable"]],
["plausible", ["plausable"]],
["possible", ["possable"]],
["producible", ["producable"]],
["reducible", ["reducable"]],
["remissible", ["remissable"]],
["reprehensible", ["reprehensable"]],
["repressible", ["repressable"]],
["resistible", ["resistable"]],
["responsible", ["responsable"]],
["reversible", ["reversable"]],
["revertible", ["revertable"]],
["risible", ["risable"]],
["seducible", ["seducable"]],
["sensible", ["sensable"]],
["submersible", ["submersable"]],
["submergible", ["submergable"]],
["suggestible", ["suggestable"]],
["suppressible", ["suppressable"]],
["susceptible", ["susceptable"]],
["terrible", ["terrable"]],
["transfusible", ["transfusable"]],
["transmissible", ["transmissable"]],
["uncollectible", ["uncollectable"]],
["vendible", ["vendable"]],
["visible", ["visable"]]
]
return preferred_forms_check(text, preferences, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/checks/spelling/athletes.py 0000644 0000000 0000000 00000002624 00000000000 017764 0 ustar 00 """Misspellings.
---
layout: post
source: The Wall Street Journal
source_url: http://on.wsj.com/1rksm8k
title: misspellings
date: 2014-06-10 12:31:19
categories: writing
---
Points out misspellings.
"""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "spelling.athletes"
msg = "Misspelling of athlete's name. '{}' is the preferred form."
misspellings = [
["Dwyane Wade", ["Dwayne Wade"]],
["Miikka Kiprusoff", ["Mikka Kiprusoff"]],
["Mark Buehrle", ["Mark Buerhle"]],
["Skylar Diggins", ["Skyler Diggins"]],
["Agnieszka Radwanska", ["Agnieska Radwanska"]],
["J.J. Redick", ["J.J. Reddick"]],
["Manny Pacquiao", ["Manny Packquaio"]],
["Antawn Jamison", ["Antwan Jamison"]],
["Cal Ripken", ["Cal Ripkin"]],
["Jhonny Peralta", ["Johnny Peralta"]],
["Monta Ellis", ["Monte Ellis"]],
["Alex Rodriguez", ["Alex Rodriquez"]],
["Mark Teixeira", ["Mark Texeira"]],
["Brett Favre", ["Brett Farve"]],
["Torii Hunter", ["Tori Hunter"]],
["Stephen Curry", ["Stephon Curry"]],
["Mike Krzyzewski", ["Mike Kryzewski"]],
]
return preferred_forms_check(text, misspellings, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/checks/spelling/em_im_en_in.py 0000644 0000000 0000000 00000004240 00000000000 020405 0 ustar 00 """Em vs. im, en vs. in."""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""em- vs. en-, im- vs. in-."""
err = "spelling.em_im_en_in"
msg = "em-, im-, en-, and in-. '{}' is the preferred spelling."
preferences = [
["embalm", ["imbalm"]],
["embark", ["imbark"]],
["embed", ["imbed"]],
["embitter", ["imbitter"]],
["emblaze", ["imblaze"]],
["embody", ["imbody"]],
["embolden", ["imbolden"]],
["embosom", ["imbosom"]],
["embower", ["imbower"]],
["embrown", ["imbrown"]],
["empanel", ["impanel"]],
["empower", ["impower"]],
["encage", ["incage"]],
["encapsulate", ["incapsulate"]],
["encase", ["incase"]],
["enclasp", ["inclasp"]],
["encumber", ["incumber"]],
["encumbrance", ["incumbrance"]],
["endow", ["indow"]],
["endowment", ["indowment"]],
["endue", ["indue"]],
["enfold", ["infold"]],
["engraft", ["ingraft"]],
["engulf", ["ingulf"]],
["enlace", ["inlace"]],
["enmesh", ["inmesh"]],
["ensheathe", ["insheathe"]],
["enshrine", ["inshrine"]],
["ensnare", ["insnare"]],
["ensoul", ["insoul"]],
["ensphere", ["insphere"]],
["enthrall", ["inthrall"]],
["enthrone", ["inthrone"]],
["entitle", ["intitle"]],
["entomb", ["intomb"]],
["entreat", ["intreat"]],
["entrench", ["intrench"]],
["entrust", ["intrust"]],
["entwine", ["intwine"]],
["entwist", ["intwist"]],
["enwind", ["inwind"]],
["enwrap", ["inwrap"]],
["enwreathe", ["inwreathe"]],
["imbrue", ["embrue"]],
["impale", ["empale"]],
["impoverish", ["empoverish"]],
["inflame", ["enflame"]],
["ingrain", ["engrain"]],
["inure", ["enure"]],
]
return preferred_forms_check(text, preferences, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/checks/spelling/er_or.py 0000644 0000000 0000000 00000002723 00000000000 017261 0 ustar 00 """-er vs. -or."""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""-er vs. -or."""
err = "spelling.er_or"
msg = "-er vs. -or. '{}' is the preferred spelling."
preferences = [
["abductor", ["abducter"]],
["abettor", ["abbeter"]],
["acquirer", ["acquiror"]],
["adapter", ["adaptor"]],
["collector", ["collecter"]],
["conjurer", ["conjuror"]],
["corrupter", ["corruptor"]],
["digester", ["digestor"]],
["dispenser", ["dispensor"]],
["distributor", ["distributer"]],
["endorser", ["endorsor"]],
["eraser", ["erasor"]],
["idolater", ["idolator"]],
["impostor", ["imposter"]],
["infiltrator", ["infiltrater"]],
["investor", ["invester"]],
["manipulator", ["manipulater"]],
["mortgagor", ["mortgager"]],
["persecutor", ["persecuter"]],
["promoter", ["promotor"]],
["promoter", ["promotor"]],
["purveyor", ["purveyer"]],
["requester", ["requestor"]],
["reviser", ["revisor"]],
["surveyor", ["surveyer"]],
]
return preferred_forms_check(text, preferences, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/checks/spelling/in_un.py 0000644 0000000 0000000 00000000770 00000000000 017263 0 ustar 00 """in- vs. un-."""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""in- vs un-."""
err = "spelling.in_un"
msg = "in- vs. un-. '{}' is the preferred spelling."
preferences = [
["inadvisable", ["unadvisable"]],
["inalienable", ["unalienable"]],
["inexpressive", ["unexpressive"]],
["infeasible", ["unfeasible"]],
]
return preferred_forms_check(text, preferences, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/checks/spelling/misc.py 0000644 0000000 0000000 00000014262 00000000000 017107 0 ustar 00 """Misspellings.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: misspellings
date: 2014-06-10 12:31:19
categories: writing
---
Points out misspellings.
"""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "spelling.misc"
msg = "Misspelling. '{}' is the preferred spelling."
misspellings = [
["a lot", ["alot"]],
["academically", ["academicly"]],
["accidentally", ["accidently"]],
["accommodable", ["accomodatable"]],
["anilingus", ["analingus"]],
["aren't i", ["amn't i"]],
["aren't i", ["an't i"]],
["barbed wire", ["bob wire"]],
["chargeable", ["chargable"]],
["chiffonier", ["chiffonnier"]],
["chintzy", ["chinchy"]],
["chipotle", ["chipolte"]],
["chlorophyll", ["chlorophyl"]],
["chocolaty", ["chocolatey"]],
["chronicle", ["chronical"]],
["chronicles", ["chronicals"]],
["coleslaw", ["coldslaw"]],
["choosy", ["choosey"]],
["cummerbund", ["kummerbund"]],
["financeable", ["financable"]],
["fluorescent", ["flourescent"]],
["fluoridation", ["flouridation"]],
["fluoride", ["flouride"]],
["foreclose", ["forclose"]],
["forswear", ["foreswear"]],
["free rein", ["free reign"]],
["gist", ["jist"]],
["glamour", ["glamor"]],
["granddad", ["grandad"]],
["grandpa", ["granpa"]],
["highfalutin", ["highfaluting", "highfalutin'", "hifalutin"]],
["Hippocratic", ["hypocratic"]],
["hirable", ["hireable"]],
["holistic", ["wholistic"]],
["ideology", ["idealogy"]],
["idiosyncrasy", ["ideosyncracy"]],
["improvise", ["improvize"]],
["incurrence", ["incurment"]],
["inevitability", ["inevitableness"]],
["innovate", ["inovate"]],
["inoculation", ["innoculation", "inocculation"]],
["integral", ["intergral"]],
["inundate", ["innundate"]],
["inundated", ["innundated"]],
["inundates", ["innundates"]],
["inundating", ["innundating"]],
["iridescent", ["irridescent"]],
["irrelevant", ["irrevelant"]],
["jujitsu", ["jiujutsu"]],
["kaleidoscope", ["kaleidascope"]],
["knickknack", ["knicknack"]],
["lassos", ["lassoes"]],
["lessee", ["leasee"]],
["lessor", ["leasor"]],
["liaison", ["liason"]],
["liaison", ["laison"]],
["lightning rod", ["lightening rod"]],
["struck by lightning", ["struck by lightening"]],
["liquefy", ["liquify"]],
["loathsome", ["loathesome"]],
["lodestar", ["loadstar"]],
["to make do", ["to make due"]],
["mademoiselle", ["madamoiselle"]],
["martial arts", ["marshall arts"]],
["court-martial", ["court marshall", "court-marshall"]],
["maelstrom", ["maelstorm"]],
["mafia", ["maffia"]],
["mafiosi", ["mafiosos"]],
["mangoes", ["mangos"]],
["marijuana", ["marihuana"]],
["marshmallow", ["marshmellow"]],
["martial law", ["marshall law"]],
["massacring", ["massacering", "massacreing"]],
["measles", ["measels"]],
["memento", ["momento"]],
["minuscule", ["miniscule"]],
["mileage", ["milage"]],
["milieu", ["mileau"]],
["millennium", ["millenium"]],
["millennia", ["millenia"]],
["millenniums", ["milleniums"]],
["millipede", ["millepede"]],
["millionaire", ["millionnaire"]],
["milquetoast", ["milktoast"]],
["mimicked", ["mimiced"]],
["mimicking", ["mimicing"]],
["misspelling", ["mispelling"]],
["mischievous", ["mischievious"]],
["moccasin", ["mocasin", "moccassin", "mocassin"]],
["monologue", ["monolog"]],
["monologuist", ["monologist"]],
["naphtha", ["naptha"]],
["navel orange", ["naval orange"]],
["neckwear", ["neckware"]],
["newsstand", ["newstand"]],
["non sequitur", ["non sequiter",
"non sequitar",
"non sequitor"]],
["nouveau riche", ["nouveau rich"]],
["occurred", ["occured"]],
["plantar fasciitis", ["planter fasciitis", "plantar fascitis"]],
["pledgeable", ["pledgable", "pledgeble"]],
["portentous", ["portentuous", "portentious"]],
["praying mantis", ["preying mantis"]],
["preestablished", ["prestablished"]],
["preexisting", ["prexisting"]],
["presumptuous", ["presumptious"]],
["rarefy", ["rarify"]],
["reckless", ["wreckless"]],
["remuneration", ["renumeration"]],
["restaurateur", ["restauranteur"]],
["retractable", ["retractible"]],
["reverie", ["revery"]],
["spicy", ["spicey"]],
["stupefy", ["stupify"]],
["subtly", ["subtley"]],
["till", ["\'till?"]],
["tinderbox", ["tenderbox"]],
["timpani", ["tympani"]],
["a timpani", ["a timpano"]],
["umpteenth", ["umteenth"]],
["verbiage", ["verbage"]],
]
return preferred_forms_check(text, misspellings, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/checks/terms/__init__.py 0000644 0000000 0000000 00000000015 00000000000 017217 0 ustar 00 """Terms."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/checks/terms/animal_adjectives.py 0000644 0000000 0000000 00000004560 00000000000 021133 0 ustar 00 """Animal adjectives.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: animal words
date: 2014-06-10 12:31:19
categories: writing
---
Animal words.
"""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "garner.animal_labels"
msg = "There's a word for this: '{}'."
preferences = [
["accipitrine", ["hawk-like"]],
["anserine", ["goose-like"]],
["aquiline", ["eagle-like"]],
["avine", ["bird-like"]],
["cancrine", ["crab-like"]],
["hircine", ["goat-like"]],
["damine", ["deer-like"]],
["corvine", ["crow-like", "raven-like"]],
["crocodiline", ["crocodile-like"]],
["crotaline", ["rattlesnake-like"]],
["falconine", ["falcon-like"]],
["ferine", ["wild animal-like"]],
["hippopotamine", ["hippopotamus-like"]],
["hirundine", ["swallow-like"]],
["hystricine", ["porcupine-like"]],
["lacertine", ["lizard-like"]],
["laridine", ["gull-like"]],
["leporine", ["hare-like"]],
["lumbricine", ["earthworm-like"]],
["lupine", ["wolf-like"]],
["murine", ["mouse-like"]],
["ovine", ["sheep-like"]],
["pardine", ["leopard-like", "panther-like"]],
["passerine", ["sparrow-like"]],
["pavonine", ["peacock-like"]],
["picine", ["woodpecker-like"]],
["piscine", ["fish-like"]],
["ranine", ["frog-like"]],
["scolopendrine", ["centipede-like"]],
["soricine", ["shrew-like"]],
["struthionine", ["ostrich-like"]],
["suilline", ["swine-like"]],
["taurine", ["bull-like", "ox-like"]],
["tigrine", ["tiger-like"]],
["vespine", ["wasp-like"]],
["viperine", ["viper-like"]],
["vituline", ["calf-like", "veal-like"]],
["viverrine", ["mongoose-like"]],
["vulpine", ["fox-like"]],
["vulturine", ["vulture-like"]],
["zebrine", ["zebra-like"]],
["zibeline", ["sable-like"]],
]
return preferred_forms_check(text, preferences, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/checks/terms/denizen_labels.py 0000644 0000000 0000000 00000006351 00000000000 020447 0 ustar 00 """Denizen labels."""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""Suggest the preferred forms.
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
"""
err = "terms.denizen_labels.garner"
msg = "'{}' is the preferred denizen label."
preferences = [
["Afrikaner", ["Afrikaaner"]],
["Afrikaner", ["Afrikander"]],
["Alabamian", ["Alabaman"]],
["Albuquerquean", ["Albuquerquian"]],
["Anchorageite", ["Anchoragite"]],
["Angeleno", ["Los Angelean"]],
["Arizonan", ["Arizonian"]],
["Arkansan", ["Arkansawyer"]],
["Belarusian", ["Belarusan"]],
["Caymanian", ["Cayman Islander"]],
["Coloradan", ["Coloradoan"]],
["Fairbanksan", ["Fairbanksian"]],
["Fort Worthian", ["Fort Worther"]],
["Grenadan", ["Grenadian"]],
["Hong Konger", ["Hong Kongite", "Hong Kongian"]],
["Hoosier", ["Indianan", "Indianian"]],
["Illinoisan", ["Illinoisian"]],
["Iowan", ["Iowegian"]],
["Louisianian", ["Louisianan"]],
["Michigander", ["Michiganite", "Michiganian"]],
["Missourian", ["Missouran"]],
["Monegasque", ["Monacan"]],
["Neapolitan", ["Neopolitan"]],
["New Hampshirite", ["New Hampshireite", "New Hampshireman"]],
["New Jerseyan", ["New Jerseyite"]],
["New Orleanian", ["New Orleansian"]],
["Nutmegger", ["Connecticuter"]],
["Oklahoma Cityan", ["Oklahoma Citian"]],
["Oklahoman", ["Oklahomian"]],
["Seattleite", ["Seattlite"]],
["Surinamese", ["Surinamer"]],
["Tallahasseean", ["Tallahassean"]],
["Tennessean", ["Tennesseean"]],
["Tusconan", ["Tusconian", "Tusconite"]],
["Utahn", ["Utahan"]],
["Saudi", ["Saudi Arabian"]],
]
return preferred_forms_check(text, preferences, err, msg)
@memoize
def check_denizen_labels_norris(text):
"""Suggest the preferred forms.
source: Mary Norris
source_url: http://nyr.kr/1rGienj
"""
err = "terms.denizen_labels.norris"
msg = "Would you like '{}'?"
preferences = [
["Mancunian", ["Manchesterian"]],
["Mancunians", ["Manchesterians"]],
["Vallisoletano", ["Valladolidian"]],
["Wulfrunian", ["Wolverhamptonian", "Wolverhamptonite"]],
["Novocastrian", ["Newcastleite", "Newcastlite"]],
["Trifluvian", ["Trois-Rivièrester"]],
["Leodenisian", ["Leedsian"]],
["Minneapolitan", ["Minneapolisian"]],
["Hartlepudlian", ["Hartlepoolian"]],
["Liverpudlian", ["Liverpoolian"]],
["Haligonian", ["Halifaxer"]],
["Varsovian", ["Warsawer", "Warsawian"]],
["Providentian", ["Providencian", "Providencer"]],
["Tridentine", ["Trentian", "Trentonian"]],
]
return preferred_forms_check(text, preferences, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/checks/terms/eponymous_adjectives.py 0000644 0000000 0000000 00000001220 00000000000 021716 0 ustar 00 """Eponymous adjectives.
---
layout: post
source: Garner's Modern American Usage
source_url: http://bit.ly/1T4alrY
title: Eponymous adjectives
date: 2014-06-10 12:31:19
categories: writing
---
Eponymous adjectives.
"""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "garner.eponymous_adjective"
msg = "'{}' is the preferred eponymous adjective."
preferences = [
["Mephistophelean", ["Mephistophelian"]],
["Shakespearean", ["Shakespearian"]],
]
return preferred_forms_check(text, preferences, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/checks/terms/venery.py 0000644 0000000 0000000 00000005037 00000000000 017001 0 ustar 00 """Names for groups of animals.
---
layout: post
source: Oxford Dictionaries
source_url: http://www.oxforddictionaries.com/words/what-do-you-call-a-group-of
title: Names for groups of animals
date: 2014-06-10 12:31:19
categories: writing
---
Names for groups of animals.
"""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""Check the text."""
err = "oxford.venery_terms"
msg = "The venery term is '{}'."
term_list = [
["alligators", "congregation"],
["antelopes", "herd"],
["baboons", "troop"],
["badgers", "cete"],
["bats", "colony"],
["bears", "sloth"],
["buffalo", "herd"],
["bullfinches", "bellowing"],
["caribou", "herd"],
["cats", "glaring"],
["caterpillars", "army"],
["cockroaches", "intrusion"],
["coyotes", "pack"],
["crows", "murder"],
["dogs", "pack"],
["eagles", "convocation"],
["emus", "mob"],
["flamingos", "stand"],
["frogs", "army"],
["goldfinches", "charm"],
["gorillas", "band"],
["guineafowl", "rasp"],
["hedgehogs", "array"],
["herons", "siege"],
["hogs", "parcel"],
["hyenas", "cackle"],
["ibex", "herd"],
["iguanas", "mess"],
["lions", "pride"],
["locusts", "plague"],
["mackerel", "shoal"],
["mares", "stud"],
["minnows", "shoal"],
["moose", "herd"],
["mosquitoes", "scourge"],
["nightingales", "watch"],
["oysters", "bed"],
["partridges", "covey"],
["pelicans", "pod"],
["raccoons", "gaze"],
["ravens", "unkindness"],
["rhinoceroses", "crash"],
["sea urchins", "sea"],
["starlings", "murmuration"],
["toads", "knot"],
["wombats", "wisdom"],
["woodcocks", "fall"],
["woodpeckers", "descent"],
["wrens", "herd"],
]
generic_terms = [
"group",
"bunch",
]
list = []
for term_pair in term_list:
for generic in generic_terms:
wrong = f"a {generic} of {term_pair[0]}"
right = f"a {term_pair[1]} of {term_pair[0]}"
list += [[right, [wrong]]]
return preferred_forms_check(text, list, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/checks/typography/__init__.py 0000644 0000000 0000000 00000000034 00000000000 020274 0 ustar 00 """Advice on typography."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/checks/typography/diacritical_marks.py 0000644 0000000 0000000 00000011005 00000000000 022202 0 ustar 00 """Diacritical marks.
Use of diacritical marks where common.
"""
from proselint.tools import memoize, preferred_forms_check
@memoize
def check(text):
"""Suggest the preferred forms."""
err = "typography.diacritical_marks"
msg = "Use diacritical marks in '{}'."
list = [
# French loanwords
["beau idéal", ["beau ideal"]],
["boutonnière", ["boutonniere"]],
["bric-à-brac", ["bric-a-brac"]],
["café", ["cafe"]],
["cause célèbre", ["cause celebre"]],
["chèvre", ["chevre"]],
["cliché", ["cliche"]],
["comme ci comme ça", ["comme ci comme ca", "comsi comsa"]],
["consommé", ["consomme"]],
["coup d'état", ["coup d'etat"]],
["coup de grâce", ["coup de grace"]],
["crudités", ["crudites"]],
["crème brûlée", ["creme brulee"]],
["crème de menthe", ["creme de menthe"]],
["crème fraîche", ["creme fraice"]],
["crème fraîche", ["creme fresh"]],
["crêpe", ["crepe"]],
["débutante", ["debutante"]],
["décor", ["decor"]],
["déjà vu", ["deja vu"]],
["dénouement", ["denouement"]],
["façade", ["facade"]],
["fiancé", ["fiance"]],
["fiancée", ["fiancee"]],
["flambé", ["flambe"]],
["garçon", ["garcon"]],
["lycée", ["lycee"]],
["maître d", ["maitre d"]],
["ménage à trois", ["menage a trois"]],
["négligée", ["negligee"]],
["papier-mâché", ["papier-mache", "paper mache", "paper-mache"]],
["protégé", ["protege"]],
["protégée", ["protegee"]],
["purée", ["puree"]],
["raison d'être", ["raison d'etre"]],
["my résumé", ["my resume"]],
["your résumé", ["your resume"]],
["his résumé", ["his resume"]],
["her résumé", ["her resume"]],
["a résumé", ["a resume"]],
["the résumé", ["the resume"]],
["risqué", ["risque"]],
["roué", ["roue"]],
["soirée", ["soiree"]],
["soufflé", ["souffle"]],
["soupçon", ["soupcon"]],
["touché", ["touche"]],
["tête-à-tête", ["tete-a-tete"]],
["voilà", ["voila"]],
["à la carte", ["a la carte"]],
["à la mode", ["a la mode"]],
["émigré", ["emigre"]],
# Spanish loanwords
["El Niño", ["El Nino"]],
["jalapeño", ["jalapeno"]],
["La Niña", ["La Nina"]],
["piña colada", ["pina colada"]],
["señor", ["senor"]],
["señora", ["senora"]],
["señorita", ["senorita"]],
# Portuguese loanwords
["açaí", ["acai"]],
# German loanwords
["doppelgänger", ["doppelganger"]],
["Führer", ["Fuhrer"]],
["Gewürztraminer", ["Gewurztraminer"]],
["vis-à-vis", ["vis-a-vis"]],
["Übermensch", ["Ubermensch"]],
# Swedish loanwords
["filmjölk", ["filmjolk"]],
["smörgåsbord", ["smorgasbord"]],
# Names, places, and companies
["Beyoncé", ["Beyonce"]],
["Brontë", ["Bronte"]],
["Brontë", ["Bronte"]],
["Champs-Élysées", ["Champs-Elysees"]],
["Citroën", ["Citroen"]],
["Curaçao", ["Curacao"]],
["Häagen-Dazs", ["Haagen-Dazs", "Haagen Dazs"]],
["Löwenbräu", ["Lowenbrau"]],
["Monégasque", ["Monegasque"]],
["Mötley Crüe", ["Motley Crue"]],
["Nescafé", ["Nescafe"]],
["Queensrÿche", ["Queensryche"]],
["Québec", ["Quebec"]],
["Québécois", ["Quebecois"]],
["Ångström", ["Angstrom"]],
["ångström", ["angstrom"]],
["Škoda", ["Skoda"]],
]
return preferred_forms_check(text, list, err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/checks/typography/exclamation.py 0000644 0000000 0000000 00000001670 00000000000 021050 0 ustar 00 """Too much yelling.
---
layout: post
source: ???
source_url: ???
title: yelling
date: 2014-06-10 12:31:19
categories: writing
---
Too much yelling.
"""
from proselint.tools import existence_check, max_errors, memoize, ppm_threshold
@max_errors(1)
@memoize
def check_repeated_exclamations(text):
"""Check the text."""
err = "leonard.exclamation.multiple"
msg = "Stop yelling. Keep your exclamation points under control."
regex = r"[\!]\s*?[\!]{1,}"
return existence_check(text, [regex], err, msg, require_padding=False,
ignore_case=False, dotall=True)
@ppm_threshold(30)
@memoize
def check_exclamations_ppm(text):
"""Make sure that the exclamation ppm is under 30."""
err = "leonard.exclamation.30ppm"
msg = "More than 30 ppm of exclamations. Keep them under control."
regex = r"\w!"
return existence_check(text, [regex], err, msg, require_padding=False)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/checks/typography/symbols.py 0000644 0000000 0000000 00000005265 00000000000 020240 0 ustar 00 """Use the right symbols.
source: Butterick's Practical Typography
source_url: http://practicaltypography.com/
"""
from proselint.tools import existence_check, max_errors, memoize
@max_errors(3)
@memoize
def check_ellipsis(text):
"""Use an ellipsis instead of three dots."""
err = "typography.symbols.ellipsis"
msg = "'...' is an approximation, use the ellipsis symbol '…'."
regex = r"\.\.\."
return existence_check(text, [regex], err, msg, require_padding=False,
offset=0)
@max_errors(1)
@memoize
def check_copyright_symbol(text):
"""Use the copyright symbol instead of (c)."""
err = "typography.symbols.copyright"
msg = "(c) is a goofy alphabetic approximation, use the symbol ©."
regex = r"\([cC]\)"
return existence_check(text, [regex], err, msg, require_padding=False)
@max_errors(3)
@memoize
def check_trademark_symbol(text):
"""Use the trademark symbol instead of (TM)."""
err = "typography.symbols.trademark"
msg = "(TM) is a goofy alphabetic approximation, use the symbol ™."
regex = r"\(TM\)"
return existence_check(text, [regex], err, msg, require_padding=False)
@max_errors(3)
@memoize
def check_registered_trademark_symbol(text):
"""Use the registered trademark symbol instead of (R)."""
err = "typography.symbols.trademark"
msg = "(R) is a goofy alphabetic approximation, use the symbol ®."
regex = r"\([rR]\)"
return existence_check(text, [regex], err, msg, require_padding=False)
@max_errors(3)
@memoize
def check_sentence_spacing(text):
"""Use no more than two spaces after a period."""
err = "typography.symbols.sentence_spacing"
msg = "More than two spaces after the period; use 1 or 2."
regex = r"\. {3}"
return existence_check(text, [regex], err, msg, require_padding=False)
@max_errors(3)
@memoize
def check_multiplication_symbol(text):
"""Use the multiplication symbol ×, not the lowercase letter x."""
err = "typography.symbols.multiplication_symbol"
msg = "Use the multiplication symbol ×, not the letter x."
regex = r"[0-9]+ ?x ?[0-9]+"
return existence_check(text, [regex], err, msg, require_padding=False)
@max_errors(3)
@memoize
def check_curly_quotes(text):
"""Use curly quotes, not straight quotes."""
err = "typography.symbols.curly_quotes"
msg = 'Use curly quotes “”, not straight quotes "".'
regex = r"\"[\w\s\d]+\""
return existence_check(text, [regex], err, msg, require_padding=False)
# @memoize
# def check_en_dash_separated_names(text):
# """Use an en-dash to separate names."""
# # [u"[A-Z][a-z]{1,10}[-\u2014][A-Z][a-z]{1,10}",
# # u"Use an en dash (–) to separate names."],
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/checks/uncomparables/__init__.py 0000644 0000000 0000000 00000000041 00000000000 020717 0 ustar 00 """Comparing an uncomparable."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/checks/uncomparables/misc.py 0000644 0000000 0000000 00000010062 00000000000 020117 0 ustar 00 """Comparing uncomparables.
---
layout: post
source: David Foster Wallace
source_url: http://www.telegraph.co.uk/a/9715551
title: Comparing an uncomparable
date: 2014-06-10 12:31:19
categories: writing
---
David Foster Wallace says:
> This is one of a class of adjectives, sometimes called “uncomparables”, that
can be a little tricky. Among other uncomparables are precise, exact, correct,
entire, accurate, preferable, inevitable, possible, false; there are probably
two dozen in all. These adjectives all describe absolute, non-negotiable
states: something is either false or it’s not; something is either inevitable
or it’s not. Many writers get careless and try to modify uncomparables with
comparatives like more and less or intensives like very. But if you really
think about them, the core assertions in sentences like “War is becoming
increasingly inevitable as Middle East tensions rise”; “Their cost estimate was
more accurate than the other firms’”; and “As a mortician, he has a very unique
attitude” are nonsense. If something is inevitable, it is bound to happen; it
cannot be bound to happen and then somehow even more bound to happen. Unique
already means one-of-a-kind, so the adj. phrase very unique is at best
redundant and at worst stupid, like “audible to the ear” or “rectangular in
shape”. You can blame the culture of marketing for some of this difficulty.
As the number and rhetorical volume of US ads increase, we become inured to
hyperbolic language, which then forces marketers to load superlatives and
uncomparables with high-octane modifiers (special - very special -
Super-special! - Mega-Special!!), and so on. A deeper issue implicit in the
problem of uncomparables is the dissimilarities between Standard Written
English and the language of advertising. Advertising English, which probably
deserves to be studied as its own dialect, operates under different syntactic
rules than SWE, mainly because AE’s goals and assumptions are different.
Sentences like “We offer a totally unique dining experience”; “Come on down and
receive your free gift”; and “Save up to 50 per cent… and more!” are perfectly
OK in Advertising English — but this is because Advertising English is aimed at
people who are not paying close attention. If your audience is by definition
involuntary, distracted and numbed, then free gift and totally unique stand a
better chance of penetrating — and simple penetration is what AE is all about.
One axiom of Standard Written English is that your reader is paying close
attention and expects you to have done the same.
"""
import itertools
from proselint.tools import existence_check, memoize
@memoize
def check(text):
"""Check the text."""
err = "uncomparables.misc"
msg = "Comparison of an uncomparable: '{}' is not comparable."
comparators = [
"most",
"more",
"less",
"least",
"very",
"quite",
"largely",
"extremely",
"increasingly",
"kind of",
"mildly"
]
uncomparables = [
"absolute",
"adequate",
"chief",
"complete",
"correct",
"devoid",
"entire",
"false",
"fatal",
"favorite",
"final",
"ideal",
"impossible",
"inevitable",
"infinite",
"irrevocable",
"main",
"manifest",
"only",
"paramount",
"perfect",
"perpetual",
"possible",
"preferable",
"principal",
"singular",
"stationary",
"sufficient",
"true",
"unanimous",
"unavoidable",
"unbroken",
"uniform",
"unique",
"universal",
"void",
"whole",
]
exceptions = [
("more", "perfect"),
("more", "possible") # FIXME
]
uncomparables = [fr"{i[0]}\s{i[1]}" for i in itertools.product(
comparators, uncomparables) if i not in exceptions]
return existence_check(text, uncomparables, err, msg, require_padding=True)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/checks/weasel_words/__init__.py 0000644 0000000 0000000 00000000024 00000000000 020563 0 ustar 00 """Weasel words."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/checks/weasel_words/misc.py 0000644 0000000 0000000 00000000633 00000000000 017765 0 ustar 00 """Weasel words.
---
layout: post
source: write-good
source_url: https://github.com/btford/write-good
title: Weasel words.
date: 2014-06-10 12:31:19
categories: writing
---
Weasel words clearly weaken various aspects of a number of your sentences.
"""
# def check(text):
# error_code = "weasel_words.misc"
# msg = "Weasel words present."
# return [(1, 1, error_code, msg)]
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/checks/weasel_words/very.py 0000644 0000000 0000000 00000001322 00000000000 020013 0 ustar 00 """Very.
---
layout: post
source: William Allen White
source_url: http://bit.ly/1XaMllw
title: very
date: 2014-06-10 12:31:19
categories: writing
---
Substitute 'damn' every time you're inclined to write 'very'; your editor will
delete it and the writing will be just as it should be.
"""
from proselint.tools import existence_check, max_errors, memoize
@max_errors(1)
@memoize
def check(text):
"""Avoid 'very'."""
err = "weasel_words.very"
msg = ("Substitute 'damn' every time you're "
"inclined to write 'very'; your editor will delete it "
"and the writing will be just as it should be.")
regex = "very"
return existence_check(text, [regex], err, msg)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/command_line.py 0000644 0000000 0000000 00000013156 00000000000 015525 0 ustar 00 """Command line utility for proselint."""
import json
import os
import shutil
import subprocess
import sys
import traceback
import click
from .config import default
from .tools import (close_cache_shelves, close_cache_shelves_after,
errors_to_json, lint, load_options)
from .version import __version__
CONTEXT_SETTINGS = {"help_option_names": ['-h', '--help']}
base_url = "proselint.com/"
proselint_path = os.path.dirname(os.path.realpath(__file__))
demo_file = os.path.join(proselint_path, "demo.md")
# TODO: fix broken corpus
def timing_test(corpus="0.1.0"):
"""Measure timing performance on the named corpus."""
import time
dirname = os.path.dirname
corpus_path = os.path.join(
dirname(dirname(os.path.realpath(__file__))), "corpora", corpus)
start = time.time()
for file in os.listdir(corpus_path):
filepath = os.path.join(corpus_path, file)
if ".md" == filepath[-3:]:
subprocess.call(["proselint", filepath, ">/dev/null"])
return time.time() - start
def clear_cache():
"""Delete the contents of the cache."""
click.echo("Deleting the cache...")
# see issue #624
_delete_compiled_python_files()
_delete_cache()
def _delete_compiled_python_files():
"""Remove files with a 'pyc' extension."""
for path, _, files in os.walk(os.getcwd()):
for fname in [f for f in files if os.path.splitext(f)[1] == ".pyc"]:
try:
os.remove(os.path.join(path, fname))
except OSError:
pass
def _delete_cache():
"""Remove the proselint cache."""
proselint_cache = os.path.join("proselint", "cache")
try:
shutil.rmtree(proselint_cache)
except OSError:
pass
def print_errors(filename, errors, output_json=False, compact=False):
"""Print the errors, resulting from lint, for filename."""
if output_json:
click.echo(errors_to_json(errors))
else:
for error in errors:
(check, message, line, column, start, end,
extent, severity, replacements) = error
if compact:
filename = "-"
click.echo(
filename + ":" +
str(1 + line) + ":" +
str(1 + column) + ": " +
check + " " +
message)
@click.command(context_settings=CONTEXT_SETTINGS)
@click.version_option(__version__, '--version', '-v', message='%(version)s')
@click.option('--config', is_flag=False, type=click.Path(),
help="Path to configuration file.")
@click.option('--debug', '-d', is_flag=True, help="Give verbose output.")
@click.option('--clean', '-c', is_flag=True, help="Clear the cache.")
@click.option('--json', '-j', 'output_json', is_flag=True,
help="Output as JSON.")
@click.option('--time', '-t', is_flag=True, help="Time on a corpus.")
@click.option('--demo', is_flag=True, help="Run over demo file.")
@click.option('--compact', is_flag=True, help="Shorten output.")
@click.option('--dump-config', is_flag=True, help="Prints current config.")
@click.option('--dump-default-config', is_flag=True,
help="Prints default config.")
@click.argument('paths', nargs=-1, type=click.Path())
@close_cache_shelves_after
def proselint(paths=None, config=None, version=None, clean=None,
debug=None, output_json=None, time=None, demo=None, compact=None,
dump_config=None, dump_default_config=None):
"""Create the CLI for proselint, a linter for prose."""
if dump_default_config:
return print(json.dumps(default, sort_keys=True, indent=4))
config = load_options(config, default)
if dump_config:
print(json.dumps(config, sort_keys=True, indent=4))
return
if time:
# click.echo(timing_test())
print("This option does not work for the time being.")
return
# In debug or clean mode, delete cache & *.pyc files before running.
if debug or clean:
clear_cache()
# Use the demo file by default.
if demo:
paths = [demo_file]
# Expand the list of directories and files.
filepaths = extract_files(list(paths))
# Lint the files
num_errors = 0
# Use stdin if no paths were specified
if len(paths) == 0:
filepaths.append('-')
for fp in filepaths:
if fp == '-':
fp = ''
f = sys.stdin
else:
try:
f = click.open_file(fp, 'r', "utf-8", "replace")
except Exception:
traceback.print_exc()
sys.exit(2)
errors = lint(f, debug, config)
num_errors += len(errors)
print_errors(fp, errors, output_json, compact)
# Return an exit code
close_cache_shelves()
if num_errors > 0:
sys.exit(1)
else:
sys.exit(0)
def extract_files(files):
"""Expand list of paths to include all text files matching the pattern."""
expanded_files = []
legal_extensions = [".md", ".txt", ".rtf", ".html", ".tex", ".markdown"]
for f in files:
# If it's a directory, recursively walk through it and find the files.
if os.path.isdir(f):
for dir_, _, filenames in os.walk(f):
for filename in filenames:
fn, file_extension = os.path.splitext(filename)
if file_extension in legal_extensions:
joined_file = os.path.join(dir_, filename)
expanded_files.append(joined_file)
# Otherwise add the file directly.
else:
expanded_files.append(f)
return expanded_files
if __name__ == '__main__':
proselint()
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/config.py 0000644 0000000 0000000 00000005507 00000000000 014346 0 ustar 00 """Proselint config - replacement for default .proselintrc since #1212."""
default = {
"max_errors": 1000,
"checks": {
"airlinese.misc": True,
"annotations.misc": True,
"archaism.misc": True,
"cliches.hell": True,
"cliches.misc": True,
"consistency.spacing": True,
"consistency.spelling": True,
"corporate_speak.misc": True,
"cursing.filth": True,
"cursing.nfl": False,
"cursing.nword": True,
"dates_times.am_pm": True,
"dates_times.dates": True,
"hedging.misc": True,
"hyperbole.misc": True,
"jargon.misc": True,
"lexical_illusions.misc": True,
"lgbtq.offensive_terms": True,
"lgbtq.terms": True,
"links.broken": False,
"malapropisms.misc": True,
"misc.apologizing": True,
"misc.back_formations": True,
"misc.bureaucratese": True,
"misc.but": True,
"misc.capitalization": True,
"misc.chatspeak": True,
"misc.commercialese": True,
"misc.composition": True,
"misc.currency": True,
"misc.debased": True,
"misc.false_plurals": True,
"misc.illogic": True,
"misc.inferior_superior": True,
"misc.institution_name": True,
"misc.latin": True,
"misc.many_a": True,
"misc.metaconcepts": True,
"misc.metadiscourse": True,
"misc.narcissism": True,
"misc.not_guilty": True,
"misc.phrasal_adjectives": True,
"misc.preferred_forms": True,
"misc.pretension": True,
"misc.professions": True,
"misc.punctuation": True,
"misc.scare_quotes": True,
"misc.suddenly": True,
"misc.tense_present": True,
"misc.waxed": True,
"misc.whence": True,
"mixed_metaphors.misc": True,
"mondegreens.misc": True,
"needless_variants.misc": True,
"nonwords.misc": True,
"oxymorons.misc": True,
"psychology.misc": True,
"redundancy.misc": True,
"redundancy.ras_syndrome": True,
"skunked_terms.misc": True,
"spelling.able_atable": True,
"spelling.able_ible": True,
"spelling.athletes": True,
"spelling.em_im_en_in": True,
"spelling.er_or": True,
"spelling.in_un": True,
"spelling.misc": True,
"security.credit_card": True,
"security.password": True,
"sexism.misc": True,
"terms.animal_adjectives": True,
"terms.denizen_labels": True,
"terms.eponymous_adjectives": True,
"terms.venery": True,
"typography.diacritical_marks": True,
"typography.exclamation": True,
"typography.symbols": True,
"uncomparables.misc": True,
"weasel_words.misc": True,
"weasel_words.very": True
}
}
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/demo.md 0000644 0000000 0000000 00000013717 00000000000 013777 0 ustar 00 # Proselint
Writing is notoriously hard, even for the best writers. Yet there is a tremendous amount of knowledge about the discipline strewn across usage guides, dictionaries, technical manuals, essays, pamphlets, websites, and the hearts and minds of great authors and editors. But poring over Strunk & White hardly makes one a better writer — it turns you into neither Strunk nor White. And nobody has the capacity to apply all the advice from Garner’s Modern American Usage, a 975-page usage guide, to everything they write. In fact, the whole notion that one becomes a better writer by reading advice on writing rests on untenable assumptions about learning and memory. The traditional formats of knowledge about writing are thus essentially inert, waiting to be transformed.
We devised a simple solution: proselint, a linter for prose. (A linter is a computer program that, like a spell checker, scans through a document and analyzes it.)
Proselint places the world's greatest writers and editors by your side, where they whisper suggestions on how to improve your prose. You'll be guided by advice inspired by Bryan Garner, David Foster Wallace, Chuck Palahniuk, Steve Pinker, Mary Norris, Mark Twain, Elmore Leonard, George Orwell, Matthew Butterick, William Strunk, E.B. White, Philip Corbett, Ernest Gowers, and the editorial staff of the world's finest literary magazines and newspapers, among others. Our goal is to aggregate knowledge about best practices in writing and to make that knowledge immediately accessible to all authors in the form of a linter for prose.
This is a live demo. Obviously, you can hover over the underlined text to see what the issue is, then fix it.
# Dates & times
The 1950's were a swell time.
The 50's were a swell time.
Things happened from 1980-1999 and from 240-398 A.D.
March, 2013 was notable in that
In February of 2010, the mayor considered
It's 5 pm somewhere.
It's 12 a.m., time to eat lunch.
It's 11 p.m. at night.
# Consistency
This is a sentence! One space after a period.
This is a sentence. Two spaces after a period.
This is a sentence? Two spaces after a period.
This is a sentence. One space after a period.
This is a sentence. One space after a period.
This is a sentence. One space after a period.
This is a sentence. One space after a period.
centre centre center
organize, organized, organizing, organise
recognize, recognise, recognise, recognise
# Symbols
$1000 USD
I hit him over the head with a 2 x 4.
# Venery terms
A bunch of antelopes walked by the road.
A group of emus attacked me.
She swam by a bunch of oysters.
# Mondegreens
They hae slain the Earl o' Moray and Lady Mondegreen.
A girl with colitis goes by.
# Skunked terms
The building is deceptively large.
The project would decimate the fragile wetland wilderness.
Hopefully, one day we will all grow older.
# Links
www.google.com
http://broken.proselint.com
http://news.ycombinator.com
# Hyperbolic language
and so I said PLEASE STOP YELLING
so excited!
so excited!!
so excited!!!
so excited!!!!
really??
and so I said PLEASE STOP YELLING
and so I said PLEASE STOP YELLING okay?
THESE ARE SMALL CAPS at the beginning of a new line.
# Preferred forms
abbreviatable to NASA
academicly superior.
transhipped
an aider and abbeter
it's adducable
let's look for an acquiror
i wonder what tort-feasor means
Get that off of me before I catch on fire!
There are many a person I have met and worked with who simply deride themselves into taking some action
In the meanwhile, he looked loving at the sheep.
Suddenly, I see.
# Mixed metaphors
Get ready: button your seatbelts.
The cream rises to the crop.
The biggest bottleneck is that...
# Illogic and redundancy
he is very smart
approximately about 5 atm machines
atm machine
we associate together
it's blatantly obvious that this obviously works.
a very unique idea
a more perfect union
the surrounding circumstances
he filled a much-needed gap
To coin a phrase from the movie,
# Blowing the punchline
Suddenly, the car came to a stop.
All hell broke loose on the farm.
# Clichés
under the weather
He's a chip off the old block
a quantum leap
Our cutting edge decision-making process will make your life crystal clear.
He's a thought leader.
# Security
John's cc#:
378282246310005
the password is tnoernturpn
my password is long and 'long'
my password is amazing
# Commercialese
inst.
please be advised that
# Archaism
boughten
# Dismissive tone
this obviously works
# Chatspeak
brb
rofl
# Ogilvy's pretension
We'll need to reconceptualize this sentence.
# Airlinese
enplanement
We'll be taking off momentarily.
# Tense present
Save up to 50% or More!
between you and i
I did it on accident
I feel nauseous
# Phrasal adjectives
It was a highly-anticipated event.
The English speaking people speak English.
A big ticket item.
A right wing militia.
# Various misspellings
highfaluting
the statement was inadmissable in court
Nikita Khruschev
I feel innundated with email
Nicknack
He's a shoe-in
Brett Farve and Dwayne Wade are good friends.
The Chronicals of Narnia
# Strunk & White composition & regex checks
I did not pay for the check. Honestly, attention to detail is useful.
I did not pay attention to detail.
I did not pay any attention to detail.
# Typography
(c) 2015
(R) The Corporation
Use ellipsis not three dots...
# Denizen labels
The Manchesterian was a good Brit.
One from Michigan is not a Michiganite but a Michigander.
One from Colorado is not a Coloradoan but a Coloradan.
# Sexism
The lady lawyer handled my case.
John and Mary married. Now they are man and wife.
Chairman Mao was the chairman of the communist party.
# Punctuation
Smith, et. al (2006) said
# Quoted text
John said that I am "very unique."
John knows that I am very unique.
John knows every unique snowflake is cold.
# Metadiscourse
The preceeding discussion
# Narcisism, metadiscourse, latin, and hedging
The 'take-home message' is that
more research is needed
The rest of this article argues that, to a certain degree
in recent years, an increasing number of psychologists have
mutatis mutandis
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/score.py 0000644 0000000 0000000 00000004726 00000000000 014216 0 ustar 00 """Compute the lintscore on the corpus."""
import os
import re
import subprocess
proselint_path = os.path.dirname(os.path.realpath(__file__))
def score(check=None):
"""Compute the linter's score on the corpus.
Proselint's score reflects the desire to have a linter that catches many
errors, but which takes false alarms seriously. It is better not to say
something than to say the wrong thing, and the harm from saying the wrong
thing is greater than the benefit of saying the right thing. Thus our score
metric is defined as:
TP * (TP / (FP + TP)) ^ k,
where TP is the number of true positives (hits), FP is the number of
false positives (false alarms), and k > 0 is a temperature parameter that
determines the penalty for imprecision. In general, we should choose a
large value of k, one that strongly discourages the creation of rules that
can't be trusted. Suppose that k = 2. Then if the linter detects 100
errors, of which 10 are false positives, the score is 81.
"""
tp = 0
fp = 0
parent_directory = os.path.dirname(proselint_path)
path_to_corpus = os.path.join(parent_directory, "corpora", "0.1.0")
for root, _, files in os.walk(path_to_corpus):
files = [f for f in files if f.endswith(".md")]
for f in files:
fullpath = os.path.join(root, f)
# Run the linter.
print(f"Linting {f}")
out = subprocess.check_output(["proselint", fullpath])
# Determine the number of errors.
regex = r".+?:(?P\d+):(?P\d+): (?P.+)"
num_errors = len(tuple(re.finditer(regex, out)))
print(f"Found {num_errors} errors.")
# Open the document.
subprocess.call(["open", fullpath])
# Ask the scorer how many of the errors were false alarms?
input_val = None
while not isinstance(input_val, int):
try:
input_val = input("# of false alarms? ")
if input_val == "exit":
return
else:
input_val = int(input_val)
fp += input_val
tp += (num_errors - input_val)
except ValueError:
pass
print(f"Currently {tp} hits and {fp} false alarms\n---")
if (tp + fp) > 0:
return tp * (1.0 * tp / (tp + fp)) ** 2
else:
return 0
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/tools.py 0000644 0000000 0000000 00000033540 00000000000 014237 0 ustar 00 """General-purpose tools shared across linting checks."""
import copy
import dbm
import functools
import hashlib
import importlib
import inspect
import json
import os
import re
import shelve
import sys
import traceback
from warnings import showwarning as warn
_cache_shelves = dict()
proselint_path = os.path.dirname(os.path.realpath(__file__))
home_dir = os.path.expanduser("~")
cwd = os.getcwd()
def close_cache_shelves():
"""Close previously opened cache shelves."""
for cache in _cache_shelves.values():
cache.close()
_cache_shelves.clear()
def close_cache_shelves_after(f):
"""Decorate a function to ensure cache shelves are closed after call."""
@functools.wraps(f)
def wrapped(*args, **kwargs):
f(*args, **kwargs)
close_cache_shelves()
return wrapped
def _get_xdg_path(variable_name, default_path):
path = os.environ.get(variable_name)
if path is None or path == '':
return default_path
else:
return path
def _get_xdg_config_home():
return _get_xdg_path('XDG_CONFIG_HOME', os.path.join(home_dir, '.config'))
def _get_xdg_cache_home():
return _get_xdg_path('XDG_CACHE_HOME', os.path.join(home_dir, '.cache'))
def _get_cache(cachepath):
if cachepath in _cache_shelves:
return _cache_shelves[cachepath]
try:
cache = shelve.open(cachepath, protocol=2)
except dbm.error:
# dbm error on open - delete and retry
print('Error (%s) opening %s - will attempt to delete and re-open.' %
(sys.exc_info()[1], cachepath))
try:
os.remove(cachepath)
cache = shelve.open(cachepath, protocol=2)
except Exception:
print('Error on re-open: %s' % sys.exc_info()[1])
cache = None
except Exception:
# unknown error
print('Could not open cache file %s, maybe name collision. '
'Error: %s' % (cachepath, traceback.format_exc()))
cache = None
# Don't fail on bad caches
if cache is None:
print('Using in-memory shelf for cache file %s' % cachepath)
cache = shelve.Shelf(dict())
_cache_shelves[cachepath] = cache
return cache
def memoize(f):
"""Cache results of computations on disk."""
# Determine the location of the cache.
cache_dirname = os.path.join(_get_xdg_cache_home(), 'proselint')
legacy_cache_dirname = os.path.join(home_dir, ".proselint")
if not os.path.isdir(cache_dirname):
# Migrate the cache from the legacy path to XDG compliant location.
if os.path.isdir(legacy_cache_dirname):
os.rename(legacy_cache_dirname, cache_dirname)
# Create the cache if it does not already exist.
else:
os.makedirs(cache_dirname)
cache_filename = f.__module__ + "." + f.__name__
cachepath = os.path.join(cache_dirname, cache_filename)
@functools.wraps(f)
def wrapped(*args, **kwargs):
# handle instance methods
if hasattr(f, '__self__'):
args = args[1:]
signature = cache_filename.encode("utf-8")
tempargdict = inspect.getcallargs(f, *args, **kwargs)
for item in list(tempargdict.items()):
if item[0] == "text":
signature += item[1].encode("utf-8")
key = hashlib.sha256(signature).hexdigest()
cache = _get_cache(cachepath)
try:
return cache[key]
except KeyError:
value = f(*args, **kwargs)
cache[key] = value
cache.sync()
return value
except TypeError:
call_to = f.__module__ + '.' + f.__name__
print('Warning: could not disk cache call to %s;'
'it probably has unhashable args. Error: %s' %
(call_to, traceback.format_exc()))
return f(*args, **kwargs)
return wrapped
def get_checks(options):
"""Extract the checks."""
sys.path.append(proselint_path)
checks = []
check_names = [key for (key, val) in options["checks"].items() if val]
for check_name in check_names:
module = importlib.import_module("checks." + check_name)
for d in dir(module):
if re.match("check", d):
checks.append(getattr(module, d))
return checks
def deepmerge_dicts(dict1, dict2):
"""Deep merge dictionaries, second dict will take priority."""
result = copy.deepcopy(dict1)
for key, value in dict2.items():
if isinstance(value, dict):
result[key] = deepmerge_dicts(result[key] or {}, value)
else:
result[key] = value
return result
def load_options(config_file_path=None, conf_default=None):
"""Read various proselintrc files, allowing user overrides."""
conf_default = conf_default or {}
if os.path.isfile("/etc/proselintrc"):
conf_default = json.load(open("/etc/proselintrc"))
user_config_paths = [
os.path.join(cwd, '.proselintrc.json'),
os.path.join(_get_xdg_config_home(), 'proselint', 'config.json'),
os.path.join(home_dir, '.proselintrc.json')
]
if config_file_path:
if not os.path.isfile(config_file_path):
raise FileNotFoundError(
f"Config file {config_file_path} does not exist")
user_config_paths.insert(0, config_file_path)
user_options = {}
for path in user_config_paths:
if os.path.isfile(path):
user_options = json.load(open(path))
break
oldpath = path.replace(".json", "")
if os.path.isfile(oldpath):
warn(f"{oldpath} was found instead of a JSON file."
f" Rename to {path}.", DeprecationWarning, "", 0)
user_options = json.load(open(oldpath))
break
return deepmerge_dicts(conf_default, user_options)
def errors_to_json(errors):
"""Convert the errors to JSON."""
out = []
for e in errors:
out.append({
"check": e[0],
"message": e[1],
"line": 1 + e[2],
"column": 1 + e[3],
"start": 1 + e[4],
"end": 1 + e[5],
"extent": e[6],
"severity": e[7],
"replacements": e[8],
})
return json.dumps(
{"status": "success", "data": {"errors": out}}, sort_keys=True)
def line_and_column(text, position):
"""Return the line number and column of a position in a string."""
position_counter = 0
line_no = 0
for line in text.splitlines(True):
if (position_counter + len(line.rstrip())) >= position:
break
position_counter += len(line)
line_no += 1
return (line_no, position - position_counter)
def lint(input_file, debug=False, config=None):
"""Run the linter on the input file."""
config = config or {}
if isinstance(input_file, str):
text = input_file
else:
text = input_file.read()
# Get the checks.
checks = get_checks(config)
# Apply all the checks.
errors = []
for check in checks:
result = check(text)
for error in result:
(start, end, check, message, replacements) = error
(line, column) = line_and_column(text, start)
if not is_quoted(start, text):
errors += [(check, message, line, column, start, end,
end - start, "warning", replacements)]
if len(errors) > config["max_errors"]:
break
# Sort the errors by line and column number.
errors = sorted(errors[:config["max_errors"]], key=lambda e: (e[2], e[3]))
return errors
def assert_error(text, check, n=1):
"""Assert that text has n errors of type check."""
assert_error.description = f"No {check} error for '{text}'"
assert(check in [error[0] for error in lint(text)])
def consistency_check(text, word_pairs, err, msg, offset=0):
"""Build a consistency checker for the given word_pairs."""
errors = []
msg = " ".join(msg.split())
for w in word_pairs:
matches = [
[m for m in re.finditer(w[0], text)],
[m for m in re.finditer(w[1], text)]
]
if len(matches[0]) > 0 and len(matches[1]) > 0:
idx_minority = len(matches[0]) > len(matches[1])
for m in matches[idx_minority]:
errors.append((
m.start() + offset,
m.end() + offset,
err,
msg.format(w[~idx_minority], m.group(0)),
w[~idx_minority]))
return errors
def preferred_forms_check(text, list, err, msg, ignore_case=True, offset=0):
"""Build a checker that suggests the preferred form."""
if ignore_case:
flags = re.IGNORECASE
else:
flags = 0
msg = " ".join(msg.split())
errors = []
regex = r"[\W^]{}[\W$]"
for p in list:
for r in p[1]:
for m in re.finditer(regex.format(r), text, flags=flags):
txt = m.group(0).strip()
errors.append((
m.start() + 1 + offset,
m.end() + offset,
err,
msg.format(p[0], txt),
p[0]))
return errors
def existence_check(text, list, err, msg, ignore_case=True, str=False,
offset=0, require_padding=True, dotall=False,
excluded_topics=None, exceptions=(), join=False):
"""Build a checker that prohibits certain words or phrases."""
flags = 0
msg = " ".join(msg.split())
if ignore_case:
flags = flags | re.IGNORECASE
if str:
flags = flags | re.UNICODE
if dotall:
flags = flags | re.DOTALL
if require_padding:
regex = r"(?:^|\W){}[\W$]"
else:
regex = r"{}"
errors = []
# If the topic of the text is in the excluded list, return immediately.
if excluded_topics:
tps = topics(text)
if any([t in excluded_topics for t in tps]):
return errors
rx = "|".join(regex.format(w) for w in list)
for m in re.finditer(rx, text, flags=flags):
txt = m.group(0).strip()
if any([re.search(exception, txt) for exception in exceptions]):
continue
errors.append((
m.start() + 1 + offset,
m.end() + offset,
err,
msg.format(txt),
None))
return errors
def max_errors(limit):
"""Decorate a check to truncate error output to a specified limit."""
def wrapper(f):
@functools.wraps(f)
def wrapped(*args, **kwargs):
return truncate_errors(f(*args, **kwargs), limit)
return wrapped
return wrapper
def truncate_errors(errors, limit=float("inf")):
"""If limit was specified, truncate the list of errors.
Give the total number of times that the error was found elsewhere.
"""
if len(errors) > limit:
start1, end1, err1, msg1, replacements = errors[0]
if len(errors) == limit + 1:
msg1 += " Found once elsewhere."
else:
msg1 += f" Found {len(errors)} times elsewhere."
errors = [(start1, end1, err1, msg1, replacements)] + errors[1:limit]
return errors
def ppm_threshold(threshold):
"""Decorate a check to error if the PPM threshold is surpassed."""
def wrapped(f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
return threshold_check(f(*args, **kwargs), threshold, len(args[0]))
return wrapper
return wrapped
def threshold_check(errors, threshold, length):
"""Check that returns an error if the PPM threshold is surpassed."""
if length > 0:
errcount = len(errors)
ppm = (errcount / length) * 1e6
if ppm >= threshold and errcount >= 1:
return [errors[0]]
return []
def is_quoted(position, text):
"""Determine if the position in the text falls within a quote."""
def matching(quotemark1, quotemark2):
straight = '\"\''
curly = '“”'
if quotemark1 in straight and quotemark2 in straight:
return True
if quotemark1 in curly and quotemark2 in curly:
return True
else:
return False
def find_ranges(text):
s = 0
q = pc = ''
start = None
ranges = []
seps = " .,:;-\r\n"
quotes = ['\"', '“', '”', "'"]
for i, c in enumerate(text + "\n"):
if s == 0 and c in quotes and pc in seps:
start = i
s = 1
q = c
elif s == 1 and matching(c, q):
s = 2
elif s == 2:
if c in seps:
ranges.append((start+1, i-1))
start = None
s = 0
else:
s = 1
pc = c
return ranges
def position_in_ranges(ranges, position):
for start, end in ranges:
if start <= position < end:
return True
return False
return position_in_ranges(find_ranges(text), position)
def detector_50_Cent(text):
"""Determine whether 50 Cent is a topic."""
keywords = [
"50 Cent",
"rap",
"hip hop",
"Curtis James Jackson III",
"Curtis Jackson",
"Eminem",
"Dre",
"Get Rich or Die Tryin'",
"G-Unit",
"Street King Immortal",
"In da Club",
"Interscope",
]
num_keywords = sum(word in text for word in keywords)
return ("50 Cent", float(num_keywords > 2))
def topics(text):
"""Return a list of topics."""
detectors = [
detector_50_Cent
]
ts = []
for detector in detectors:
ts.append(detector(text))
return [t[0] for t in ts if t[1] > 0.95]
def context(text, position, level="paragraph"):
"""Get sentence or paragraph that surrounds the given position."""
if level == "sentence":
pass
elif level == "paragraph":
pass
return ""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/proselint/version.py 0000644 0000000 0000000 00000000070 00000000000 014554 0 ustar 00 """Proselint version number."""
__version__ = "0.13.0"
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/pyproject.toml 0000644 0000000 0000000 00000002252 00000000000 013416 0 ustar 00 [tool.poetry]
name = "proselint"
version = "0.13.0"
description = "A linter for prose."
license = "BSD-3-Clause"
authors = ["Amperser Labs "]
readme = "README.md"
homepage = "https://proselint.com"
repository = "https://github.com/amperser/proselint"
classifiers = ["Programming Language :: Python :: Implementation :: CPython"]
include = [
"proselint/",
"tests/",
"proselint/demo.md",
]
exclude = ["tests/.gitignore"]
[tool.poetry.dependencies]
python = "^3.6.1"
click = "^8.0.0"
future = "^0.18.2"
six = "^1.15.0"
[tool.poetry.dev-dependencies]
gmail = {git = "https://github.com/charlierguo/gmail.git"}
APScheduler = ">=3.5.3"
bumpversion = ">=0.5.3"
coverage = "^6.1"
Flask-API = ">=1.0"
Flask-Cors = ">=3.0.4"
Flask = ">=1.1.4"
Flask-Limiter = ">=1.0.1"
gunicorn = ">=19.8.1"
mock = ">=2.0.0"
pytest = "^6.2.5"
redis = ">=2.10.6"
requests = ">=2.19.1"
rq = ">=0.12.0"
pydocstyle = "^6.1.1"
twine = "^3.5.0"
flake8 = "^4.0.1"
flake8-bugbear = "^21.9.2"
flake8-import-order = "^0.18.1"
isort = "^5.10.0"
[tool.poetry.scripts]
proselint = "proselint.command_line:proselint"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/tests/__init__.py 0000644 0000000 0000000 00000000033 00000000000 013750 0 ustar 00 """Tests for proselint."""
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/tests/_test_version.py 0000644 0000000 0000000 00000000736 00000000000 015106 0 ustar 00 """Test version number."""
from click.testing import CliRunner
from proselint.command_line import proselint
from proselint.version import __version__
from .check import Check
class TestCheck(Check):
"""Test class for version number."""
__test__ = True
def test_version(self):
"""Make sure the version number is correct."""
runner = CliRunner()
output = runner.invoke(proselint, "--version")
assert __version__ in output.stdout
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/tests/check.py 0000644 0000000 0000000 00000003261 00000000000 013274 0 ustar 00 """Check that a check is working."""
import codecs
import os
from unittest import TestCase
class Check(TestCase):
"""All tests inherit from Check."""
__test__ = False
def setUp(self):
"""Create a placeholder for setup procedure."""
pass
def tearDown(self):
"""Create a placeholder for teardown procedure."""
pass
@property
def this_check(self):
"""Create a placeholder for the specific check."""
raise NotImplementedError
def passes(self, lst):
"""Check if the test runs cleanly on the given text."""
if isinstance(lst, str):
lst = [lst]
errors = []
for text in lst:
errors += self.this_check.check.__wrapped__(text)
return len(errors) == 0
def wpe_too_high(self):
"""Check whether the check is too noisy."""
min_wpe = 50
examples_dir = os.path.join(os.getcwd(), "tests", "corpus")
examples = os.listdir(examples_dir)
for example in examples:
example_path = os.path.join(examples_dir, example)
if ".DS_Store" in example_path:
break
# Compute the number of words per (wpe) error.
with codecs.open(example_path, "r", encoding='utf-8') as f:
text = f.read()
num_errors = len(self.this_check.check.__wrapped__(text))
num_words = len(text)
try:
wpe = 1.0 * num_words / num_errors
except ZeroDivisionError:
wpe = float('Inf')
# Make sure that
assert wpe > min_wpe, \
f"{example} has only {round(wpe, 2)} wpe."
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/tests/illegal-chars.txt 0000644 0000000 0000000 00000000101 00000000000 015103 0 ustar 00 This file contains an illegal character on the next line...
don
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/tests/test_annotations.py 0000644 0000000 0000000 00000001075 00000000000 015614 0 ustar 00 """Tests for annotations.misc check."""
from proselint.checks.annotations import misc as chk
from .check import Check
class TestCheck(Check):
"""The test class for annotations.misc."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for annotations.misc."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert self.passes("""Add it to the to do list.""")
assert not self.passes("""Add it to the TODO list.""")
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/tests/test_archaism.py 0000644 0000000 0000000 00000001105 00000000000 015040 0 ustar 00 """Tests for archaism.misc check."""
from proselint.checks.archaism import misc as chk
from .check import Check
class TestCheck(Check):
"""The test class for archaism.misc."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for archaism.misc."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert self.passes("""I want to sleep, and maybe dream.""")
assert not self.passes("""I want to sleep, perchance to dream.""")
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/tests/test_butterick_symbols.py 0000644 0000000 0000000 00000003062 00000000000 017021 0 ustar 00 """Test Butterick's symbols."""
from proselint.checks.typography import symbols as chk
from .check import Check
class TestCheck(Check):
"""The test class for typography.symbols."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_ellipsis(self):
"""Find ... in a string."""
assert chk.check_ellipsis("""The long and winding road...""")
def test_copyright(self):
"""Find a (c) or (C) in a string."""
assert chk.check_copyright_symbol("""Show me the money! (C)""")
assert chk.check_copyright_symbol("""Show me the money! (c)""")
def test_trademark(self):
"""Find a (TM) or (tm) in a string."""
assert chk.check_trademark_symbol("""The Fresh Maker (TM)""")
assert chk.check_trademark_symbol("""The Fresh Maker (tm)""")
def test_registered_trademark(self):
"""Find a (r) or (R) in a string."""
assert chk.check_registered_trademark_symbol("""Just Do It (R)""")
assert chk.check_registered_trademark_symbol("""Just Do It (r)""")
def test_sentence_spacing(self):
"""Find a sentence followed by three or more spaces."""
assert chk.check_sentence_spacing(
"""This is a sentence. This is another.""")
def test_multiplication(self):
"""Find an x between two digits."""
assert chk.check_multiplication_symbol(
"""It is obvious that 2 x 2 = 4.""")
def test_curly_quotes(self): # FIXME
"""Find "" quotes in a string."""
pass
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/tests/test_clear_cache.py 0000644 0000000 0000000 00000010660 00000000000 015470 0 ustar 00 """Tests for the clear cache operation from proselint.command_line."""
import os
import unittest
from proselint import command_line as cl
try:
from unittest import mock
except ImportError:
# Py2.x
from unittest import mock
try:
from builtins import PermissionError
except ImportError:
class PermissionError(OSError):
"""Introduced in Py3.3, emulate for earlier versions."""
def __init__(self, *args, **kwargs):
"""Constructor."""
OSError.__init__(self, *args, **kwargs)
try:
from builtins import FileNotFoundError
except ImportError:
class FileNotFoundError(OSError):
"""Introduced in Py3.3, emulate for earlier versions."""
def __init__(self, *args, **kwargs):
"""Constructor."""
OSError.__init__(self, *args, **kwargs)
try:
from builtins import IsADirectoryError
except ImportError:
class IsADirectoryError(OSError):
"""Introduced in Py3.3, emulate for earlier versions."""
def __init__(self, *args, **kwargs):
"""Constructor."""
OSError.__init__(self, *args, **kwargs)
class Test__delete_compiled_python_files(unittest.TestCase):
"""proselint.command_line._delete_compiled_python_files()."""
def setUp(self):
"""init common data."""
self.base_dir = '.'
self.python_file = 'a.py'
self.pyc_file = 'a.pyc'
self.dot_pyc = '.pyc'
self.files = [
(self.base_dir, ('dummy',), (self.pyc_file,
self.python_file,
self.dot_pyc))
]
self.pyc_file_path = os.path.join(self.base_dir, self.pyc_file)
self.python_file_path = os.path.join(self.base_dir, self.python_file)
self.dot_pyc_path = os.path.join(self.base_dir, self.python_file)
@mock.patch('os.walk')
@mock.patch('os.remove')
def test_delete_pyc_file(self, mock_remove, mock_walk):
"""Ensure 'pyc' files are removed."""
mock_walk.return_value = self.files
cl._delete_compiled_python_files()
mock_remove.assert_called_with(self.pyc_file_path)
@mock.patch('os.walk')
@mock.patch('os.remove')
def test_files_not_deleted(self, mock_remove, mock_walk):
"""Ensure non 'pyc' files are not removed."""
mock_walk.return_value = self.files
cl._delete_compiled_python_files()
with self.assertRaises(AssertionError):
mock_remove.assert_called_with(self.python_file_path)
with self.assertRaises(AssertionError):
mock_remove.assert_called_with(self.dot_pyc_path)
@mock.patch('os.walk')
@mock.patch('os.remove', side_effect=PermissionError)
def test_no_permission(self, mock_remove, mock_walk):
"""Ignore if unable to delete files."""
mock_walk.return_value = self.files
cl._delete_compiled_python_files()
@mock.patch('os.walk')
@mock.patch('os.remove', side_effect=OSError)
def test_on_oserror(self, mock_remove, mock_walk):
"""Ignore if OSError."""
mock_walk.return_value = self.files
cl._delete_compiled_python_files()
@mock.patch('os.walk')
@mock.patch('os.remove', side_effect=FileNotFoundError)
def test_files_not_found(self, mock_remove, mock_walk):
"""Ignore if file not found."""
mock_walk.return_value = self.files
cl._delete_compiled_python_files()
@mock.patch('os.walk')
@mock.patch('os.remove', side_effect=IsADirectoryError)
def test__remove_dir(self, mock_remove, mock_walk):
"""Ignore if attempt to delete a directory."""
mock_walk.return_value = self.files
cl._delete_compiled_python_files()
class Test__delete_cache(unittest.TestCase):
"""proselint.command_line.__delete_cache()."""
def setUp(self):
"""Init common data."""
self.cache_path = os.path.join("proselint", "cache")
@mock.patch('shutil.rmtree')
def test_rm_cache(self, mock_rmtree):
"""Correct directory is removed."""
cl._delete_cache()
mock_rmtree.assert_called_with(self.cache_path)
@mock.patch('shutil.rmtree', side_effect=PermissionError)
def test_no_permission(self, mock_rmtree):
"""Ignore if unable to delete."""
cl._delete_cache()
@mock.patch('shutil.rmtree', side_effect=OSError)
def test_on_oserror(self, mock_rmtree):
"""Ignore if general OSError."""
cl._delete_cache()
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/tests/test_cliches.py 0000644 0000000 0000000 00000003337 00000000000 014674 0 ustar 00 """Test the Cliches.misc module."""
from proselint.checks.cliches import misc as chk
from .check import Check
class TestCheck(Check):
"""The test class for cliches.misc."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def setUp(self):
"""Create test sentences."""
self.l_garner = """Worse than a fate worse than death."""
self.l_write_good = """He's a chip off the old block."""
self.l_gnu_diction = """It's a matter of concern."""
def test_cliches_garner_basic(self):
"""Basic checks on check_cliches_garner."""
assert chk.check_cliches_garner("""No cliches here.""") == []
# use one of the example cliches to verify basic functionality
assert chk.check_cliches_garner(self.l_garner) != []
assert "cliches.garner" in chk.check_cliches_garner(self.l_garner)[0]
def test_cliches_write_good_basic(self):
"""Basic checks on check_cliches_write_good."""
assert chk.check_cliches_write_good("""No cliches here.""") == []
# use one of the example cliches to verify basic functionality
assert chk.check_cliches_write_good(self.l_write_good) != []
assert "cliches.write_good" in chk.check_cliches_write_good(
self.l_write_good)[0]
def test_cliches_gnu_diction_basic(self):
"""Basic check on check_cliches_gnu_diction."""
assert chk.check_cliches_gnu_diction("""No cliches here.""") == []
# use one of the example cliches to verify basic functionality
assert chk.check_cliches_gnu_diction(self.l_gnu_diction) != []
assert "cliches.gnu_diction" in chk.check_cliches_gnu_diction(
self.l_gnu_diction)[0]
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/tests/test_config_flag.py 0000644 0000000 0000000 00000004071 00000000000 015514 0 ustar 00 """Test user option overrides using --config and load_options"""
import json
import os
from unittest import TestCase
from unittest.mock import patch
from click.testing import CliRunner
from proselint.command_line import proselint
from proselint.config import default
from proselint.tools import deepmerge_dicts, load_options
runner = CliRunner()
def test_deepmerge_dicts():
"""Test deepmerge_dicts"""
d1 = {'a': 1, 'b': {'c': 2, 'd': 3}}
d2 = {'a': 2, 'b': {'c': 3, 'e': 4}}
assert deepmerge_dicts(d1, d2) == {'a': 2, 'b': {'c': 3, 'd': 3, 'e': 4}}
@patch("os.path.isfile")
def test_load_options_function(isfile):
"""Test load_options by specifying a user options path"""
isfile.side_effect = "tests/test_config_flag_proselintrc".__eq__
overrides = load_options("tests/test_config_flag_proselintrc", default)
assert load_options(conf_default=default)["checks"]["uncomparables.misc"]
assert not overrides["checks"]["uncomparables.misc"]
isfile.side_effect = os.path.join(os.getcwd(), ".proselintrc").__eq__
TestCase().assertRaises(FileNotFoundError, load_options)
def test_config_flag():
"""Test the --config CLI argument"""
output = runner.invoke(proselint, "--demo")
assert "uncomparables.misc" in output.stdout
output = runner.invoke(
proselint, "--demo --config tests/test_config_flag_proselintrc")
assert "uncomparables.misc" not in output.stdout
output = runner.invoke(proselint, "--demo --config non_existent_file")
assert output.exit_code == 1
assert "FileNotFoundError" == output.exc_info[0].__name__
output = runner.invoke(proselint, "non_existent_file")
assert output.exit_code == 2
def test_dump_config():
"""Test --dump-default-config and --dump-config"""
output = runner.invoke(proselint, "--dump-default-config")
assert json.loads(output.stdout) == default
output = runner.invoke(
proselint, "--dump-config --config tests/test_config_flag_proselintrc")
assert json.loads(output.stdout) == json.load(
open("tests/test_config_flag_proselintrc"))
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/tests/test_config_flag_proselintrc 0000644 0000000 0000000 00000007465 00000000000 017523 0 ustar 00 {
"max_errors": 1000,
"checks": {
"airlinese.misc" : true,
"annotations.misc" : true,
"archaism.misc" : true,
"cliches.hell" : true,
"cliches.misc" : true,
"consistency.spacing" : true,
"consistency.spelling" : true,
"corporate_speak.misc" : true,
"cursing.filth" : true,
"cursing.nfl" : false,
"cursing.nword" : true,
"dates_times.am_pm" : true,
"dates_times.dates" : true,
"hedging.misc" : true,
"hyperbole.misc" : true,
"jargon.misc" : true,
"lexical_illusions.misc" : true,
"lgbtq.offensive_terms" : true,
"lgbtq.terms" : true,
"links.broken" : false,
"malapropisms.misc" : true,
"misc.apologizing" : true,
"misc.back_formations" : true,
"misc.bureaucratese" : true,
"misc.but" : true,
"misc.capitalization" : true,
"misc.chatspeak" : true,
"misc.commercialese" : true,
"misc.composition" : true,
"misc.currency" : true,
"misc.debased" : true,
"misc.false_plurals" : true,
"misc.illogic" : true,
"misc.inferior_superior" : true,
"misc.institution_name" : true,
"misc.latin" : true,
"misc.many_a" : true,
"misc.metaconcepts" : true,
"misc.metadiscourse" : true,
"misc.narcissism" : true,
"misc.not_guilty" : true,
"misc.phrasal_adjectives" : true,
"misc.preferred_forms" : true,
"misc.pretension" : true,
"misc.professions" : true,
"misc.punctuation" : true,
"misc.scare_quotes" : true,
"misc.suddenly" : true,
"misc.tense_present" : true,
"misc.waxed" : true,
"misc.whence" : true,
"mixed_metaphors.misc" : true,
"mondegreens.misc" : true,
"needless_variants.misc" : true,
"nonwords.misc" : true,
"oxymorons.misc" : true,
"psychology.misc" : true,
"redundancy.misc" : true,
"redundancy.ras_syndrome" : true,
"skunked_terms.misc" : true,
"spelling.able_atable" : true,
"spelling.able_ible" : true,
"spelling.athletes" : true,
"spelling.em_im_en_in" : true,
"spelling.er_or" : true,
"spelling.in_un" : true,
"spelling.misc" : true,
"security.credit_card" : true,
"security.password" : true,
"sexism.misc" : true,
"terms.animal_adjectives" : true,
"terms.denizen_labels" : true,
"terms.eponymous_adjectives" : true,
"terms.venery" : true,
"typography.diacritical_marks" : true,
"typography.exclamation" : true,
"typography.symbols" : true,
"uncomparables.misc" : false,
"weasel_words.misc" : true,
"weasel_words.very" : true
}
}
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/tests/test_consistency_check.py 0000644 0000000 0000000 00000001567 00000000000 016763 0 ustar 00 """Test the consistency_check function from the tools.py module."""
from proselint.tools import consistency_check as chk
from .check import Check
class TestCheck(Check):
"""The test class for tools.consistency_check."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def setUp(self):
"""Create some test fixtures."""
self.L = [['colour', 'color']]
self.err = 'error message'
self.msg = 'inconsistent form of {} vs {}'
def test_smoke(self):
"""Basic smoke test for consistency_check."""
assert chk(
"Painting colour on color", self.L, self.err, self.msg) != []
assert chk(
"Painting colour on colour", self.L, self.err, self.msg) == []
assert chk(
"Painting color on color", self.L, self.err, self.msg) == []
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250509.186823
proselint-0.13.0/tests/test_consistency_spacing.py 0000644 0000000 0000000 00000001175 00000000000 017325 0 ustar 00 """Tests for consistency.spacing check."""
from proselint.checks.consistency import spacing as chk
from .check import Check
class TestCheck(Check):
"""The test class for consistency.spacing."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for consistency.spacing."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert self.passes(
"""This is good. Only one space each time. Every time.""")
assert not self.passes("""This is bad. Not consistent. At all.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_consistency_spelling.py 0000644 0000000 0000000 00000001274 00000000000 017516 0 ustar 00 """Tests for consistency.spelling check."""
from proselint.checks.consistency import spelling as chk
from .check import Check
class TestCheck(Check):
"""The test class for consistency.spelling."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for consistency.spelling."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert self.passes("""The centre for the arts is the art centre.""")
assert self.passes("""The center for the arts is the art center.""")
assert not self.passes("""The centre of the arts is the art center.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_corporate_speak.py 0000644 0000000 0000000 00000001126 00000000000 016435 0 ustar 00 """Tests for corporate_speak.misc check."""
from proselint.checks.corporate_speak import misc as chk
from .check import Check
class TestCheck(Check):
"""The test class for corporate_speak.misc."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for corporate_speak.misc."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert self.passes("""We will discuss it later.""")
assert not self.passes("""We will circle back around to it.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_cursing_filth.py 0000644 0000000 0000000 00000000765 00000000000 016124 0 ustar 00 """Tests for cursing.filth check."""
from proselint.checks.cursing import filth as chk
from .check import Check
class TestCheck(Check):
"""The test class for cursing.filth."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for cursing.filth."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""Bad shit in this phrase.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_cursing_nfl.py 0000644 0000000 0000000 00000000761 00000000000 015571 0 ustar 00 """Tests for cursing.nfl check."""
from proselint.checks.cursing import nfl as chk
from .check import Check
class TestCheck(Check):
"""The test class for cursing.nfl."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for cursing.nfl."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""The QB is named ball licker.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_cursing_nword.py 0000644 0000000 0000000 00000000750 00000000000 016141 0 ustar 00 """Tests for cursing.nword check."""
from proselint.checks.cursing import nword as chk
from .check import Check
class TestCheck(Check):
"""The test class for cursing.nword."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for cursing.nword."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""The n-word.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_dates_times_am_pm.py 0000644 0000000 0000000 00000004126 00000000000 016731 0 ustar 00 """Tests for dates_times.am_pm check."""
from proselint.checks.dates_times import am_pm as chk
from .check import Check
class TestCheck(Check):
"""The test class for dates_times.am_pm."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke_check_lowercase_periods(self):
"""Basic smoke test.
This is for the function
dates_times.am_pm.check_lowercase_periods.
"""
assert chk.check_lowercase_periods(
"Basic smoke phrase without issues.") == []
assert chk.check_lowercase_periods(
"It happened at 7 a.m.") == []
assert chk.check_lowercase_periods(
"It happened at 7 am.") != []
assert chk.check_lowercase_periods(
"On Wed, Sep 21, 2016 at 11:42 AM -0400, X wrote:") == []
def test_smoke_check_spacing(self):
"""Basic smoke test.
This is for the function
dates_times.am_pm.check_spacing.
"""
assert chk.check_spacing(
"Basic smoke phrase without issues.") == []
assert chk.check_spacing(
"It happened at 7 a.m.") == []
assert chk.check_spacing(
"It happened at 7a.m.") != []
def test_smoke_check_midnight_noon(self):
"""Basic smoke test.
This for the function
dates_times.am_pm.midnight_noon.
"""
assert chk.check_midnight_noon(
"Basic smoke phrase without issues.") == []
assert chk.check_midnight_noon(
"It happened at noon.") == []
assert chk.check_midnight_noon(
"It happened at 12 a.m.") != []
def test_smoke_check_redundancy(self):
"""Basic smoke test.
This for the function
dates_times.am_pm.check_redundancy.
"""
assert len(chk.check_redundancy(
"Basic smoke phrase without issues.")) == 0
assert len(chk.check_redundancy(
"It happened at 7 a.m.")) == 0
assert len(chk.check_redundancy(
"It happened at 7a.m. in the morning.")) == 1
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_dates_times_dates.py 0000644 0000000 0000000 00000005077 00000000000 016746 0 ustar 00 """Tests for dates_times.dates check."""
from proselint.checks.dates_times import dates as chk
from .check import Check
class TestCheck(Check):
"""The test class for dates_times.dates."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke_check_decade_apostrophes_short(self):
"""Basic smoke test.
This for the function
dates_times.dates.check_decade_apostrophes_short.
"""
assert chk.check_decade_apostrophes_short(
"Basic smoke phrase without issues.") == []
assert chk.check_decade_apostrophes_short(
"It happened in the 90s.") == []
assert chk.check_decade_apostrophes_short(
"It happened in the 90's.") != []
def test_smoke_check_decade_apostrophes_long(self):
"""Basic smoke test.
This is for the function
dates_times.dates.decade_apostrophes_long.
"""
assert chk.check_decade_apostrophes_long(
"Basic smoke phrase without issues.") == []
assert chk.check_decade_apostrophes_long(
"It happened in the 1980s.") == []
assert chk.check_decade_apostrophes_long(
"It happened in the 1980's.") != []
def test_smoke_check_dash_and_from(self):
"""Basic smoke test.
This for the function
dates_times.dates.dash_and_from.
"""
assert chk.check_dash_and_from(
"Basic smoke phrase without issues.") == []
assert chk.check_dash_and_from(
"It happened from 2000 to 2005.") == []
assert chk.check_dash_and_from(
"It happened from 2000-2005.") != []
def test_smoke_check_month_year_comma(self):
"""Basic smoke test.
This is for the function
dates_times.dates.check_month_year_comma.
"""
assert chk.check_month_year_comma(
"Basic smoke phrase without issues.") == []
assert chk.check_month_year_comma(
"It happened in August 2008.") == []
assert chk.check_month_year_comma(
"It happened in August, 2008.") != []
def test_smoke_check_month_of_year(self):
"""Basic smoke test.
This is for the function
dates_times.dates.check_month_of_year.
"""
assert chk.check_month_of_year(
"Basic smoke phrase without issues.") == []
assert chk.check_month_of_year(
"It happened in August 2008.") == []
assert chk.check_month_of_year(
"It happened in August of 2008.") != []
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_existence_check.py 0000644 0000000 0000000 00000004701 00000000000 016402 0 ustar 00 """Test the existence_check function from the tools.py module."""
from __future__ import absolute_import
from proselint.tools import existence_check as chk
from .check import Check
class TestCheck(Check):
"""The test class for tools.existence_check."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def setUp(self):
"""setUp method creating some test fixtures."""
self.L = ['abc']
self.err = 'error message'
self.msg = 'it exists'
def test_smoke(self):
"""Basic smoke test to determine that existence_check is working."""
assert chk(
"""abc is as easy as 123""", self.L, self.err, self.msg) != []
assert chk(
"""easy breezy""", self.L, self.err, self.msg) == []
assert self.err in chk(
"""abc is as easy as 123""", self.L, self.err, self.msg)[0]
assert self.msg in chk(
"""abc is as easy as 123""", self.L, self.err, self.msg)[0]
def test_multiple_matches(self):
"""Test that multiple matches are found correctly."""
assert len(
chk("""abc and abc are as easy as 123""",
self.L, self.err, self.msg)) == 2
assert len(
chk("""ABC and abc are as easy as 123""",
self.L, self.err, self.msg, ignore_case=True)) == 2
assert len(
chk("""ABC and abc are as easy as 123""",
self.L, self.err, self.msg, ignore_case=False)) == 1
assert chk(
"""abcabc are easy as 123""", self.L, self.err, self.msg) == []
def test_string_types(self):
"""Test that the function works with different string types."""
assert chk('abc is easy as 123', self.L, self.err, self.msg) != []
assert chk("abc is easy as 123", self.L, self.err, self.msg) != []
assert chk(u'abc is easy as 123', self.L, self.err, self.msg) != []
assert chk(u"abc is easy as 123", self.L, self.err, self.msg) != []
def test_exceptions(self):
"""Test that existence_check does not report excluded phrases"""
regex = [r"\b(\w+)\b\s\1"]
no = ["should should"]
errs = chk("should should flag flag.", regex, "", "",
require_padding=False)
assert len(errs) == 2
errs = chk("should should flag flag.", regex, "", "", exceptions=no,
require_padding=False)
assert len(errs) == 1
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_exit_codes.py 0000644 0000000 0000000 00000001325 00000000000 015403 0 ustar 00 """Check that the CLI returns the appropriate exit code."""
from click.testing import CliRunner
from proselint.command_line import proselint
from .check import Check
class TestExitCodes(Check):
"""Test class for CLI exit codes"""
__test__ = True
def setUp(self):
self.runner = CliRunner()
def test_exit_code_demo(self):
"""Ensure that linting the demo returns an exit code of 1."""
output = self.runner.invoke(proselint, "--demo")
assert output.exit_code == 1
def test_exit_code_version(self):
"""Ensure that getting the version returns an exit code of 0."""
output = self.runner.invoke(proselint, "--version")
assert output.exit_code == 0
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_garner_dates.py 0000644 0000000 0000000 00000001764 00000000000 015722 0 ustar 00 """Test garner.dates."""
from proselint.checks.dates_times import dates
from .check import Check
class TestCheck(Check):
"""Test class for garner.dates."""
__test__ = True
def test_50s_hyphenation(self):
"""Find unneeded hyphen in 50's."""
text = """The 50's were swell."""
errors = dates.check_decade_apostrophes_short(text)
assert len(errors) == 1
def test_50_Cent_hyphenation(self):
"""Don't flag 50's when it refers to 50 Cent's manager."""
text = """
Dr. Dre suggested to 50's manager that he look into signing
Eminem to the G-Unit record label.
"""
errors = dates.check_decade_apostrophes_short(text)
assert len(errors) == 0
def test_dash_and_from(self):
"""Test garner.check_dash_and_from."""
text = """From 1999-2002, Sally served as chair of the committee."""
errors = dates.check_dash_and_from(text)
print(errors)
assert len(errors) == 1
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_gmeu/test_a_A.py 0000644 0000000 0000000 00000004367 00000000000 015742 0 ustar 00 #!/usr/bin/env python
"""Test GMEU entry 'a', part A."""
from proselint.tools import assert_error
from tests.check import Check
class chk:
def check(self, text):
return assert_error, text, "misc.a_vs_an"
class TestCheck(Check):
"""The test class for GMEU entry A - using the correct determiner."""
@property
def this_check(self):
return chk
sentences_with_errors = [
"Are you an Yankee fan?",
"Coffee tastes less sweet in an white mug.",
"One of them wore a opalescent vest.",
"You're a intelligent guy, often misguided.",
"Ezra gave an eulogy.",
"What capital of an European country is the farthest north?",
"His sole reward was an one-year term as Ambassador to Thailand.",
"I will be relying on a roulette wheel and an Ouija board.",
"Anyone in an uniform is fair game.",
"Grimm started working as a F.B.I. agent in 1995.",
"Out of 186 managers participating, 57 had a MBA degree.",
"Smith announced that a SEC filing is pending.",
"This argument is an historical desecration.",
"The treatment of crime in Britain shows an historic shift away…",
"It is, in some ways, an humble form.",
"The thief turned out to be an habitual offender from Darlington.",
"This stage displays an hallucinatory image that signifies itself.",
"He saw an hallucinatory image before passing out.",
"A triumphant Adolf Hitler addressed an hysterical crowd.",
"Kun pieced together an history of gender-segregated dining in L.A.",
"An historian who fled the Nazis and still wants us to read Hitler.",
"It is nominally an historical novel.",
"It feels good to validate an hypothesis.",
"An hereditary title can be passed to a member of the family.",
"The Clinton Presidency was an historic era of prosperity.",
"There comes to be an habitual pattern between neurons in the brain.",
"They had the authority to start an humanitarian intervention.",
"She laughed aloud, an hysterical sort of giggled, quickly stifled",
]
def test_smoke(self):
for sentence in self.sentences_with_errors:
assert not self.passes(sentence)
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_gmeu/test_a_B.py 0000644 0000000 0000000 00000001557 00000000000 015741 0 ustar 00 #!/usr/bin/env python
"""Test GMEU entry 'a', part B."""
from proselint.tools import assert_error
from tests.check import Check
class chk:
def check(self, text):
return assert_error, text, "misc.a_distributive"
class TestCheck(Check):
"""The test class for GMEU entry A - using a over per in the distributive
sense.
"""
@property
def this_check(self):
return chk
def test_smoke(self):
sentences = [
"An apple per day keeps the doctor away.",
"I sleep eight hours per night.",
"Their policy allows one golf cart a couple.",
"The company donated five books a student.",
"Our a-unit cost is less than $1000.",
"The $50-a-parent fee seems unreasonably high."
]
for sentence in sentences:
assert not self.passes(sentence)
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_gmeu/test_a_C.py 0000644 0000000 0000000 00000000253 00000000000 015732 0 ustar 00 #!/usr/bin/env python
"""Test GMEU entry 'a', part C.
This entry is about pronunciation of the word 'a' and is unlikely to be
relevant to usage in written language.
"""
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_hedging.py 0000644 0000000 0000000 00000001000 00000000000 014650 0 ustar 00 """Tests for hedging.misc check."""
from proselint.checks.hedging import misc as chk
from .check import Check
class TestCheck(Check):
"""The test class for hedging.misc."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for hedging.misc."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""I would argue that this is a good test.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_hyperbole.py 0000644 0000000 0000000 00000000762 00000000000 015252 0 ustar 00 """Tests for hyperbole.misc check."""
from proselint.checks.hyperbole import misc as chk
from .check import Check
class TestCheck(Check):
"""The test class for hyperbole.misc."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for hyperbole.misc."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""So exaggerated!!!""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_illegal_chars.py 0000644 0000000 0000000 00000001352 00000000000 016046 0 ustar 00 """Check that the CLI can handle invalid characters."""
from os.path import abspath, dirname, join
from click.testing import CliRunner
from proselint.command_line import proselint
from .check import Check
class TestInvalidCharacters(Check):
"""Test class for testing invalid characters on the CLI"""
__test__ = True
def test_invalid_characters(self):
"""Ensure that a file with illegal characters does not break us."""
curr_dir = dirname(abspath(__file__))
test_file = join(curr_dir, "illegal-chars.txt")
runner = CliRunner()
output = runner.invoke(proselint, test_file)
assert "UnicodeDecodeError" not in output.stdout
assert "FileNotFoundError" not in output.stdout
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_jargon.py 0000644 0000000 0000000 00000000765 00000000000 014544 0 ustar 00 """Tests for jargon.misc check."""
from proselint.checks.jargon import misc as chk
from .check import Check
class TestCheck(Check):
"""The test class for jargon.misc."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for jargon.misc."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""I agree it's in the affirmative.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_leonard.py 0000644 0000000 0000000 00000001426 00000000000 014703 0 ustar 00 """Test garner.dates."""
from proselint.checks.typography import exclamation
from .check import Check
class TestCheck(Check):
"""Test class for leonard.exclamation."""
__test__ = True
def test_capitalization_and_no_exclamation(self):
"""Don't throw error when phrase has capitalization."""
text = """
The QUICK BROWN fox juMPED over the lazy cat.
"""
errors = exclamation.check_repeated_exclamations(text)
assert len(errors) == 0
def test_exclamation(self):
"""Test leonard.exclamation. with exclamation marks."""
text = """Sally sells seashells and they were too expensive!!!!"""
errors = exclamation.check_repeated_exclamations(text)
print(errors)
assert len(errors) == 1
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_lexical_illusions.py 0000644 0000000 0000000 00000001710 00000000000 016775 0 ustar 00 """Tests for lexical_illusions.misc check."""
from proselint.checks.lexical_illusions import misc as chk
from .check import Check
class TestCheck(Check):
"""The test class for lexical_illusions.misc."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for lexical_illusions.misc."""
assert self.passes("Smoke phrase with nothing flagged.")
assert not self.passes("Paris in the the springtime.")
assert self.passes("And he's gone, gone with the breeze")
assert self.passes("You should know that that sentence wasn't wrong.")
assert self.passes("She had had dessert on the balcony.")
assert not self.passes("You should know that that that was wrong.")
assert self.passes("The practitioner's side")
assert self.passes("An antimatter particle")
assert self.passes("The theory")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_lgbtq_offensive_terms.py 0000644 0000000 0000000 00000001074 00000000000 017645 0 ustar 00 """Tests for lgbtq.terms check."""
from proselint.checks.lgbtq import offensive_terms as chk
from .check import Check
class TestCheck(Check):
"""The test class for lgbtq.offensive_terms."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for lgbtq.offensive_terms."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert self.passes("""I once met a gay man.""")
assert not self.passes("""I once met a fag.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_lgbtq_terms.py 0000644 0000000 0000000 00000001553 00000000000 015603 0 ustar 00 """Tests for lgbtq.offensive_terms check."""
from proselint.checks.lgbtq import terms as chk
from .check import Check
class TestCheck(Check):
"""The test class for lgbtq.terms."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for lgbtq.terms."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert self.passes("""They were a gay couple.""")
assert not self.passes("""He was a homosexual man.""")
def test_homosexual_term(self):
"""Check that the term homosexual does not get caught."""
assert self.passes("""Homosexual.""")
def test_sexual_prefence(self):
"""Check that sexual preference is flagged."""
assert not self.passes("""My sexual preference is for women.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_malaproprisms.py 0000644 0000000 0000000 00000001024 00000000000 016142 0 ustar 00 """Tests for malaproprisms.misc check."""
from proselint.checks.malapropisms import misc as chk
from .check import Check
class TestCheck(Check):
"""The test class for malaproprisms.misc."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for malaproprisms.misc."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""Found in the Infinitesimal Universe.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_apologizing.py 0000644 0000000 0000000 00000001001 00000000000 016601 0 ustar 00 """Tests for misc.apologizing check."""
from proselint.checks.misc import apologizing as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.apologizing."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.apologizing."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""More research is needed.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_back_formations.py 0000644 0000000 0000000 00000001024 00000000000 017425 0 ustar 00 """Tests for misc.back_formations check."""
from proselint.checks.misc import back_formations as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.back_formations."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.back_formations."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""It is an improprietous use.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_bureaucratese.py 0000644 0000000 0000000 00000001051 00000000000 017116 0 ustar 00 """Tests for misc.bureaucratese check."""
from proselint.checks.misc import bureaucratese as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.bureaucratese."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.bureaucratese."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes(
"""I hope the report meets with your approval.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_but.py 0000644 0000000 0000000 00000001130 00000000000 015054 0 ustar 00 """Tests for misc.but check."""
from proselint.checks.misc import but as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.but."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.but."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""But I never start with the word "but".""")
assert self.passes("""I never start with the word "but",
but might use it after a linebreak.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_capitalization.py 0000644 0000000 0000000 00000002016 00000000000 017301 0 ustar 00 """Tests for misc.capitalization check."""
from proselint.checks.misc import capitalization as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.capitalization."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.capitalization.check."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""It goes back to the stone age.""")
def test_smoke_check_months(self):
"""Basic smoke test for misc.capitalization.check_months."""
assert chk.check_months("""Smoke phrase with nothing flagged""") == []
assert chk.check_months("""A nice day in june.""") != []
def test_smoke_check_days(self):
"""Basic smoke test for misc.capitalization.check_days."""
assert chk.check_days("""Smoke phrase with nothing flagged""") == []
assert chk.check_days("""It happened on friday.""") != []
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_chatspeak.py 0000644 0000000 0000000 00000000764 00000000000 016241 0 ustar 00 """Tests for misc.chatspeak check."""
from proselint.checks.misc import chatspeak as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.chatspeak."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.chatspeak."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""BRB getting coffee.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_commercialese.py 0000644 0000000 0000000 00000001021 00000000000 017071 0 ustar 00 """Tests for misc.commercialese check."""
from proselint.checks.misc import commercialese as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.commercialese."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.commercialese."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""We regret to inform you of this.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_composition.py 0000644 0000000 0000000 00000001001 00000000000 016622 0 ustar 00 """Tests for misc.composition check."""
from proselint.checks.misc import composition as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.composition."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.composition."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""His story is not honest.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_currency.py 0000644 0000000 0000000 00000000761 00000000000 016125 0 ustar 00 """Tests for misc.currency check."""
from proselint.checks.misc import currency as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.currency."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.currency."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""It cost $10 dollars.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_debased.py 0000644 0000000 0000000 00000000770 00000000000 015662 0 ustar 00 """Tests for misc.debased check."""
from proselint.checks.misc import debased as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.debased."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.debased."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""This leaves much to be desired.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_false_plurals.py 0000644 0000000 0000000 00000001400 00000000000 017116 0 ustar 00 """Tests for misc.false_plurals check."""
from proselint.checks.misc import false_plurals as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.false_plurals."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.false_plurals."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""There were several phenomenons.""")
def test_smoke_kudos(self):
"""Basic smoke test for misc.false_plurals.kudos."""
assert chk.check_kudos("""Smoke phrase with nothing flagged.""") == []
assert chk.check_kudos("""I give you many kudos.""") != []
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_greylist.py 0000644 0000000 0000000 00000000776 00000000000 016143 0 ustar 00 """Tests for misc.greylist check."""
from proselint.checks.misc import greylist as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.greylist."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.greylist."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""She should utilize her knowledge.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_illogic.py 0000644 0000000 0000000 00000002210 00000000000 015704 0 ustar 00 """Tests for misc.illogic check."""
from proselint.checks.misc import illogic as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.illogic."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.illogic."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""We should preplan the trip.""")
def test_smoke_coin_a_phrase_from(self):
"""Basic smoke test for misc.illogic.check_coin_a_phrase_from."""
assert chk.check_coin_a_phrase_from(
"""Smoke phrase with nothing flagged.""") == []
assert chk.check_coin_a_phrase_from(
"""To coin a phrase from him, No diggity""") != []
def test_smoke_check_without_your_collusion(self):
"""Basic smoke test for misc.illogic."""
assert chk.check_without_your_collusion(
"""Smoke phrase with nothing flagged.""") == []
assert chk.check_without_your_collusion(
"""Not Without your collusion you won't'.""") != []
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_inferior_superior.py 0000644 0000000 0000000 00000001070 00000000000 020032 0 ustar 00 """Tests for misc.inferior_superior check."""
from proselint.checks.misc import inferior_superior as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.inferior_superior."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.inferior_superior."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes(
"""It was more inferior than the alternative.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_latin.py 0000644 0000000 0000000 00000000762 00000000000 015403 0 ustar 00 """Tests for misc.latin check."""
from proselint.checks.misc import latin as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.latin."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.latin."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""And ceteris paribus, it was good.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_many_a.py 0000644 0000000 0000000 00000001013 00000000000 015526 0 ustar 00 """Tests for misc.many_a check."""
from proselint.checks.misc import many_a as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.many_a."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.many_a."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes(
"""There were many a day I thought about it.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_metaconcepts.py 0000644 0000000 0000000 00000000616 00000000000 016757 0 ustar 00 """Tests for misc.metaconcepts check."""
from proselint.checks.misc import metaconcepts as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.metaconcepts."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.metaconcepts."""
pass
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_metadiscourse.py 0000644 0000000 0000000 00000001030 00000000000 017130 0 ustar 00 """Tests for misc.metadiscourse check."""
from proselint.checks.misc import metadiscourse as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.metadiscourse."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.metadiscourse."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""It's based on the rest of this article.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_narcissism.py 0000644 0000000 0000000 00000001126 00000000000 016442 0 ustar 00 """Tests for misc.narcissism check."""
from proselint.checks.misc import narcissism as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.narcissism."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.narcissism."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes(
"""In recent years, an increasing number of scientists have studied
the problem in detail.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_not_guilty.py 0000644 0000000 0000000 00000001036 00000000000 016464 0 ustar 00 """Tests for misc.not_guilty check."""
from proselint.checks.misc import not_guilty as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.not_guilty."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.not_guilty."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes(
"""She is not guilty beyond a reasonable doubt.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_phrasal_adjectives.py 0000644 0000000 0000000 00000001604 00000000000 020123 0 ustar 00 """Tests for misc.phrasal_adjectives check."""
from proselint.checks.misc import phrasal_adjectives as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.phrasal_adjectives."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.phrasal_adjectives."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""There were across the board discounts.""")
def test_smoke_ly(self):
"""Basic smoke test for misc.phrasal_adjectives.check_ly."""
assert chk.check_ly("""Smoke phrase with nothing flagged.""") == []
assert chk.check_ly("""He ran swiftly-fast.""")
assert chk.check_ly("""The not-so-hotly-contested
result was fine.""") == []
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_preferred_forms.py 0000644 0000000 0000000 00000001020 00000000000 017444 0 ustar 00 """Tests for misc.preferred_forms check."""
from proselint.checks.misc import preferred_forms as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.preferred_forms."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.preferred_forms."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""It was almost haloween.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_pretension.py 0000644 0000000 0000000 00000001014 00000000000 016451 0 ustar 00 """Tests for misc.pretension check."""
from proselint.checks.misc import pretension as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.pretension."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.pretension."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""We need to reconceptualize the project.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_professions.py 0000644 0000000 0000000 00000001011 00000000000 016632 0 ustar 00 """Tests for misc.professions check."""
from proselint.checks.misc import professions as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.professions."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.professions."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""I really need a shoe repair guy.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_punctuation.py 0000644 0000000 0000000 00000000772 00000000000 016646 0 ustar 00 """Tests for misc.punctuation check."""
from proselint.checks.misc import punctuation as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.punctuation."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.punctuation."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""See Smith et. al.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_scare_quotes.py 0000644 0000000 0000000 00000001016 00000000000 016762 0 ustar 00 """Tests for misc.scare_quotes check."""
from proselint.checks.misc import scare_quotes as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.scare_quotes."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.scare_quotes."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""What was the 'take-home message'?""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_suddenly.py 0000644 0000000 0000000 00000000771 00000000000 016123 0 ustar 00 """Tests for misc.suddenly check."""
from proselint.checks.misc import suddenly as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.suddenly."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.suddenly."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""Suddenly, it all made sense.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_tense_present.py 0000644 0000000 0000000 00000001017 00000000000 017144 0 ustar 00 """Tests for misc.tense_present check."""
from proselint.checks.misc import tense_present as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.tense_present."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.tense_present."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""I did it on accident honestly.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_usage.py 0000644 0000000 0000000 00000000562 00000000000 015376 0 ustar 00 """Tests for misc.usage check."""
from proselint.checks.misc import usage as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.usage."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.usage."""
pass
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_waxed.py 0000644 0000000 0000000 00000000762 00000000000 015404 0 ustar 00 """Tests for misc.waxed check."""
from proselint.checks.misc import waxed as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.waxed."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.waxed."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""They really could wax poetically.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_misc_whence.py 0000644 0000000 0000000 00000000762 00000000000 015545 0 ustar 00 """Tests for misc.whence check."""
from proselint.checks.misc import whence as chk
from .check import Check
class TestCheck(Check):
"""The test class for misc.whence."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for misc.whence."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""Go back from whence you came!""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_mixed_metaphors.py 0000644 0000000 0000000 00000001542 00000000000 016446 0 ustar 00 """Tests for mixed_metaphors.misc check."""
from proselint.checks.mixed_metaphors import misc as chk
from .check import Check
class TestCheck(Check):
"""The test class for mixed_metaphors.misc."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke_bottleneck(self):
"""Basic smoke test for check_bottleneck."""
assert chk.check_bottleneck(
"""Smoke phrase with nothing flagged.""") == []
assert chk.check_bottleneck(
"""The project produced a huge bottleneck.""") != []
def test_smoke_misc(self):
"""Basic smoke test for check_misc."""
assert chk.check_misc(
"""Smoke phrase with nothing flagged.""") == []
assert chk.check_misc(
"""Writing tests is not rocket surgery.""") != []
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_mondegreens.py 0000644 0000000 0000000 00000001100 00000000000 015552 0 ustar 00 """Tests for mondegreens.misc check."""
from proselint.checks.mondegreens import misc as chk
from .check import Check
class TestCheck(Check):
"""The test class for mondegreens.misc."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for mondegreens.misc."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert self.passes("""... and laid him on the green.""")
assert not self.passes("""..and Lady Mondegreen.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_needless_variants.py 0000644 0000000 0000000 00000001040 00000000000 016760 0 ustar 00 """Tests for needless_variants.misc check."""
from proselint.checks.needless_variants import misc as chk
from .check import Check
class TestCheck(Check):
"""The test class for needless_variants.misc."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for needless_variants.misc."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""It was an extensible telescope.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_nonwords.py 0000644 0000000 0000000 00000000774 00000000000 015135 0 ustar 00 """Tests for nonwords.misc check."""
from proselint.checks.nonwords import misc as chk
from .check import Check
class TestCheck(Check):
"""The test class for nonwords.misc."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for nonwords.misc."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""The test was good irregardless.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_oxymorons.py 0000644 0000000 0000000 00000000775 00000000000 015342 0 ustar 00 """Tests for oxymorons.misc check."""
from proselint.checks.oxymorons import misc as chk
from .check import Check
class TestCheck(Check):
"""The test class for oxymorons.misc."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for oxymorons.misc."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""He needed an exact estimate.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_preferred_forms_check.py 0000644 0000000 0000000 00000002244 00000000000 017577 0 ustar 00 """Test the preferred_forms_check function from the tools.py module."""
from proselint.tools import preferred_forms_check as chk
from .check import Check
class TestCheck(Check):
"""The test class for tools.preferred_forms_check."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def setUp(self):
"""Create some test fixtures."""
self.L = [['use', ['utilize']]]
self.l_caps = [["Stone Age", ["stone age"]]]
self.err = 'error message'
self.msg = 'use the preferred form'
def test_smoke(self):
"""Basic smoke test for preferred_forms_check."""
assert chk(
"We utilize this tech", self.L, self.err, self.msg) != []
assert chk(
"We use this tech", self.L, self.err, self.msg) == []
def test_capitalization(self):
"""Test for preferred forms involving capitalization."""
assert not chk(
"In the stone age", self.l_caps, self.err, self.msg,
ignore_case=False)
assert chk(
"In the Stone Age", self.l_caps, self.err, self.msg,
ignore_case=False) == []
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_psychology.py 0000644 0000000 0000000 00000002405 00000000000 015455 0 ustar 00 """Tests for psychology.misc check."""
from proselint.checks.psychology import misc as chk
from .check import Check
class TestCheck(Check):
"""The test class for psychology.misc."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke_lie_detector_test(self):
"""Basic smoke test for psychology.misc.check_lie_detector_test."""
assert chk.check_lie_detector_test(
"""Smoke phrase with nothing flagged.""") == []
assert chk.check_lie_detector_test(
"""The defendant took a lie detector test.""") != []
def test_smoke_p_equals_zero(self):
"""Basic smoke test for psychology.misc.check_p_equals_zero."""
assert chk.check_p_equals_zero(
"""Smoke phrase with nothing flagged.""") == []
assert chk.check_p_equals_zero(
"""The effect was highly signficant at p = 0.00.""") != []
def test_smoke_mental_telepathy(self):
"""Basic smoke test for psychology.misc.check_mental_telepathy."""
assert chk.check_mental_telepathy(
"""Smoke phrase with nothing flagged.""") == []
assert chk.check_mental_telepathy(
"""I've been practicing mental telepathy.""") != []
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_redundancy_misc.py 0000644 0000000 0000000 00000002576 00000000000 016435 0 ustar 00 """Tests for redundancy.misc check."""
from proselint.checks.redundancy import misc as chk
from .check import Check
class TestCheck(Check):
"""The test class for redundancy.misc."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke_check(self):
"""Basic smoke test for redundancy.misc.check."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""The table was rectangular in shape.""")
def test_smoke_garner(self):
"""Basic smoke test for redundancy.misc.check_garner."""
assert chk.check_garner(
"""Smoke phrase with nothing flagged.""") == []
assert chk.check_garner(
"""It was blatantly obvious what to do next.""") != []
def test_smoke_nordquist(self):
"""Basic smoke test for redundancy.misc.check_norquist."""
assert chk.check_nordquist(
"""Smoke phrase with nothing flagged.""") == []
assert chk.check_nordquist(
"""Taking the package was absolutely essential.""") != []
def test_smoke_atd(self):
"""Basic smoke test for redundancy.misc.check_norquist."""
assert chk.check_atd(
"""Smoke phrase with nothing flagged.""") == []
assert chk.check_atd(
"""He often repeated the old adage.""") != []
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_redundancy_ras_syndrome.py 0000644 0000000 0000000 00000001042 00000000000 020172 0 ustar 00 """Tests for redundancy.ras_syndrome check."""
from proselint.checks.redundancy import ras_syndrome as chk
from .check import Check
class TestCheck(Check):
"""The test class for redundancy.ras_syndrome."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for redundancy.ras_syndrome."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""Please enter your PIN number.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_security_credit_card.py 0000644 0000000 0000000 00000001156 00000000000 017451 0 ustar 00 """Tests for security.credit_card check."""
from proselint.checks.security import credit_card as chk
from .check import Check
class TestCheck(Check):
"""The test class for security.credit_card."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for security.credit_card.
This makes use of a test MasterCard number.
"""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes(
"""My credit card number is 5555555555554444.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_security_password.py 0000644 0000000 0000000 00000001103 00000000000 017040 0 ustar 00 """Tests for security.password check."""
from proselint.checks.security import password as chk
from .check import Check
class TestCheck(Check):
"""The test class for security.password."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for security.password."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""The password is 123456.""")
assert not self.passes("""My password is PASSWORD.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_sexism.py 0000644 0000000 0000000 00000001023 00000000000 014560 0 ustar 00 """Tests for sexism.misc check."""
from proselint.checks.sexism import misc as chk
from .check import Check
class TestCheck(Check):
"""The test class for sexism.misc."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for sexism.misc."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes(
"""The legal team had two lawyers and a lady lawyer.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_skunked_terms.py 0000644 0000000 0000000 00000001056 00000000000 016134 0 ustar 00 """Tests for skunked_terms.misc check."""
from proselint.checks.skunked_terms import misc as chk
from .check import Check
class TestCheck(Check):
"""The test class for skunked_terms.misc."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for skunked_terms.misc."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes(
"""I gave an impassionate defence of the situation.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_spelling_able_atable.py 0000644 0000000 0000000 00000001037 00000000000 017365 0 ustar 00 """Tests for spelling.able_atable check."""
from proselint.checks.spelling import able_atable as chk
from .check import Check
class TestCheck(Check):
"""The test class for spelling.able_atable."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for spelling.able_atable."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""There was a demonstratable difference.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_spelling_able_ible.py 0000644 0000000 0000000 00000001014 00000000000 017043 0 ustar 00 """Tests for spelling.able_ible check."""
from proselint.checks.spelling import able_ible as chk
from .check import Check
class TestCheck(Check):
"""The test class for spelling.able_ible."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for spelling.able_ible."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""It was a sensable decision.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_spelling_athletes.py 0000644 0000000 0000000 00000001013 00000000000 016755 0 ustar 00 """Tests for spelling.athletes check."""
from proselint.checks.spelling import athletes as chk
from .check import Check
class TestCheck(Check):
"""The test class for spelling.athletes."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for spelling.athletes."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""One of the greats: Cal Ripkin.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_spelling_em_im_en_in.py 0000644 0000000 0000000 00000001025 00000000000 017405 0 ustar 00 """Tests for spelling.em_im_en_in check."""
from proselint.checks.spelling import em_im_en_in as chk
from .check import Check
class TestCheck(Check):
"""The test class for spelling.em_im_en_in."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for spelling.em_im_en_in."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""We shall imbark on a voyage.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_spelling_er_or.py 0000644 0000000 0000000 00000000773 00000000000 016266 0 ustar 00 """Tests for spelling.er_or check."""
from proselint.checks.spelling import er_or as chk
from .check import Check
class TestCheck(Check):
"""The test class for spelling.er_or."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for spelling.er_or."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""She met with the invester.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_spelling_in_un.py 0000644 0000000 0000000 00000000771 00000000000 016266 0 ustar 00 """Tests for spelling.in_un check."""
from proselint.checks.spelling import in_un as chk
from .check import Check
class TestCheck(Check):
"""The test class for spelling.in_un."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for spelling.in_un."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""The plan was unfeasible.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_spelling_misc.py 0000644 0000000 0000000 00000000756 00000000000 016114 0 ustar 00 """Tests for spelling.misc check."""
from proselint.checks.spelling import misc as chk
from .check import Check
class TestCheck(Check):
"""The test class for spelling.misc."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for spelling.misc."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""I like this alot.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_strunk_white_eos.py 0000644 0000000 0000000 00000001303 00000000000 016645 0 ustar 00 """Unit tests for strunk_white_eos."""
# from __future__ import absolute_import
# from .check import Check
# from proselint.checks.strunkwhite import elementary_composition as chk
# class TestCheck(Check):
# """Define the suite of checks."""
# __test__ = True
# @property
# def this_check(self):
# return chk
# def test_with_utilized(self):
# """Don't produce an error when 'use' is used correctly."""
# assert self.check("I use a hammer to drive nails into wood.")
# def test_no_utilized(self):
# """Produce an error when 'utilize' is used in place of 'use'."""
# assert not self.check("I utilize a hammer to drive nails into wood.")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_terms_animal_adjectives.py 0000644 0000000 0000000 00000001044 00000000000 020127 0 ustar 00 """Tests for terms.animal_adjectives check."""
from proselint.checks.terms import animal_adjectives as chk
from .check import Check
class TestCheck(Check):
"""The test class for terms.animal_adjectives."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for terms.animal_adjectives."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""It was some bird-like creature.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_terms_denizen_labels.py 0000644 0000000 0000000 00000001032 00000000000 017440 0 ustar 00 """Tests for terms.denizen_labels check."""
from proselint.checks.terms import denizen_labels as chk
from .check import Check
class TestCheck(Check):
"""The test class for terms.denizen_labels."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for terms.denizen_labels."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""He was definitely a Hong Kongite.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_terms_eponymous_adjectives.py 0000644 0000000 0000000 00000001062 00000000000 020724 0 ustar 00 """Tests for terms.eponymous_adjectives check."""
from proselint.checks.terms import eponymous_adjectives as chk
from .check import Check
class TestCheck(Check):
"""The test class for terms.eponymous_adjectives."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for terms.eponymous_adjectives."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""The writing wasn't Shakespearian.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_terms_venery.py 0000644 0000000 0000000 00000000771 00000000000 016003 0 ustar 00 """Tests for terms.venery check."""
from proselint.checks.terms import venery as chk
from .check import Check
class TestCheck(Check):
"""The test class for terms.venery."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for terms.venery."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""There was a group of alligators.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_tools.py 0000644 0000000 0000000 00000002174 00000000000 014420 0 ustar 00 """Test the tools module."""
from proselint.config import default
from proselint.tools import lint as proselint, load_options
from .check import Check
def lint(text):
return proselint(text, config=load_options(conf_default=default))
class TestLint(Check):
"""The test class for tools.lint."""
__test__ = True
def setUp(self):
"""setUp method creating text fixtures."""
self.text = """But this is a very bad sentence.
This is also a no-good sentence.
"""
self.text_with_no_newline = """A very bad sentence."""
def extract_line_col(self, error):
"""Extract the line and column number from an error tuple."""
_, _, line, column, _, _, _, _, _ = error
return line, column
def test_errors_sorted(self):
"""Test that errors are sorted by line and column number."""
lines_and_cols = [self.extract_line_col(e) for e in lint(self.text)]
assert sorted(lines_and_cols) == lines_and_cols
def test_on_no_newlines(self):
"""Test that lint works on text without a terminal newline."""
assert len(lint(self.text_with_no_newline)) == 1
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_topic_detector.py 0000644 0000000 0000000 00000001305 00000000000 016262 0 ustar 00 """Test the topic detector tool."""
from proselint.tools import topics
def test_50_Cent_detector_on_topic():
"""Check precision of the 50 Cent topic-detector."""
text = """With the aid of Eminem and Dr. Dre (who produced his first
major-label album, Get Rich or Die Tryin'), Jackson became one
of the world's best selling rappers and rose to prominence with
East Coast hip hop group G-Unit (which he leads de facto). """
assert("50 Cent" in topics(text))
text = """Hip hop was started in the early 50's."""
assert("50 Cent" not in topics(text))
text = """Nowadays it costs 50 cents to buy a lollipop."""
assert("50 Cent" not in topics(text))
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_typography_diacritical_marks.py 0000644 0000000 0000000 00000001073 00000000000 021210 0 ustar 00 """Tests for typography.diacritical_marks check."""
from proselint.checks.typography import diacritical_marks as chk
from .check import Check
class TestCheck(Check):
"""The test class for typography.diacritical_marks."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for typography.diacritical_marks."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""He saw the performance by Beyonce.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_typography_exclamation.py 0000644 0000000 0000000 00000002006 00000000000 020044 0 ustar 00 """Tests for typography.exclamation check."""
from proselint.checks.typography import exclamation as chk
from .check import Check
class TestCheck(Check):
"""The test class for typography.exclamation."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke_repeated_exclamations(self):
"""Basic smoke test.
Test for typography.exclamation.check_repeated_exclamations.
"""
assert chk.check_repeated_exclamations(
"""Smoke phrase with nothing flagged.""") == []
assert chk.check_repeated_exclamations(
"""I'm really excited!!""") != []
def test_smoke_exclamations_ppm(self):
"""Basic smoke test.
Test for typography.exclamation.check_exclamations_ppm.
"""
assert chk.check_exclamations_ppm(
"""Smoke phrase with nothing flagged.""") == []
assert chk.check_exclamations_ppm(
"""I'm really excited! Really!""") != []
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_typography_symbols.py 0000644 0000000 0000000 00000003535 00000000000 017240 0 ustar 00 """Test Butterick's symbols."""
from proselint.checks.typography import symbols as chk
from .check import Check
class TestCheck(Check):
"""The test class for typography.symbols."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_ellipsis(self):
"""Find ... in a string."""
assert chk.check_ellipsis("""The long and winding road...""")
def test_copyright(self):
"""Find a (c) or (C) in a string."""
assert chk.check_copyright_symbol("""Show me the money! (C)""")
assert chk.check_copyright_symbol("""Show me the money! (c)""")
def test_trademark(self):
"""Find a (TM) or (tm) in a string."""
assert chk.check_trademark_symbol("""The Fresh Maker (TM)""")
assert chk.check_trademark_symbol("""The Fresh Maker (tm)""")
def test_registered_trademark(self):
"""Find a (r) or (R) in a string."""
assert chk.check_registered_trademark_symbol("""Just Do It (R)""")
assert chk.check_registered_trademark_symbol("""Just Do It (r)""")
def test_sentence_spacing(self):
"""Find a sentence followed by three or more spaces."""
assert chk.check_sentence_spacing(
"""This is a sentence. This is another.""")
def test_multiplication(self):
"""Find an x between two digits."""
assert chk.check_multiplication_symbol(
"""It is obvious that 2 x 2 = 4.""")
def test_curly_quotes(self): # FIXME
"""Find "" quotes in a string."""
assert chk.check_curly_quotes(
"\"This should produce an error\", he said.")
assert not chk.check_curly_quotes("But this should not.")
assert chk.check_curly_quotes("Alas, \"it should here too\".")
assert not chk.check_curly_quotes("\"A singular should not, though.")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_uncomparables.py 0000644 0000000 0000000 00000002004 00000000000 016103 0 ustar 00 """Test uncomparables.misc"""
from proselint.checks.uncomparables import misc as chk
from .check import Check
class TestCheck(Check):
"""The test class for uncomparables.misc."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for uncomparables.misc."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""The item was more unique.""")
def test_sample_phrases(self):
"""Find 'very unique'."""
assert not self.passes("""This sentence is very unique.""")
def test_spaces(self):
"""Handle spacing correctly."""
assert not self.passes("""This sentence is very\nunique.""")
assert not self.passes("""Kind of complete.""")
assert self.passes("""Every perfect instance.""")
def test_constitutional(self):
"""Don't flag exceptions."""
assert self.passes("""A more perfect union.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_weasel_words_misc.py 0000644 0000000 0000000 00000000771 00000000000 016772 0 ustar 00 """Tests for weasel_words.misc check."""
from proselint.checks.weasel_words import misc as chk
from .check import Check
class TestCheck(Check):
"""The test class for weasel_words.misc."""
__test__ = False
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for weasel_words.misc."""
assert self.passes("""Smoke phrase with nothing flagged.""")
# TODO: add test when check is implemented
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250509.1908228
proselint-0.13.0/tests/test_weasel_words_very.py 0000644 0000000 0000000 00000001013 00000000000 017012 0 ustar 00 """Tests for weasel_words.very check."""
from proselint.checks.weasel_words import very as chk
from .check import Check
class TestCheck(Check):
"""The test class for weasel_words.very."""
__test__ = True
@property
def this_check(self):
"""Boilerplate."""
return chk
def test_smoke(self):
"""Basic smoke test for weasel_words.very."""
assert self.passes("""Smoke phrase with nothing flagged.""")
assert not self.passes("""The book was very interesting.""")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636250523.3928878
proselint-0.13.0/setup.py 0000644 0000000 0000000 00000032515 00000000000 012221 0 ustar 00 # -*- coding: utf-8 -*-
from setuptools import setup
packages = \
['proselint',
'proselint.checks',
'proselint.checks.airlinese',
'proselint.checks.annotations',
'proselint.checks.archaism',
'proselint.checks.cliches',
'proselint.checks.consistency',
'proselint.checks.corporate_speak',
'proselint.checks.cursing',
'proselint.checks.dates_times',
'proselint.checks.hedging',
'proselint.checks.hyperbole',
'proselint.checks.inprogress',
'proselint.checks.jargon',
'proselint.checks.lexical_illusions',
'proselint.checks.lgbtq',
'proselint.checks.links',
'proselint.checks.malapropisms',
'proselint.checks.misc',
'proselint.checks.mixed_metaphors',
'proselint.checks.mondegreens',
'proselint.checks.needless_variants',
'proselint.checks.nonwords',
'proselint.checks.oxymorons',
'proselint.checks.psychology',
'proselint.checks.redundancy',
'proselint.checks.security',
'proselint.checks.sexism',
'proselint.checks.skunked_terms',
'proselint.checks.spelling',
'proselint.checks.terms',
'proselint.checks.typography',
'proselint.checks.uncomparables',
'proselint.checks.weasel_words']
package_data = \
{'': ['*']}
install_requires = \
['click>=8.0.0,<9.0.0', 'future>=0.18.2,<0.19.0', 'six>=1.15.0,<2.0.0']
entry_points = \
{'console_scripts': ['proselint = proselint.command_line:proselint']}
setup_kwargs = {
'name': 'proselint',
'version': '0.13.0',
'description': 'A linter for prose.',
'long_description': '
\n\n\n[](https://houndci.com)\n[](https://codeclimate.com/repos/5538989ee30ba0793100090f/feed)\n[](https://codecov.io/gh/amperser/proselint)\n[](https://en.wikipedia.org/wiki/BSD_licenses)\n\nWriting is notoriously hard, even for the best writers, and it\'s not for lack of good advice — a tremendous amount of knowledge about the craft is strewn across usage guides, dictionaries, technical manuals, essays, pamphlets, websites, and the hearts and minds of great authors and editors. But poring over Strunk & White hardly makes one a better writer — it turns you into neither Strunk nor White. And nobody has the capacity to apply all the advice from *Garner’s Modern English Usage*, an 1100-page usage guide, to everything they write. In fact, the whole notion that one becomes a better writer by reading advice on writing rests on untenable assumptions about learning and memory. The traditional formats of knowledge about writing are thus essentially inert, waiting to be transformed.\n\nWe devised a simple solution: `proselint`, a linter for English prose. A linter is a computer program that, akin to a spell checker, scans through a file and detects issues — like how a real lint roller helps you get unwanted lint off of your shirt.\n\n`proselint` places the world\'s greatest writers and editors by your side, where they whisper suggestions on how to improve your prose. You’ll be guided by advice inspired by Bryan Garner, David Foster Wallace, Chuck Palahniuk, Steve Pinker, Mary Norris, Mark Twain, Elmore Leonard, George Orwell, Matthew Butterick, William Strunk, Elwyn White, Philip Corbett, Ernest Gowers, and the editorial staff of the world’s finest literary magazines and newspapers, among others. Our goal is to aggregate knowledge about best practices in writing and to make that knowledge immediately accessible to all authors in the form of a linter for prose; all in a neat command-line utility that you can integrate into other tools, scripts, and workflows.\n\n### Installation\n\nTo get this up and running, install it using [pip]:\n\n```bash\npip install proselint\n```\n\n[pip]: https://packaging.python.org/installing/#use-pip-for-installing\n\n#### Fedora\n\n```bash\nsudo dnf install proselint\n```\n\n#### Debian\n\n```bash\nsudo apt install python3-proselint\n```\n\n#### Ubuntu\n\n```bash\nsudo add-apt-repository universe\nsudo apt install python3-proselint\n```\n\n### Plugins for other software\n\n`proselint` is available on:\n\n- A [demo editor](http://proselint.com/write)\n- [Sublime Text](https://github.com/amperser/proselint/tree/main/plugins/sublime/SublimeLinter-contrib-proselint)\n- [Atom Editor](https://github.com/smockle/linter-proselint) (thanks to [Clay Miller](https://github.com/smockle)).\n- [Emacs via Flycheck](http://www.flycheck.org/).\n- Vim via [ALE](https://github.com/w0rp/ale) or [Syntastic](https://github.com/vim-syntastic/syntastic) (thanks to @lcd047, @Carreau, and [Daniel M. Capella](https://github.com/polyzen))\n- [Phabricator\'s `arc` CLI](https://github.com/google/arc-proselint) (thanks to [Jeff Verkoeyen](https://github.com/jverkoey))\n- [Danger](https://github.com/dbgrandi/danger-prose) (thanks to [David Grandinetti](https://github.com/dbgrandi) and [Orta Therox](https://github.com/orta))\n- [Visual Studio Code](https://github.com/ppeszko/vscode-proselint) (thanks to [Patryk Peszko](https://github.com/ppeszko))\n- [coala](https://github.com/coala-analyzer/bear-docs/blob/master/docs/ProseLintBear.rst) (thanks to the [coala Development Group](https://github.com/coala-analyzer))\n- [IntelliJ](https://github.com/kropp/intellij-proselint) (by [Victor Kropp](https://github.com/kropp))\n- [pre-commit](https://pre-commit.com/) (by [Andy Airey](https://github.com/aairey))\n- [Statick](https://github.com/sscpac/statick-md)\n\n### Usage\n\nSuppose you have a document `text.md` with the following text:\n\n```\nJohn is very unique.\n```\n\nYou can run `proselint` over the document using the command line:\n\n```bash\nproselint text.md\n```\n\nThis prints a list of suggestions to stdout, one per line. Each suggestion has the form:\n\n```bash\ntext.md::: \n```\n\nFor example,\n\n```bash\ntext.md:0:10: wallace.uncomparables Comparison of an uncomparable: \'unique\' cannot be compared.\n```\n\nThe command-line utility can also print suggestions in JSON using the `--json` flag. In this case, the output is considerably richer:\n\n```jsonc\n{\n // Type of check that output this suggestion.\n check: "wallace.uncomparables",\n\n // Message to describe the suggestion.\n message: "Comparison of an uncomparable: \'unique\' cannot be compared.",\n\n // The person or organization giving the suggestion.\n source: "David Foster Wallace"\n\n // URL pointing to the source material.\n source_url: "http://www.telegraph.co.uk/a/9715551"\n\n // Line where the error starts.\n line: 0,\n\n // Column where the error starts.\n column: 10,\n\n // Index in the text where the error starts.\n start: 10,\n\n // Index in the text where the error ends.\n end: 21,\n\n // length from start -> end\n extent: 11,\n\n // How important is this? Can be "suggestion", "warning", or "error".\n severity: "warning",\n\n // Possible replacements.\n replacements: [\n {\n value: "unique"\n }\n ]\n}\n```\n\nTo run the linter as part of another Python program, you can use the `lint` function in `proselint.tools`:\n\n```python\nimport proselint\n\nsuggestions = proselint.tools.lint("This sentence is very unique")\n```\n\nThis will return a list of suggestions:\n\n```python\n[(\'weasel_words.very\', "Substitute \'damn\' every time you\'re inclined to write \'very;\' your editor will delete it and the writing will be just as it should be.", 0, 17, 17, 22, 5, \'warning\', None), (\'uncomparables.misc\', "Comparison of an uncomparable: \'very unique.\' is not comparable.", 0, 17, 17, 29, 12, \'warning\', None)]\n```\n\n### Checks\n\nYou can disable any of the checks by modifying `$XDG_CONFIG_HOME/proselint/config`. If `$XDG_CONFIG_HOME` is not set or empty, `~/.config/proselint/config` will be used. Additionally, for compatibility reasons, the legacy configuration `~/.proselintrc` will be checked if `$XDG_CONFIG_HOME/proselint/config` does not exist.\n\n```json\n{\n "checks": {\n "typography.diacritical_marks": false\n }\n}\n```\n\n| ID | Description |\n| ----- | --------------- |\n| `airlinese.misc` | Avoiding jargon of the airline industry |\n| `annotations.misc` | Catching annotations left in the text |\n| `archaism.misc` | Avoiding archaic forms |\n| `cliches.hell` | Avoiding a common cliché |\n| `cliches.misc` | Avoiding clichés |\n| `consistency.spacing` | Consistent sentence spacing |\n| `consistency.spelling` | Consistent spelling |\n| `corporate_speak.misc` | Avoiding corporate buzzwords |\n| `cursing.filth` | Words to avoid |\n| `cursing.nfl` | Avoiding words banned by the NFL |\n| `dates_times.am_pm` | Using the right form for the time of day |\n| `dates_times.dates` | Stylish formatting of dates |\n| `hedging.misc` | Not hedging |\n| `hyperbole.misc` | Not being hyperbolic |\n| `jargon.misc` | Avoiding miscellaneous jargon |\n| `lgbtq.offensive_terms` | Avoding offensive LGBTQ terms |\n| `lgbtq.terms` | Misused LGBTQ terms |\n| `lexical_illusions.misc` | Avoiding lexical illusions |\n| `links.broken` | Linking only to existing sites |\n| `malapropisms.misc` | Avoiding common malapropisms |\n| `misc.apologizing` | Being confident |\n| `misc.back_formations` | Avoiding needless backformations |\n| `misc.bureaucratese` | Avoiding bureaucratese |\n| `misc.but` | Avoid starting a paragraph with "But..." |\n| `misc.capitalization` | Capitalizing only what ought to be capitalized |\n| `misc.chatspeak` | Avoiding lolling and other chatspeak |\n| `misc.commercialese` | Avoiding jargon of the commercial world |\n| `misc.currency` | Avoiding redundant currency symbols |\n| `misc.debased` | Avoiding debased language |\n| `misc.false_plurals` | Avoiding false plurals |\n| `misc.illogic` | Avoiding illogical forms |\n| `misc.inferior_superior` | Superior to, not than |\n| `misc.latin` | Avoiding overuse of Latin phrases |\n| `misc.many_a` | Many a singular |\n| `misc.metaconcepts` | Avoiding overuse of metaconcepts |\n| `misc.narcissism` | Talking about the subject, not its study |\n| `misc.phrasal_adjectives` | Hyphenating phrasal adjectives |\n| `misc.preferred_forms` | Miscellaneous preferred forms |\n| `misc.pretension` | Avoiding being pretentious |\n| `misc.professions` | Calling jobs by the right name |\n| `misc.punctuation` | Using punctuation assiduously |\n| `misc.scare_quotes` | Using scare quotes only when needed |\n| `misc.suddenly` | Avoiding the word suddenly |\n| `misc.tense_present` | Advice from Tense Present |\n| `misc.waxed` | Waxing poetic |\n| `misc.whence` | Using "whence" |\n| `mixed_metaphors.misc` | Not mixing metaphors |\n| `mondegreens.misc` | Avoiding mondegreen |\n| `needless_variants.misc` | Using the preferred form |\n| `nonwords.misc` | Avoid using nonwords |\n| `oxymorons.misc` | Avoiding oxymorons |\n| `psychology.misc` | Avoiding misused psychological terms |\n| `redundancy.misc` | Avoiding redundancy and saying things twice |\n| `redundancy.ras_syndrome` | Avoiding RAS syndrome |\n| `skunked_terms.misc` | Avoid using skunked terms |\n| `spelling.able_atable` | -able vs. -atable |\n| `spelling.able_ible` | -able vs. -ible |\n| `spelling.athletes` | Spelling of athlete names |\n| `spelling.em_im_en_in` | -em vs. -im and -en vs. -in |\n| `spelling.er_or` | -er vs. -or |\n| `spelling.in_un` | in- vs. un- |\n| `spelling.misc` | Spelling words corectly |\n| `security.credit_card` | Keeping credit card numbers secret |\n| `security.password` | Keeping passwords secret |\n| `sexism.misc` | Avoiding sexist language |\n| `terms.animal_adjectives` | Animal adjectives |\n| `terms.denizen_labels` | Calling denizens by the right name |\n| `terms.eponymous_adjectives` | Calling people by the right name |\n| `terms.venery` | Call groups of animals by the right name |\n| `typography.diacritical_marks` | Using dïacríticâl marks |\n| `typography.exclamation` | Avoiding overuse of exclamation |\n| `typography.symbols` | Using the right symbols |\n| `uncomparables.misc` | Not comparing uncomparables |\n| `weasel_words.misc` | Avoiding weasel words |\n| `weasel_words.very` | Avoiding the word "very" |\n\n### Contributing\n\nInterested in contributing to `proselint`? Great — there are plenty of ways you can help. Read more on [our website], where we describe how you can help us build `proselint` into the greatest writing tool in the world.\n\n- [Issue Tracker](http://github.com/amperser/proselint/issues)\n- [Source Code](http://github.com/amperser/proselint)\n\n[our website]: http://proselint.com/contributing/\n\n### Support\n\nIf you run into a problem, please [open an issue](http://github.com/amperser/proselint/issues) in or send an email to hello@amperser.com.\n\n### Running Automated Tests\n\nAutomated tests are included in the `proselint/tests` directory. To run these tests locally, you can use `./utils`.\n\n### License\n\nThe project is licensed under the BSD license.\n',
'author': 'Amperser Labs',
'author_email': 'hello@amperser.com',
'maintainer': None,
'maintainer_email': None,
'url': 'https://proselint.com',
'packages': packages,
'package_data': package_data,
'install_requires': install_requires,
'entry_points': entry_points,
'python_requires': '>=3.6.1,<4.0.0',
}
setup(**setup_kwargs)
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1636250523.393498
proselint-0.13.0/PKG-INFO 0000644 0000000 0000000 00000030105 00000000000 011575 0 ustar 00 Metadata-Version: 2.1
Name: proselint
Version: 0.13.0
Summary: A linter for prose.
Home-page: https://proselint.com
License: BSD-3-Clause
Author: Amperser Labs
Author-email: hello@amperser.com
Requires-Python: >=3.6.1,<4.0.0
Classifier: License :: OSI Approved :: BSD License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: Implementation :: CPython
Requires-Dist: click (>=8.0.0,<9.0.0)
Requires-Dist: future (>=0.18.2,<0.19.0)
Requires-Dist: six (>=1.15.0,<2.0.0)
Project-URL: Repository, https://github.com/amperser/proselint
Description-Content-Type: text/markdown

[](https://houndci.com)
[](https://codeclimate.com/repos/5538989ee30ba0793100090f/feed)
[](https://codecov.io/gh/amperser/proselint)
[](https://en.wikipedia.org/wiki/BSD_licenses)
Writing is notoriously hard, even for the best writers, and it's not for lack of good advice — a tremendous amount of knowledge about the craft is strewn across usage guides, dictionaries, technical manuals, essays, pamphlets, websites, and the hearts and minds of great authors and editors. But poring over Strunk & White hardly makes one a better writer — it turns you into neither Strunk nor White. And nobody has the capacity to apply all the advice from *Garner’s Modern English Usage*, an 1100-page usage guide, to everything they write. In fact, the whole notion that one becomes a better writer by reading advice on writing rests on untenable assumptions about learning and memory. The traditional formats of knowledge about writing are thus essentially inert, waiting to be transformed.
We devised a simple solution: `proselint`, a linter for English prose. A linter is a computer program that, akin to a spell checker, scans through a file and detects issues — like how a real lint roller helps you get unwanted lint off of your shirt.
`proselint` places the world's greatest writers and editors by your side, where they whisper suggestions on how to improve your prose. You’ll be guided by advice inspired by Bryan Garner, David Foster Wallace, Chuck Palahniuk, Steve Pinker, Mary Norris, Mark Twain, Elmore Leonard, George Orwell, Matthew Butterick, William Strunk, Elwyn White, Philip Corbett, Ernest Gowers, and the editorial staff of the world’s finest literary magazines and newspapers, among others. Our goal is to aggregate knowledge about best practices in writing and to make that knowledge immediately accessible to all authors in the form of a linter for prose; all in a neat command-line utility that you can integrate into other tools, scripts, and workflows.
### Installation
To get this up and running, install it using [pip]:
```bash
pip install proselint
```
[pip]: https://packaging.python.org/installing/#use-pip-for-installing
#### Fedora
```bash
sudo dnf install proselint
```
#### Debian
```bash
sudo apt install python3-proselint
```
#### Ubuntu
```bash
sudo add-apt-repository universe
sudo apt install python3-proselint
```
### Plugins for other software
`proselint` is available on:
- A [demo editor](http://proselint.com/write)
- [Sublime Text](https://github.com/amperser/proselint/tree/main/plugins/sublime/SublimeLinter-contrib-proselint)
- [Atom Editor](https://github.com/smockle/linter-proselint) (thanks to [Clay Miller](https://github.com/smockle)).
- [Emacs via Flycheck](http://www.flycheck.org/).
- Vim via [ALE](https://github.com/w0rp/ale) or [Syntastic](https://github.com/vim-syntastic/syntastic) (thanks to @lcd047, @Carreau, and [Daniel M. Capella](https://github.com/polyzen))
- [Phabricator's `arc` CLI](https://github.com/google/arc-proselint) (thanks to [Jeff Verkoeyen](https://github.com/jverkoey))
- [Danger](https://github.com/dbgrandi/danger-prose) (thanks to [David Grandinetti](https://github.com/dbgrandi) and [Orta Therox](https://github.com/orta))
- [Visual Studio Code](https://github.com/ppeszko/vscode-proselint) (thanks to [Patryk Peszko](https://github.com/ppeszko))
- [coala](https://github.com/coala-analyzer/bear-docs/blob/master/docs/ProseLintBear.rst) (thanks to the [coala Development Group](https://github.com/coala-analyzer))
- [IntelliJ](https://github.com/kropp/intellij-proselint) (by [Victor Kropp](https://github.com/kropp))
- [pre-commit](https://pre-commit.com/) (by [Andy Airey](https://github.com/aairey))
- [Statick](https://github.com/sscpac/statick-md)
### Usage
Suppose you have a document `text.md` with the following text:
```
John is very unique.
```
You can run `proselint` over the document using the command line:
```bash
proselint text.md
```
This prints a list of suggestions to stdout, one per line. Each suggestion has the form:
```bash
text.md:::
```
For example,
```bash
text.md:0:10: wallace.uncomparables Comparison of an uncomparable: 'unique' cannot be compared.
```
The command-line utility can also print suggestions in JSON using the `--json` flag. In this case, the output is considerably richer:
```jsonc
{
// Type of check that output this suggestion.
check: "wallace.uncomparables",
// Message to describe the suggestion.
message: "Comparison of an uncomparable: 'unique' cannot be compared.",
// The person or organization giving the suggestion.
source: "David Foster Wallace"
// URL pointing to the source material.
source_url: "http://www.telegraph.co.uk/a/9715551"
// Line where the error starts.
line: 0,
// Column where the error starts.
column: 10,
// Index in the text where the error starts.
start: 10,
// Index in the text where the error ends.
end: 21,
// length from start -> end
extent: 11,
// How important is this? Can be "suggestion", "warning", or "error".
severity: "warning",
// Possible replacements.
replacements: [
{
value: "unique"
}
]
}
```
To run the linter as part of another Python program, you can use the `lint` function in `proselint.tools`:
```python
import proselint
suggestions = proselint.tools.lint("This sentence is very unique")
```
This will return a list of suggestions:
```python
[('weasel_words.very', "Substitute 'damn' every time you're inclined to write 'very;' your editor will delete it and the writing will be just as it should be.", 0, 17, 17, 22, 5, 'warning', None), ('uncomparables.misc', "Comparison of an uncomparable: 'very unique.' is not comparable.", 0, 17, 17, 29, 12, 'warning', None)]
```
### Checks
You can disable any of the checks by modifying `$XDG_CONFIG_HOME/proselint/config`. If `$XDG_CONFIG_HOME` is not set or empty, `~/.config/proselint/config` will be used. Additionally, for compatibility reasons, the legacy configuration `~/.proselintrc` will be checked if `$XDG_CONFIG_HOME/proselint/config` does not exist.
```json
{
"checks": {
"typography.diacritical_marks": false
}
}
```
| ID | Description |
| ----- | --------------- |
| `airlinese.misc` | Avoiding jargon of the airline industry |
| `annotations.misc` | Catching annotations left in the text |
| `archaism.misc` | Avoiding archaic forms |
| `cliches.hell` | Avoiding a common cliché |
| `cliches.misc` | Avoiding clichés |
| `consistency.spacing` | Consistent sentence spacing |
| `consistency.spelling` | Consistent spelling |
| `corporate_speak.misc` | Avoiding corporate buzzwords |
| `cursing.filth` | Words to avoid |
| `cursing.nfl` | Avoiding words banned by the NFL |
| `dates_times.am_pm` | Using the right form for the time of day |
| `dates_times.dates` | Stylish formatting of dates |
| `hedging.misc` | Not hedging |
| `hyperbole.misc` | Not being hyperbolic |
| `jargon.misc` | Avoiding miscellaneous jargon |
| `lgbtq.offensive_terms` | Avoding offensive LGBTQ terms |
| `lgbtq.terms` | Misused LGBTQ terms |
| `lexical_illusions.misc` | Avoiding lexical illusions |
| `links.broken` | Linking only to existing sites |
| `malapropisms.misc` | Avoiding common malapropisms |
| `misc.apologizing` | Being confident |
| `misc.back_formations` | Avoiding needless backformations |
| `misc.bureaucratese` | Avoiding bureaucratese |
| `misc.but` | Avoid starting a paragraph with "But..." |
| `misc.capitalization` | Capitalizing only what ought to be capitalized |
| `misc.chatspeak` | Avoiding lolling and other chatspeak |
| `misc.commercialese` | Avoiding jargon of the commercial world |
| `misc.currency` | Avoiding redundant currency symbols |
| `misc.debased` | Avoiding debased language |
| `misc.false_plurals` | Avoiding false plurals |
| `misc.illogic` | Avoiding illogical forms |
| `misc.inferior_superior` | Superior to, not than |
| `misc.latin` | Avoiding overuse of Latin phrases |
| `misc.many_a` | Many a singular |
| `misc.metaconcepts` | Avoiding overuse of metaconcepts |
| `misc.narcissism` | Talking about the subject, not its study |
| `misc.phrasal_adjectives` | Hyphenating phrasal adjectives |
| `misc.preferred_forms` | Miscellaneous preferred forms |
| `misc.pretension` | Avoiding being pretentious |
| `misc.professions` | Calling jobs by the right name |
| `misc.punctuation` | Using punctuation assiduously |
| `misc.scare_quotes` | Using scare quotes only when needed |
| `misc.suddenly` | Avoiding the word suddenly |
| `misc.tense_present` | Advice from Tense Present |
| `misc.waxed` | Waxing poetic |
| `misc.whence` | Using "whence" |
| `mixed_metaphors.misc` | Not mixing metaphors |
| `mondegreens.misc` | Avoiding mondegreen |
| `needless_variants.misc` | Using the preferred form |
| `nonwords.misc` | Avoid using nonwords |
| `oxymorons.misc` | Avoiding oxymorons |
| `psychology.misc` | Avoiding misused psychological terms |
| `redundancy.misc` | Avoiding redundancy and saying things twice |
| `redundancy.ras_syndrome` | Avoiding RAS syndrome |
| `skunked_terms.misc` | Avoid using skunked terms |
| `spelling.able_atable` | -able vs. -atable |
| `spelling.able_ible` | -able vs. -ible |
| `spelling.athletes` | Spelling of athlete names |
| `spelling.em_im_en_in` | -em vs. -im and -en vs. -in |
| `spelling.er_or` | -er vs. -or |
| `spelling.in_un` | in- vs. un- |
| `spelling.misc` | Spelling words corectly |
| `security.credit_card` | Keeping credit card numbers secret |
| `security.password` | Keeping passwords secret |
| `sexism.misc` | Avoiding sexist language |
| `terms.animal_adjectives` | Animal adjectives |
| `terms.denizen_labels` | Calling denizens by the right name |
| `terms.eponymous_adjectives` | Calling people by the right name |
| `terms.venery` | Call groups of animals by the right name |
| `typography.diacritical_marks` | Using dïacríticâl marks |
| `typography.exclamation` | Avoiding overuse of exclamation |
| `typography.symbols` | Using the right symbols |
| `uncomparables.misc` | Not comparing uncomparables |
| `weasel_words.misc` | Avoiding weasel words |
| `weasel_words.very` | Avoiding the word "very" |
### Contributing
Interested in contributing to `proselint`? Great — there are plenty of ways you can help. Read more on [our website], where we describe how you can help us build `proselint` into the greatest writing tool in the world.
- [Issue Tracker](http://github.com/amperser/proselint/issues)
- [Source Code](http://github.com/amperser/proselint)
[our website]: http://proselint.com/contributing/
### Support
If you run into a problem, please [open an issue](http://github.com/amperser/proselint/issues) in or send an email to hello@amperser.com.
### Running Automated Tests
Automated tests are included in the `proselint/tests` directory. To run these tests locally, you can use `./utils`.
### License
The project is licensed under the BSD license.