forked from amueller/word_cloud
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
194 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
import argparse | ||
import inspect | ||
import wordcloud_cli | ||
import wordcloud as wc | ||
import sys | ||
from collections import namedtuple | ||
from mock import patch, MagicMock | ||
from nose.tools import assert_equal, assert_true, assert_in | ||
|
||
from tempfile import NamedTemporaryFile | ||
|
||
temp = NamedTemporaryFile() | ||
ArgOption = namedtuple('ArgOption', ['cli_name', 'init_name', 'pass_value', 'fail_value']) | ||
ARGUMENT_SPEC_TYPED = [ | ||
ArgOption(cli_name='width', init_name='width', pass_value=13, fail_value=1.), | ||
ArgOption(cli_name='height', init_name='height', pass_value=15, fail_value=1.), | ||
ArgOption(cli_name='margin', init_name='margin', pass_value=17, fail_value=1.), | ||
ArgOption(cli_name='relative_scaling', init_name='relative_scaling', pass_value=1, fail_value='c') | ||
] | ||
ARGUMENT_SPEC_REMAINING = [ | ||
ArgOption(cli_name='stopwords', init_name='stopwords', pass_value=temp.name, fail_value=None), | ||
ArgOption(cli_name='mask', init_name='mask', pass_value=temp.name, fail_value=None), | ||
ArgOption(cli_name='fontfile', init_name='font_path', pass_value=temp.name, fail_value=None), | ||
ArgOption(cli_name='color', init_name='color_func', pass_value='red', fail_value=None), | ||
ArgOption(cli_name='background', init_name='background_color', pass_value='grey', fail_value=None) | ||
] | ||
|
||
def all_arguments(): | ||
arguments = [] | ||
arguments.extend(ARGUMENT_SPEC_TYPED) | ||
arguments.extend(ARGUMENT_SPEC_REMAINING) | ||
return arguments | ||
|
||
|
||
def test_argument_spec_matches_to_constructor_args(): | ||
args = argparse.Namespace() | ||
for option in all_arguments(): | ||
setattr(args, option.init_name, option.pass_value) | ||
|
||
supported_args = inspect.getargspec(wc.WordCloud.__init__).args | ||
supported_args.remove('self') | ||
for arg_name in vars(args).keys(): | ||
assert_in(arg_name, supported_args) | ||
|
||
|
||
def test_main_passes_arguments_through(): | ||
args = argparse.Namespace() | ||
for option in all_arguments(): | ||
setattr(args, option.init_name, option.pass_value) | ||
args.imagefile = NamedTemporaryFile() | ||
args.text = 'some long text' | ||
|
||
with patch('wordcloud_cli.wc.WordCloud', autospec=True) as mock_word_cloud: | ||
instance = mock_word_cloud.return_value | ||
instance.to_image.return_value = MagicMock() | ||
wordcloud_cli.main(args) | ||
|
||
posargs, kwargs = mock_word_cloud.call_args | ||
for option in all_arguments(): | ||
assert_in(option.init_name, kwargs) | ||
|
||
|
||
def check_argument(name, result_name, value): | ||
text = NamedTemporaryFile() | ||
|
||
args = wordcloud_cli.parse_args(['--text', text.name, '--' + name, str(value)]) | ||
assert_in(result_name, vars(args)) | ||
|
||
|
||
def check_argument_type(name, value): | ||
text = NamedTemporaryFile() | ||
|
||
try: | ||
with patch('wordcloud_cli.sys.stderr') as mock_stdout: | ||
args = wordcloud_cli.parse_args(['--text', text.name, '--' + name, str(value)]) | ||
raise AssertionError('argument "{}" was accepted even though the type did not match'.format(name)) | ||
except SystemExit: | ||
pass | ||
except ValueError: | ||
pass | ||
|
||
|
||
def test_parse_args_are_passed_along(): | ||
for option in all_arguments(): | ||
if option.cli_name != 'mask': | ||
yield check_argument, option.cli_name, option.init_name, option.pass_value | ||
|
||
|
||
def test_parse_arg_types(): | ||
for option in ARGUMENT_SPEC_TYPED: | ||
yield check_argument_type, option.cli_name, option.fail_value | ||
|
||
|
||
def test_check_duplicate_color_error(): | ||
color_mask_file = NamedTemporaryFile() | ||
text_file = NamedTemporaryFile() | ||
|
||
try: | ||
wordcloud_cli.parse_args(['--color', 'red', '--colormask', color_mask_file.name, '--text', text_file.name]) | ||
raise AssertionError('parse_args(...) didn\'t raise') | ||
except ValueError as e: | ||
assert_true('specify either' in str(e), msg='expecting the correct error message, instead got: ' + str(e)) | ||
|
||
|
||
def test_parse_args_defaults_to_random_color(): | ||
text = NamedTemporaryFile() | ||
|
||
args = wordcloud_cli.parse_args(['--text', text.name]) | ||
assert_equal(args.color_func, wc.random_color_func) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,3 @@ | ||
* command line interface | ||
* html export | ||
* good notebook interface | ||
* by default differnt color schemes | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
#!/usr/bin/env python | ||
# -*- coding: utf-8 -*- | ||
r"""Command-line tool to generate word clouds | ||
Usage:: | ||
$ cat word.txt | wordcloud_cli.py | ||
$ wordcloud_cli.py --text=words.txt --stopwords=stopwords.txt | ||
""" | ||
import argparse | ||
import wordcloud as wc | ||
import numpy as np | ||
import sys | ||
import io | ||
from PIL import Image | ||
|
||
def main(args): | ||
wordcloud = wc.WordCloud(stopwords=args.stopwords, mask=args.mask, | ||
width=args.width, height=args.height, font_path=args.font_path, | ||
margin=args.margin, relative_scaling=args.relative_scaling, | ||
color_func=args.color_func, background_color=args.background_color).generate(args.text) | ||
image = wordcloud.to_image() | ||
|
||
b = io.BytesIO() | ||
image.save(b, format='png') | ||
with args.imagefile: | ||
args.imagefile.write(b.getvalue()) | ||
|
||
def parse_args(arguments): | ||
prog = 'python wordcloud_cli.py' | ||
description = ('A simple command line interface for wordcloud module.') | ||
parser = argparse.ArgumentParser(description=description) | ||
parser.add_argument('--text', metavar='file', type=argparse.FileType(), default='-', | ||
help='specify file of words to build the word cloud (default: stdin)') | ||
parser.add_argument('--stopwords', metavar='file', type=argparse.FileType(), | ||
help='specify file of stopwords (containing one word per line) to remove from the given text after parsing') | ||
parser.add_argument('--imagefile', metavar='file', type=argparse.FileType('w'), default='-', | ||
help='file the completed PNG image should be written to (default: stdout)') | ||
parser.add_argument('--fontfile', metavar='path', dest='font_path', | ||
help='path to font file you wish to use (default: DroidSansMono)') | ||
parser.add_argument('--mask', metavar='file', type=argparse.FileType(), | ||
help='mask to use for the image form') | ||
parser.add_argument('--colormask', metavar='file', type=argparse.FileType(), | ||
help='color mask to use for image coloring') | ||
parser.add_argument('--relative_scaling', type=float, default=0, | ||
metavar='rs', help=' scaling of words by frequency (0 - 1)') | ||
parser.add_argument('--margin', type=int, default=2, | ||
metavar='width', help='spacing to leave around words') | ||
parser.add_argument('--width', type=int, default=400, | ||
metavar='width', help='define output image width') | ||
parser.add_argument('--height', type=int, default=200, | ||
metavar='height', help='define output image height') | ||
parser.add_argument('--color', metavar='color', | ||
help='use given color as coloring for the image - accepts any value from PIL.ImageColor.getcolor') | ||
parser.add_argument('--background', metavar='color', default='black', type=str, dest='background_color', | ||
help='use given color as background color for the image - accepts any value from PIL.ImageColor.getcolor') | ||
args = parser.parse_args(arguments) | ||
|
||
if args.colormask and args.color: | ||
raise ValueError('specify either a color mask or a color function') | ||
|
||
with args.text: | ||
args.text = args.text.read() | ||
|
||
if args.stopwords: | ||
with args.stopwords: | ||
args.stopwords = set(map(str.strip, args.stopwords.readlines())) | ||
|
||
if args.mask: | ||
args.mask = np.array(Image.open(args.mask)) | ||
|
||
color_func = wc.random_color_func | ||
if args.colormask: | ||
image = np.array(Image.open(args.colormask)) | ||
color_func = wc.ImageColorGenerator(image) | ||
|
||
if args.color: | ||
color_func = wc.get_single_color_func(args.color) | ||
|
||
args.color_func = color_func | ||
return args | ||
|
||
if __name__ == '__main__': | ||
main(parse_args(sys.argv[1:])) |