Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit a2f37e6

Browse filesBrowse files
committed
discussions
1 parent 1829014 commit a2f37e6
Copy full SHA for a2f37e6

File tree

Expand file treeCollapse file tree

9 files changed

+716
-57
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

9 files changed

+716
-57
lines changed
Open diff view settings
Collapse file

‎appendix/argparse/README.md‎

Copy file name to clipboardExpand all lines: appendix/argparse/README.md
+17-1Lines changed: 17 additions & 1 deletion
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# argparse
2+
13
The `argparse` module will interpret all the command-line arguments to your program. I suggest you use `argparse` for every command-line program you write so that you always have a standard way to get arguments and present help.
24

35
## Types of arguments
@@ -97,6 +99,20 @@ if __name__ == '__main__':
9799

98100
The `type` of the input `file` argument is an *open file handle* which we can directly read line-by-line with a `for` loop! Because it's a file *handle* and not a file *name*, I chose to call the variable `fh` to help me remember what it is. You can access the file's name via `fh.name`.
99101

102+
````
103+
$ ./cat_n.py ../../inputs/the-bustle.txt
104+
Reading "../../inputs/the-bustle.txt"
105+
0 The bustle in a house
106+
1 The morning after death
107+
2 Is solemnest of industries
108+
3 Enacted upon earth,--
109+
4
110+
5 The sweeping up the heart,
111+
6 And putting love away
112+
7 We shall not want to use again
113+
8 Until eternity.
114+
````
115+
100116
## Number of arguments
101117

102118
If you want one positional argument, you can define them like so:
@@ -302,4 +318,4 @@ str_arg = "bar" (<class 'str'>)
302318
int_arg = "4" (<class 'int'>)
303319
flag_arg = "True" (<class 'bool'>)
304320
positional = "foo" (<class 'str'>)
305-
````
321+
````
Collapse file

‎article/discussion.md‎

Copy file name to clipboard
+53Lines changed: 53 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
Cf Appendices: argparse, Truthiness
2+
3+
As with all the solutions presented, this assumes you have stubbed the program with `new.py` and that you are using the `argparse` module. I suggest putting this logic into a separate function which here is called `get_args` and which I like to define first so that I can see right away when I'm reading the program what the program expects as input. On line 12, I set the `description` for the program that will be displayed with the help documentation. On line 15, I indicate that the program expects just one *positional* argument, no more, no less. Since it is a "word" that I expect, I called the argument `word` which is also how I will access the value on line 25. I use the `metavar` on line 15 to let the user know that this should be a string.
4+
5+
The `get_args` function will `return` the result of parsing the command line arguments which I put into the variable `args` on line 24. I can now access the `word` by call `args.word`. Note the lack of parentheses -- it's not `args.word()` -- as this is not a function call. Think of it like a slot where the value lives.
6+
7+
On line 26, we need to figure out whether the `article` should be `a` or `an`. We'll use a very simple rule that any word that has a first character that is a vowel should get `an` and otherwise we choose `a`. This obviously misses actual pronunciations like in American English we don't pronounce the "h" in "herb" and so actually say "an herb" whereas the British *do* pronounce the "h" and so would say "an herb". (Even more bizarre to me is that the British leave off the article entirely for the word "hospital" as in, "The Queen is in hospital!") Nor will we consider words where the initial `y` acts like a vowel.
8+
9+
We can access the first character of the `word` with `word[0]` which looks the same as how we access the first element of a list. Strings are really list of characters, so this isn't so far-fetched, but we do have to remember that Python, like so many programming languages, starts numbering at `0`, so we often talked about the first element of a list as the "zeroth" element.
10+
11+
To decided if the given word starts with a vowel, we ask if `word[0].lower() in 'aeiou'`. So, to unpack that, `word[0]` returns a one-character-long `str` type which has the method `.lower()` which we call using the parentheses. Without the parens, this would just be the *idea* of the function that returns a lowercased version of the string. Understand that the `word` remains unchanged. The function does not lowercase `word[0]`, it only *returns a lowercase version* of that character.
12+
13+
The `X in Y` form is a way to ask if element `X` is in the collection `Y`:
14+
15+
````
16+
>>> 'a' in 'abc'
17+
True
18+
>>> 'foo' in ['foo', 'bar']
19+
True
20+
>>> 3 in range(5)
21+
True
22+
>>> 10 in range(3)
23+
False
24+
````
25+
26+
So we get the first character of `word` and ask if the lowercased version is in the list of characters `aeiou`.
27+
28+
The `if` *expression* is different from an `if` *statement*. An expression returns a value, and a statement does not. The `if` expression must have an `else`, but the `if` statement does not have this requirement. The first value is returned if the predicate (the bit after the `if`) evaluates to `True` in a Boolean context (more on that later), otherwise the last value is returned:
29+
30+
````
31+
>>> 'Hooray!' if True else 'Shucks!'
32+
'Hooray!'
33+
````
34+
35+
The longer way to write this would have been:
36+
37+
````
38+
article = ''
39+
if word[0].lower() in 'aeiou':
40+
article = 'a'
41+
else:
42+
article = 'an'
43+
````
44+
45+
Or more succinctly:
46+
47+
````
48+
article = 'an'
49+
if word[0].lower() in 'aeiou':
50+
article = 'a'
51+
````
52+
53+
Collapse file

