Skip to content

Commit f9cb643

Browse files
committed
gashlycrumb mostly
1 parent 815c7e1 commit f9cb643

8 files changed

Lines changed: 199 additions & 53 deletions

File tree

bin/no_solution.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Author : kyclark
4+
Date : 2019-07-01
5+
Purpose: Rock the Casbah
6+
"""
7+
8+
import argparse
9+
import os
10+
import sys
11+
12+
13+
# --------------------------------------------------
14+
def get_args():
15+
"""Get command-line arguments"""
16+
17+
parser = argparse.ArgumentParser(
18+
description='Argparse Python script',
19+
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
20+
21+
parser.add_argument('positional',
22+
metavar='str',
23+
help='A positional argument')
24+
25+
parser.add_argument('-a',
26+
'--arg',
27+
help='A named string argument',
28+
metavar='str',
29+
type=str,
30+
default='')
31+
32+
parser.add_argument('-i',
33+
'--int',
34+
help='A named integer argument',
35+
metavar='int',
36+
type=int,
37+
default=0)
38+
39+
parser.add_argument('-f',
40+
'--flag',
41+
help='A boolean flag',
42+
action='store_true')
43+
44+
return parser.parse_args()
45+
46+
47+
# --------------------------------------------------
48+
def main():
49+
"""Make a jazz noise here"""
50+
51+
args = get_args()
52+
str_arg = args.arg
53+
int_arg = args.int
54+
flag_arg = args.flag
55+
pos_arg = args.positional
56+
57+
print('str_arg = "{}"'.format(str_arg))
58+
print('int_arg = "{}"'.format(int_arg))
59+
print('flag_arg = "{}"'.format(flag_arg))
60+
print('positional = "{}"'.format(pos_arg))
61+
62+
63+
# --------------------------------------------------
64+
if __name__ == '__main__':
65+
main()

gashlycrumb/Makefile

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
.PHONY: pdf test
2-
3-
pdf:
4-
pandoc README.md -o README.pdf
1+
.PHONY: test
52

63
test:
7-
pytest -v test.py
4+
pytest -xv test.py

gashlycrumb/README.md

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Gashlycrumb
22

3-
Write a Python program called `gashlycrumb.py` that takes a letter of the alphabet as an argument and looks up the line in a `-f|--file` argument (default `gashlycrumb.txt`) and prints the line starting with that letter.
3+
Write a Python program called `gashlycrumb.py` that takes a letter of the alphabet as an argument and looks up the line in a `-f|--file` argument (default `gashlycrumb.txt`) and prints the line starting with that letter. It should generate usage with no arguments or for `-h|--help`:
44

55
````
66
$ ./gashlycrumb.py
@@ -17,28 +17,48 @@ positional arguments:
1717
optional arguments:
1818
-h, --help show this help message and exit
1919
-f str, --file str Input file (default: gashlycrumb.txt)
20-
$ ./gashlycrumb.py 3
21-
I do not know "3".
22-
$ ./gashlycrumb.py CH
23-
"CH" is not 1 character.
20+
````
21+
22+
You can see the structure of the default "gashlycrumb.txt" file:
23+
24+
````
25+
$ head -3 gashlycrumb.txt
26+
A is for Amy who fell down the stairs.
27+
B is for Basil assaulted by bears.
28+
C is for Clara who wasted away.
29+
````
30+
31+
You will use the first character of the line as a lookup value:
32+
33+
````
2434
$ ./gashlycrumb.py a
2535
A is for Amy who fell down the stairs.
2636
$ ./gashlycrumb.py z
2737
Z is for Zillah who drank too much gin.
2838
````
2939

30-
If you are not familiar with the work of Edward Gorey, please stop and go read about him immediately, e.g. https://www.brainpickings.org/2011/01/19/edward-gorey-the-gashlycrumb-tinies/!
40+
If given a value that does not exist (when searched with regard to case), you should print a message:
3141

32-
Write your own version of Gorey's text and pass in your version as the `--file`.
42+
````
43+
$ ./gashlycrumb.py 3
44+
I do not know "3".
45+
````
3346

34-
Write an interactive version that takes input directly from the user:
47+
You expect the positional argument to be exactly one character long. If it is not, exit with an error:
3548

3649
````
37-
$ ./gashlycrumb_i.py
38-
Please provide a letter [! to quit]: a
39-
A is for Amy who fell down the stairs.
40-
Please provide a letter [! to quit]: b
41-
B is for Basil assaulted by bears.
42-
Please provide a letter [! to quit]: !
43-
Bye
50+
$ ./gashlycrumb.py CH
51+
"CH" is not 1 character.
4452
````
53+
54+
If you provide a `--file` argument that does not exist, you should exit with an error and message:
55+
56+
````
57+
$ ./gashlycrumb.py -f sdfl b
58+
usage: gashlycrumb.py [-h] [-f str] str
59+
gashlycrumb.py: error: argument -f/--file: can't open 'sdfl': \
60+
[Errno 2] No such file or directory: 'sdfl'
61+
````
62+
63+
For those last two, look into using `argparse.FileType('r')` to describe the `type` of the `--file` argument so that `argparse` will do the check and create the error. For the length of the `letter` argument, look into using `parser.error`.
64+

gashlycrumb/alternate.txt

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,16 @@ J is for Jered, who fell off a chair,
1111
K is for Ken, bit by a snake.
1212
L is for Lori, impaled on a stake.
1313
M is for Moira, hit by a brick.
14-
N is for Norbert,
15-
O is for Olive run through with an awl.
16-
P is for Prue trampled flat in a brawl.
17-
Q is for Quentin who sank on a mire.
18-
R is for Rhoda consumed by a fire.
19-
S is for Susan who perished of fits.
20-
T is for Titus who flew into bits.
21-
U is for Una who slipped down a drain.
22-
V is for Victor squashed under a train.
23-
W is for Winnie embedded in ice.
24-
X is for Xerxes devoured by mice.
25-
Y is for Yorick whose head was bashed in.
26-
Z is for Zillah who drank too much gin.
14+
N is for Norbert, who swallowed a stick.
15+
O is for Orville, who fell in a canyon,
16+
P is for Paul, strangled by his banyan,
17+
Q is for Quintanna, flayed in the night,
18+
R is for Robert, who died of spite,
19+
S is for Susan, stung by a jelly,
20+
T is for Terrange, kicked in the belly,
21+
U is for Uma, who's life was vanquished,
22+
V is for Victor, consumed by anguish,
23+
W is for Walter, who's socks were too long,
24+
X is for Xavier, stuck through with a prong,
25+
Y is for Yoeman, too fat by a piece,
26+
Z is for Zora, smothered by a fleece.

gashlycrumb/discussion.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
If you haven't yet explored dictionaries, this is a natural solution.
2+
3+
## Edward Gorey
4+
5+
If you are not familiar with the work of Edward Gorey, please stop and go read about him immediately, e.g. https://www.brainpickings.org/2011/01/19/edward-gorey-the-gashlycrumb-tinies/!
6+
7+
## Alternate text
8+
9+
Write your own version of Gorey's text and pass in your version as the `--file`. I include my own `alternate.txt` which I used the simple and Soundex rhymers to help me find words.
10+
11+
## Interactive version
12+
13+
Write an interactive version that takes input directly from the user:
14+
15+
````
16+
$ ./gashlycrumb_i.py
17+
Please provide a letter [! to quit]: a
18+
A is for Amy who fell down the stairs.
19+
Please provide a letter [! to quit]: b
20+
B is for Basil assaulted by bears.
21+
Please provide a letter [! to quit]: !
22+
Bye
23+
````
Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22
"""Lookup tables"""
33

44
import argparse
5-
import os
6-
from dire import die
75

86

97
# --------------------------------------------------
108
def get_args():
119
"""get command-line arguments"""
10+
1211
parser = argparse.ArgumentParser(
1312
description='Gashlycrumb',
1413
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
@@ -19,28 +18,29 @@ def get_args():
1918
'--file',
2019
help='Input file',
2120
metavar='str',
22-
type=str,
21+
type=argparse.FileType('r'),
2322
default='gashlycrumb.txt')
2423

25-
return parser.parse_args()
24+
args = parser.parse_args()
25+
26+
if len(args.letter) != 1:
27+
parser.error('"{}" is not 1 character.'.format(args.letter))
28+
29+
return args
2630

2731

2832
# --------------------------------------------------
2933
def main():
3034
"""Make a jazz noise here"""
35+
3136
args = get_args()
3237
letter = args.letter.upper()
33-
file = args.file
34-
35-
if not os.path.isfile(file):
36-
die('--file "{}" is not a file.'.format(file))
3738

38-
if len(letter) != 1:
39-
die('"{}" is not 1 character.'.format(letter))
39+
# lookup = {}
40+
# for line in args.file:
41+
# lookup[line[0]] = line.rstrip()
4042

41-
lookup = {}
42-
for line in open(file):
43-
lookup[line[0]] = line.rstrip()
43+
lookup = {line[0]: line.rstrip() for line in args.file}
4444

4545
if letter in lookup:
4646
print(lookup[letter])

gashlycrumb/test.py

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,29 @@
11
#!/usr/bin/env python3
22
"""tests for gashlycrumb.py"""
33

4+
import os
45
import re
56
import random
6-
from subprocess import getstatusoutput, getoutput
7+
import string
8+
from subprocess import getstatusoutput
79

810
prg = './gashlycrumb.py'
911

1012

1113
# --------------------------------------------------
1214
def file_flag():
15+
"""Either -f or --file"""
16+
1317
return '-f' if random.randint(0, 1) else '--file'
1418

1519

20+
# --------------------------------------------------
21+
def test_exists():
22+
"""exists"""
23+
24+
assert os.path.isfile(prg)
25+
26+
1627
# --------------------------------------------------
1728
def test_usage():
1829
"""usage"""
@@ -25,27 +36,57 @@ def test_usage():
2536

2637
# --------------------------------------------------
2738
def test_a():
28-
out = getoutput('{} a'.format(prg))
39+
"""Test for 'a'"""
40+
41+
rv, out = getstatusoutput('{} a'.format(prg))
42+
assert rv == 0
2943
expected = 'A is for Amy who fell down the stairs.'
3044
assert out.strip() == expected
3145

3246

3347
# --------------------------------------------------
3448
def test_y():
35-
out = getoutput('{} Y'.format(prg))
49+
"""Test for 'y'"""
50+
51+
rv, out = getstatusoutput('{} Y'.format(prg))
52+
assert rv == 0
3653
expected = 'Y is for Yorick whose head was bashed in.'
3754
assert out.strip() == expected
3855

3956

4057
# --------------------------------------------------
4158
def test_number():
42-
out = getoutput('{} 5'.format(prg))
59+
"""Test for a number"""
60+
61+
rv, out = getstatusoutput('{} 5'.format(prg))
62+
assert rv == 0
4363
expected = 'I do not know "5".'
4464
assert out.strip() == expected
4565

4666

4767
# --------------------------------------------------
4868
def test_too_long():
49-
out = getoutput('{} ch'.format(prg))
50-
expected = '"CH" is not 1 character.'
51-
assert out.strip() == expected
69+
"""Test for too long"""
70+
71+
rv, out = getstatusoutput('{} ch'.format(prg))
72+
assert rv != 0
73+
expected = '"ch" is not 1 character'
74+
assert re.search(expected, out)
75+
76+
# --------------------------------------------------
77+
def test_bad_file():
78+
"""Test for bad --file"""
79+
80+
bad_file = random_string()
81+
letter = random.choice(string.ascii_lowercase)
82+
rv, out = getstatusoutput('{} {} -f {}'.format(prg, letter, bad_file))
83+
assert rv != 0
84+
expected = "No such file or directory: '{}'".format(bad_file)
85+
assert re.search(expected, out)
86+
87+
# --------------------------------------------------
88+
def random_string():
89+
"""generate a random string"""
90+
91+
k = random.randint(5, 10)
92+
return ''.join(random.choices(string.ascii_letters + string.digits, k=k))

0 commit comments

Comments
 (0)