Skip to content

Commit ff5dfce

Browse files
committed
Problem 11 solution
1 parent 25dffd1 commit ff5dfce

File tree

2 files changed

+136
-31
lines changed

2 files changed

+136
-31
lines changed

11_bottles_of_beer/bottles.py

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Author : Luke McGuire <[email protected]>
4+
Date : 2024-06-28
5+
Purpose: Bottles of beer song
6+
"""
7+
8+
import argparse
9+
10+
11+
# --------------------------------------------------
12+
def positive_int(string):
13+
"""check for positive integer"""
14+
try:
15+
value = int(string)
16+
except ValueError as e:
17+
raise argparse.ArgumentTypeError(f"invalid int value: '{string}'") from e
18+
if value < 1:
19+
raise argparse.ArgumentTypeError(f'"{value}" must be greater than 0')
20+
return value
21+
22+
23+
# --------------------------------------------------
24+
25+
26+
def get_args():
27+
"""Get command-line arguments"""
28+
29+
parser = argparse.ArgumentParser(
30+
description="Bottles of beer song",
31+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
32+
)
33+
34+
parser.add_argument(
35+
"-n",
36+
"--num",
37+
help="How many bottles",
38+
metavar="int",
39+
type=positive_int,
40+
default=10,
41+
)
42+
43+
return parser.parse_args()
44+
45+
46+
# --------------------------------------------------
47+
def verse(bottle: int) -> str:
48+
"""Sing a verse"""
49+
50+
next_bottle = bottle - 1
51+
s1 = "" if bottle == 1 else "s"
52+
s2 = "" if next_bottle == 1 else "s"
53+
54+
lyrics = [
55+
f"{bottle} bottle{s1} of beer on the wall,",
56+
f"{bottle} bottle{s1} of beer,",
57+
"Take one down, pass it around,",
58+
f"{next_bottle if next_bottle else 'No more'} bottle{s2} of beer on the wall!",
59+
]
60+
return "\n".join(lyrics)
61+
62+
63+
# --------------------------------------------------
64+
def test_verse_1():
65+
"""Test verse for 1 bottle"""
66+
67+
one = verse(1)
68+
assert one == "\n".join(
69+
[
70+
"1 bottle of beer on the wall,",
71+
"1 bottle of beer,",
72+
"Take one down, pass it around,",
73+
"No more bottles of beer on the wall!",
74+
]
75+
)
76+
77+
78+
def test_verse_2():
79+
"""Test verse for 2 bottles"""
80+
81+
two = verse(2)
82+
assert two == "\n".join(
83+
[
84+
"2 bottles of beer on the wall,",
85+
"2 bottles of beer,",
86+
"Take one down, pass it around,",
87+
"1 bottle of beer on the wall!",
88+
]
89+
)
90+
91+
92+
# --------------------------------------------------
93+
def main():
94+
"""Make a jazz noise here"""
95+
96+
args = get_args()
97+
# song = map(verse, range(args.num, 0, -1))
98+
print("\n\n".join(song))
99+
100+
101+
# --------------------------------------------------
102+
if __name__ == "__main__":
103+
main()

11_bottles_of_beer/test.py

+33-31
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,22 @@
88
import string
99
from subprocess import getstatusoutput
1010

11-
prg = './bottles.py'
11+
PRG = "./bottles.py"
1212

1313

1414
# --------------------------------------------------
1515
def test_exists():
1616
"""exists"""
1717

18-
assert os.path.isfile(prg)
18+
assert os.path.isfile(PRG)
1919

2020

2121
# --------------------------------------------------
2222
def test_usage():
2323
"""usage"""
2424

25-
for flag in ['-h', '--help']:
26-
rv, out = getstatusoutput(f'{prg} {flag}')
25+
for flag in ["-h", "--help"]:
26+
rv, out = getstatusoutput(f"python {PRG} {flag}")
2727
assert rv == 0
2828
assert re.match("usage", out, re.IGNORECASE)
2929

@@ -33,17 +33,17 @@ def test_bad_int():
3333
"""Bad integer value"""
3434

3535
bad = random.randint(-10, 0)
36-
rv, out = getstatusoutput(f'{prg} -n {bad}')
36+
rv, out = getstatusoutput(f"python {PRG} -n {bad}")
3737
assert rv != 0
38-
assert re.search(f'--num "{bad}" must be greater than 0', out)
38+
assert re.search(f'--num: "{bad}" must be greater than 0', out)
3939

4040

4141
# --------------------------------------------------
4242
def test_float():
4343
"""float value"""
4444

4545
bad = round(random.random() * 10, 2)
46-
rv, out = getstatusoutput(f'{prg} --num {bad}')
46+
rv, out = getstatusoutput(f"python {PRG} --num {bad}")
4747
assert rv != 0
4848
assert re.search(f"invalid int value: '{bad}'", out)
4949

@@ -53,7 +53,7 @@ def test_str():
5353
"""str value"""
5454

5555
bad = random_string()
56-
rv, out = getstatusoutput(f'{prg} -n {bad}')
56+
rv, out = getstatusoutput(f"python {PRG} -n {bad}")
5757
assert rv != 0
5858
assert re.search(f"invalid int value: '{bad}'", out)
5959

@@ -62,12 +62,14 @@ def test_str():
6262
def test_one():
6363
"""One bottle of beer"""
6464

65-
expected = ('1 bottle of beer on the wall,\n'
66-
'1 bottle of beer,\n'
67-
'Take one down, pass it around,\n'
68-
'No more bottles of beer on the wall!')
65+
expected = (
66+
"1 bottle of beer on the wall,\n"
67+
"1 bottle of beer,\n"
68+
"Take one down, pass it around,\n"
69+
"No more bottles of beer on the wall!"
70+
)
6971

70-
rv, out = getstatusoutput(f'{prg} --num 1')
72+
rv, out = getstatusoutput(f"python {PRG} --num 1")
7173
assert rv == 0
7274
assert out == expected
7375

@@ -76,16 +78,18 @@ def test_one():
7678
def test_two():
7779
"""Two bottles of beer"""
7880

79-
expected = ('2 bottles of beer on the wall,\n'
80-
'2 bottles of beer,\n'
81-
'Take one down, pass it around,\n'
82-
'1 bottle of beer on the wall!\n\n'
83-
'1 bottle of beer on the wall,\n'
84-
'1 bottle of beer,\n'
85-
'Take one down, pass it around,\n'
86-
'No more bottles of beer on the wall!')
87-
88-
rv, out = getstatusoutput(f'{prg} -n 2')
81+
expected = (
82+
"2 bottles of beer on the wall,\n"
83+
"2 bottles of beer,\n"
84+
"Take one down, pass it around,\n"
85+
"1 bottle of beer on the wall!\n\n"
86+
"1 bottle of beer on the wall,\n"
87+
"1 bottle of beer,\n"
88+
"Take one down, pass it around,\n"
89+
"No more bottles of beer on the wall!"
90+
)
91+
92+
rv, out = getstatusoutput(f"python {PRG} -n 2")
8993
assert rv == 0
9094
assert out == expected
9195

@@ -94,21 +98,19 @@ def test_two():
9498
def test_random():
9599
"""Random number"""
96100

97-
sums = dict(
98-
map(lambda x: x.split('\t'),
99-
open('sums.txt').read().splitlines()))
101+
sums = dict(map(lambda x: x.split("\t"), open("sums.txt").read().splitlines()))
100102

101103
for n in random.choices(list(sums.keys()), k=10):
102-
flag = '-n' if random.choice([0, 1]) == 1 else '--num'
103-
rv, out = getstatusoutput(f'{prg} {flag} {n}')
104-
out += '\n' # because the last newline is removed
104+
flag = "-n" if random.choice([0, 1]) == 1 else "--num"
105+
rv, out = getstatusoutput(f"python {PRG} {flag} {n}")
106+
out += "\n" # because the last newline is removed
105107
assert rv == 0
106-
assert hashlib.md5(out.encode('utf-8')).hexdigest() == sums[n]
108+
assert hashlib.md5(out.encode("utf-8")).hexdigest() == sums[n]
107109

108110

109111
# --------------------------------------------------
110112
def random_string():
111113
"""generate a random string"""
112114

113115
k = random.randint(5, 10)
114-
return ''.join(random.choices(string.ascii_letters + string.digits, k=k))
116+
return "".join(random.choices(string.ascii_letters + string.digits, k=k))

0 commit comments

Comments
 (0)