‎article/solution.py‎

Copy file name to clipboardExpand all lines: article/solution.py
-2Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
"""Article selector"""
33

44
import argparse
5-
import os
6-
import sys
75

86

97
# --------------------------------------------------
Collapse file

‎article/test.py‎

Copy file name to clipboardExpand all lines: article/test.py
+18-9Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@
33

44
import re
55
import os
6-
import random
76
from subprocess import getstatusoutput, getoutput
87

98
prg = './article.py'
9+
consonant_words = [
10+
'bear', 'cow', 'deer', 'frog', 'giraffe', 'horse', 'jackyl', 'kestrel',
11+
'lion', 'marmot', 'nutria', 'porpoise', 'quark', 'rooster', 'sturgeon',
12+
'turtle', 'vermin', 'walrus', 'xray', 'yoosy', 'zebra'
13+
]
14+
vowel_words = ['appaloosa', 'elephant', 'ingot', 'octopus', 'unicorn']
1015

1116

1217
# --------------------------------------------------
@@ -30,29 +35,33 @@ def test_usage():
3035
def test_01():
3136
""" bear -> a bear """
3237

33-
out = getoutput('{} bear'.format(prg))
34-
assert out.strip() == 'a bear'
38+
for word in consonant_words:
39+
out = getoutput('{} {}'.format(prg, word))
40+
assert out.strip() == 'a ' + word
3541

3642

3743
# --------------------------------------------------
3844
def test_02():
3945
""" Bear -> a Bear """
4046

41-
out = getoutput('{} Bear'.format(prg))
42-
assert out.strip() == 'a Bear'
47+
for word in consonant_words:
48+
out = getoutput('{} {}'.format(prg, word.title()))
49+
assert out.strip() == 'a ' + word.title()
4350

4451

4552
# --------------------------------------------------
4653
def test_03():
4754
""" octopus -> an octopus """
4855

49-
out = getoutput('{} octopus'.format(prg))
50-
assert out.strip() == 'an octopus'
56+
for word in vowel_words:
57+
out = getoutput('{} {}'.format(prg, word))
58+
assert out.strip() == 'an ' + word
5159

5260

5361
# --------------------------------------------------
5462
def test_04():
5563
""" Octopus -> an Octopus """
5664

57-
out = getoutput('{} Octopus'.format(prg))
58-
assert out.strip() == 'an Octopus'
65+
for word in vowel_words:
66+
out = getoutput('{} {}'.format(prg, word.title()))
67+
assert out.strip() == 'an ' + word.title()
Collapse file

‎bin/appendices.txt‎

Copy file name to clipboard
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
argparse
2+
truthiness
3+
markov
File renamed without changes.
Collapse file

‎bin/compile.py‎

Copy file name to clipboardExpand all lines: bin/compile.py
+49-17Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,17 @@ def get_args():
4343
default=os.getcwd())
4444

4545
parser.add_argument('-c',
46-
'--contents',
47-
help='Table of contents',
48-
metavar='str',
49-
type=str,
46+
'--chapters',
47+
help='Chapters listing',
48+
metavar='FILE',
49+
type=argparse.FileType('r'),
50+
default=None)
51+
52+
parser.add_argument('-a',
53+
'--appendix',
54+
help='Appendix listing',
55+
metavar='FILE',
56+
type=argparse.FileType('r'),
5057
default=None)
5158

