Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new --ignore-words option to ignore 'good' words #100

Merged
merged 2 commits into from
Mar 22, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions codespell_lib/_codespell.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
VERSION = '1.10.0.dev0'

misspellings = {}
ignore_words = set()
exclude_lines = set()
options = None
file_opener = None
Expand Down Expand Up @@ -222,6 +223,10 @@ def parse_options(args):
'equals "-" then default dictionary "%s" is used. '
'This option can be specified multiple times.' %
default_dictionary)
parser.add_option('-I', '--ignore-words',
action='append', metavar='FILE',
help='File that contains words which will be ignored '
'by codespell.')
parser.add_option('-r', '--regex',
action='store', type='string',
help='Regular expression which is used to find words. '
Expand Down Expand Up @@ -284,10 +289,18 @@ def build_exclude_hashes(filename):
exclude_lines.add(line)


def build_ignore_words(filename):
with codecs.open(filename, mode='r', buffering=1, encoding='utf-8') as f:
for line in f:
ignore_words.add(line.strip())


def build_dict(filename):
with codecs.open(filename, mode='r', buffering=1, encoding='utf-8') as f:
for line in f:
[key, data] = line.split('->')
if key in ignore_words:
continue
data = data.strip()
fix = data.rfind(',')

Expand Down Expand Up @@ -520,6 +533,15 @@ def main(*args):
parser.print_help()
return 1

ignore_words_files = options.ignore_words or []
for ignore_words_file in ignore_words_files:
if not os.path.exists(ignore_words_file):
print('ERROR: cannot find ignore-words file: %s' %
ignore_words_file, file=sys.stderr)
parser.print_help()
return 1
build_ignore_words(ignore_words_file)

dictionaries = options.dictionary or [default_dictionary]
for dictionary in dictionaries:
if dictionary is "-":
Expand Down
139 changes: 86 additions & 53 deletions codespell_lib/tests/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,20 @@
import tempfile
import warnings

from nose.tools import assert_equal, assert_true
from nose.tools import with_setup, assert_equal, assert_true

from codespell_lib import main
import codespell_lib as cs


def reload_codespell_lib():
try:
reload # Python 2.7
except NameError:
try:
from importlib import reload # Python 3.4+
except ImportError:
from imp import reload # Python 3.0 - 3.3
reload(cs._codespell)


def run_codespell(args=(), cwd=None):
Expand All @@ -34,102 +45,102 @@ def test_command():

def test_basic():
"""Test some basic functionality"""
assert_equal(main('_does_not_exist_'), 0)
assert_equal(cs.main('_does_not_exist_'), 0)
with tempfile.NamedTemporaryFile('w') as f:
with CaptureStdout() as sio:
assert_equal(main('-D', 'foo', f.name), 1) # missing dictionary
assert_equal(cs.main('-D', 'foo', f.name), 1) # missing dictionary
assert_true('cannot find dictionary' in sio[1])
assert_equal(main(f.name), 0) # empty file
assert_equal(cs.main(f.name), 0) # empty file
f.write('this is a test file\n')
f.flush()
assert_equal(main(f.name), 0) # good
assert_equal(cs.main(f.name), 0) # good
f.write('abandonned\n')
f.flush()
assert_equal(main(f.name), 1) # bad
assert_equal(cs.main(f.name), 1) # bad
f.write('abandonned\n')
f.flush()
assert_equal(main(f.name), 2) # worse
assert_equal(cs.main(f.name), 2) # worse
with TemporaryDirectory() as d:
with open(op.join(d, 'bad.txt'), 'w') as f:
f.write('abandonned\nAbandonned\nABANDONNED\nAbAnDoNnEd')
assert_equal(main(d), 4)
assert_equal(cs.main(d), 4)
with CaptureStdout() as sio:
assert_equal(main('-w', d), 0)
assert_equal(cs.main('-w', d), 0)
assert_true('FIXED:' in sio[1])
with open(op.join(d, 'bad.txt')) as f:
new_content = f.read()
assert_equal(main(d), 0)
assert_equal(cs.main(d), 0)
assert_equal(new_content, 'abandoned\nAbandoned\nABANDONED\nabandoned')

with open(op.join(d, 'bad.txt'), 'w') as f:
f.write('abandonned abandonned\n')
assert_equal(main(d), 2)
assert_equal(cs.main(d), 2)
with CaptureStdout() as sio:
assert_equal(main('-q', '16', '-w', d), 0)
assert_equal(cs.main('-q', '16', '-w', d), 0)
assert_equal(sio[0], '')
assert_equal(main(d), 0)
assert_equal(cs.main(d), 0)

# empty directory
os.mkdir(op.join(d, 'test'))
assert_equal(main(d), 0)
assert_equal(cs.main(d), 0)

# hidden file
with open(op.join(d, 'test.txt'), 'w') as f:
f.write('abandonned\n')
assert_equal(main(op.join(d, 'test.txt')), 1)
assert_equal(cs.main(op.join(d, 'test.txt')), 1)
os.rename(op.join(d, 'test.txt'), op.join(d, '.test.txt'))
assert_equal(main(op.join(d, '.test.txt')), 0)
assert_equal(cs.main(op.join(d, '.test.txt')), 0)


def test_interactivity():
"""Test interaction"""
with tempfile.NamedTemporaryFile('w') as f:
assert_equal(main(f.name), 0) # empty file
assert_equal(cs.main(f.name), 0) # empty file
f.write('abandonned\n')
f.flush()
assert_equal(main('-i', '-1', f.name), 1) # bad
assert_equal(cs.main('-i', '-1', f.name), 1) # bad
with FakeStdin('y\n'):
assert_equal(main('-i', '3', f.name), 1)
assert_equal(cs.main('-i', '3', f.name), 1)
with CaptureStdout() as sio:
with FakeStdin('n\n'):
assert_equal(main('-w', '-i', '3', f.name), 0)
assert_equal(cs.main('-w', '-i', '3', f.name), 0)
assert_true('==>' in sio[0])
with CaptureStdout():
with FakeStdin('x\ny\n'):
assert_equal(main('-w', '-i', '3', f.name), 0)
assert_equal(main(f.name), 0)
assert_equal(cs.main('-w', '-i', '3', f.name), 0)
assert_equal(cs.main(f.name), 0)
with tempfile.NamedTemporaryFile('w') as f:
f.write('abandonned\n')
f.flush()
assert_equal(main(f.name), 1)
assert_equal(cs.main(f.name), 1)
with CaptureStdout():
with FakeStdin(' '): # blank input -> Y
assert_equal(main('-w', '-i', '3', f.name), 0)
assert_equal(main(f.name), 0)
assert_equal(cs.main('-w', '-i', '3', f.name), 0)
assert_equal(cs.main(f.name), 0)
# multiple options
with tempfile.NamedTemporaryFile('w') as f:
f.write('ackward\n')
f.flush()
assert_equal(main(f.name), 1)
assert_equal(cs.main(f.name), 1)
with CaptureStdout():
with FakeStdin(' \n'): # blank input -> nothing
assert_equal(main('-w', '-i', '3', f.name), 0)
assert_equal(main(f.name), 1)
assert_equal(cs.main('-w', '-i', '3', f.name), 0)
assert_equal(cs.main(f.name), 1)
with CaptureStdout():
with FakeStdin('0\n'): # blank input -> nothing
assert_equal(main('-w', '-i', '3', f.name), 0)
assert_equal(main(f.name), 0)
assert_equal(cs.main('-w', '-i', '3', f.name), 0)
assert_equal(cs.main(f.name), 0)
with open(f.name, 'r') as f_read:
assert_equal(f_read.read(), 'awkward\n')
f.seek(0)
f.write('ackward\n')
f.flush()
assert_equal(main(f.name), 1)
assert_equal(cs.main(f.name), 1)
with CaptureStdout() as sio:
with FakeStdin('x\n1\n'): # blank input -> nothing
assert_equal(main('-w', '-i', '3', f.name), 0)
assert_equal(cs.main('-w', '-i', '3', f.name), 0)
assert_true('a valid option' in sio[0])
assert_equal(main(f.name), 0)
assert_equal(cs.main(f.name), 0)
with open(f.name, 'r') as f:
assert_equal(f.read(), 'backward\n')

Expand All @@ -138,24 +149,46 @@ def test_summary():
"""Test summary functionality"""
with tempfile.NamedTemporaryFile('w') as f:
with CaptureStdout() as sio:
main(f.name)
cs.main(f.name)
for ii in range(2):
assert_equal(sio[ii], '') # no output
with CaptureStdout() as sio:
main(f.name, '--summary')
cs.main(f.name, '--summary')
assert_equal(sio[1], '') # stderr
assert_true('SUMMARY' in sio[0])
assert_equal(len(sio[0].split('\n')), 5) # no output
f.write('abandonned\nabandonned')
f.flush()
with CaptureStdout() as sio:
main(f.name, '--summary')
cs.main(f.name, '--summary')
assert_equal(sio[1], '') # stderr
assert_true('SUMMARY' in sio[0])
assert_equal(len(sio[0].split('\n')), 7)
assert_true('abandonned' in sio[0].split()[-2])


@with_setup(reload_codespell_lib, reload_codespell_lib)
def test_ignore_dictionary():
"""Test ignore dictionary functionality"""
with TemporaryDirectory() as d:
with open(op.join(d, 'bad.txt'), 'w') as f:
f.write('abandonned\nabondon\n')
with tempfile.NamedTemporaryFile('w') as f:
f.write('abandonned\n')
f.flush()
assert_equal(cs.main('-I', f.name, d), 1)


@with_setup(reload_codespell_lib, reload_codespell_lib)
def test_custom_regex():
"""Test custom word regex"""
with TemporaryDirectory() as d:
with open(op.join(d, 'bad.txt'), 'w') as f:
f.write('abandonned_abondon\n')
assert_equal(cs.main(d), 0)
assert_equal(cs.main('-r', "[a-z]+", d), 2)


def test_exclude_file():
"""Test exclude file functionality"""
with TemporaryDirectory() as d:
Expand All @@ -164,33 +197,33 @@ def test_exclude_file():
with tempfile.NamedTemporaryFile('w') as f:
f.write('abandonned 1\n')
f.flush()
assert_equal(main(d), 2)
assert_equal(main('-x', f.name, d), 1)
assert_equal(cs.main(d), 2)
assert_equal(cs.main('-x', f.name, d), 1)


def test_encoding():
"""Test encoding handling"""
# Some simple Unicode things
with tempfile.NamedTemporaryFile('wb') as f:
# with CaptureStdout() as sio:
assert_equal(main(f.name), 0)
assert_equal(cs.main(f.name), 0)
f.write(u'naïve\n'.encode('utf-8'))
f.flush()
assert_equal(main(f.name), 0)
assert_equal(main('-e', f.name), 0)
assert_equal(cs.main(f.name), 0)
assert_equal(cs.main('-e', f.name), 0)
f.write(u'naieve\n'.encode('utf-8'))
f.flush()
assert_equal(main(f.name), 1)
assert_equal(cs.main(f.name), 1)
# Binary file warning
with tempfile.NamedTemporaryFile('wb') as f:
assert_equal(main(f.name), 0)
assert_equal(cs.main(f.name), 0)
f.write(b'\x00\x00naiive\x00\x00')
f.flush()
with CaptureStdout() as sio:
assert_equal(main(f.name), 0)
assert_equal(cs.main(f.name), 0)
assert_true('WARNING: Binary file' in sio[1])
with CaptureStdout() as sio:
assert_equal(main('-q', '2', f.name), 0)
assert_equal(cs.main('-q', '2', f.name), 0)
assert_equal(sio[1], '')


Expand All @@ -199,19 +232,19 @@ def test_ignore():
with TemporaryDirectory() as d:
with open(op.join(d, 'good.txt'), 'w') as f:
f.write('this file is okay')
assert_equal(main(d), 0)
assert_equal(cs.main(d), 0)
with open(op.join(d, 'bad.txt'), 'w') as f:
f.write('abandonned')
assert_equal(main(d), 1)
assert_equal(main('--skip=bad*', d), 0)
assert_equal(main('--skip=bad.txt', d), 0)
assert_equal(cs.main(d), 1)
assert_equal(cs.main('--skip=bad*', d), 0)
assert_equal(cs.main('--skip=bad.txt', d), 0)
subdir = op.join(d, 'ignoredir')
os.mkdir(subdir)
with open(op.join(subdir, 'bad.txt'), 'w') as f:
f.write('abandonned')
assert_equal(main(d), 2)
assert_equal(main('--skip=bad*', d), 0)
assert_equal(main('--skip=*ignoredir*', d), 1)
assert_equal(cs.main(d), 2)
assert_equal(cs.main('--skip=bad*', d), 0)
assert_equal(cs.main('--skip=*ignoredir*', d), 1)


class TemporaryDirectory(object):
Expand Down