5259
return parser.parse_args()
@@ -59,19 +66,26 @@ def main():
5966
args = get_args()
6067
in_dir = args.dir
6168
out_dir = args.outdir
62-
contents = args.contents
69+
chapters = args.chapters
70+
appendix = args.appendix
71+
cur_dir = os.path.dirname(sys.argv[0])
72+
73+
if not chapters:
74+
chapters = os.path.join(cur_dir, 'chapters.txt')
6375

64-
if not contents:
65-
cur_dir = os.path.dirname(sys.argv[0])
66-
contents = os.path.join(cur_dir, 'contents.txt')
76+
if not os.path.isfile(chapters):
77+
die('--chapters "{}" is not a file'.format(chapters))
6778

68-
if not os.path.isfile(contents):
69-
die('Bad --contents "{}"'.format(contents))
79+
if not appendix:
80+
appendix = os.path.join(cur_dir, 'appendices.txt')
81+
82+
if appendix and not os.path.isfile(appendix):
83+
die('--appendix "{}" is not a file'.format(appendix))
7084

7185
book_file = os.path.join(out_dir, 'book.md')
7286

7387
with open(book_file, 'wt') as fh:
74-
fh.write('\\setcounter{tocdepth}{1}\\tableofcontents\n\\newpage\n\n')
88+
fh.write('\\setcounter{tocdepth}{2}\\tableofcontents\n\\newpage\n\n')
7589

7690
top_readme = 'README.md'
7791
if os.path.isfile(top_readme):
@@ -83,8 +97,8 @@ def main():
8397
fh.write(open(outline).read())
8498
fh.write('\n\\newpage\n\n')
8599

86-
for i, dir_name in enumerate(map(str.rstrip, open(contents)), 1):
87-
print('{:3}: {}'.format(i, dir_name))
100+
for i, dir_name in enumerate(map(str.rstrip, open(chapters)), 1):
101+
print('Chapter {}: {}'.format(i, dir_name))
88102
readme = os.path.join(in_dir, dir_name, 'README.md')
89103
if os.path.isfile(readme):
90104
print('\tREADME')
@@ -93,16 +107,34 @@ def main():
93107
text = re.sub(r'^#\s+', '# ' + chapter, text)
94108
fh.write(text + '\n\\newpage\n\n')
95109

96-
solution = os.path.join(in_dir, dir_name, 'solution.py')
97-
if os.path.isfile(solution):
98-
print('\tSOLUTION')
110+
solution_py = os.path.join(in_dir, dir_name, 'solution.py')
111+
if os.path.isfile(solution_py):
112+
print('\tSOLUTION PY')
99113
fh.write('## Solution\n\n')
100114
fh.write('````\n')
101-
numbered = getoutput('cat -n {}'.format(solution))
115+
numbered = getoutput('cat -n {}'.format(solution_py))
102116
fh.write(numbered)
103117
fh.write('\n````\n')
104118
fh.write('\n\\newpage\n\n')
105119

120+
solution_md = os.path.join(in_dir, dir_name, 'discussion.md')
121+
if os.path.isfile(solution_md):
122+
print('\tDISCUSSION MD')
123+
fh.write('## Discussion\n\n')
124+
fh.write(open(solution_md).read())
125+
fh.write('\n\\newpage\n\n')
126+
127+
if appendix:
128+
for i, dir_name in enumerate(map(str.rstrip, open(appendix)), 1):
129+
print('Appendix {}: {}'.format(i, dir_name))
130+
readme = os.path.join(in_dir, 'appendix', dir_name, 'README.md')
131+
if os.path.isfile(readme):
132+
print('\tREADME')
133+
header = 'Appendix {}: '.format(i)
134+
text = open(readme).read()
135+
text = re.sub(r'^#\s+', '# ' + header, text)
136+
fh.write(text + '\n\\newpage\n\n')
137+
106138
cmd = 'pandoc {} --pdf-engine=xelatex -o {}'
107139
rv, out = getstatusoutput(cmd.format(book_file, args.outfile))
108140

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.