1010
1111import os
1212import re
13+ import sys
14+
1315import yaml
1416
1517#----------------------------------------
1618# Error reporting.
1719
1820def report_error (file_path , line_number , line , error_message ):
19- '''
20- FIXME: docstring .
21- '''
21+ """
22+ Print information about general error .
23+ """
2224 ERR_MSG = "Error at line {} of {}:\n \t {}\n {}"
2325 print (ERR_MSG .format (line_number , file_path , line , error_message ))
2426
2527def report_missing (present , file_path , missing_element ):
26- '''
27- FIXME: docstring .
28- '''
28+ """
29+ Print information about missing element .
30+ """
2931 ERR_MSG = "Error on {}: missing {}"
3032 if not present :
3133 print (ERR_MSG .format (file_path , missing_element ))
3234
3335def report_missing_metadata (missing_element ):
34- '''
35- FIXME: docstring .
36- '''
36+ """
37+ Print information about missing metadata at YAML header .
38+ """
3739 ERR_MSG = "Error on YAML header: missing {}"
3840 print (ERR_MSG .format (missing_element ))
3941
4042def report_broken_link (file_path , line_number , link ):
41- '''
42- FIXME: docstring .
43- '''
43+ """
44+ Print information about broken link .
45+ """
4446 ERR_MSG = "Broken link at line {} of {}:\n \t Can't find {}."
4547 print (ERR_MSG .format (line_number , file_path , link ))
4648
@@ -55,23 +57,50 @@ def check_yaml(metadata):
5557 for key in METADATA_REQUIRED - set (metadata .keys ()):
5658 report_missing_metadata (key )
5759
60+ # TODO: Implement check_lesson
5861def check_lesson (file_path ):
59- '''
60- FIXME: docstring telling people what you want them to write here.
61- '''
62+ """
63+ Checks the file ``pages/[0-9]{2}-.*.md`` for:
64+
65+ - "layout: topic" at YAML header
66+ - "title" as keyword at YAML header
67+ - line "> ## Learning Objectives {.objectives}" after YAML header
68+ - items at learning objectives begin with "*"
69+ - items at learning objective following four space rule
70+ - code samples be of type error, output, python, shell, r, matlab, sql
71+ - callout box style
72+ - line with "> ## Key Points {.keypoints}"
73+ - challenge box style
74+ """
6275 pass
6376
77+ # TODO: Implement check_discussion
6478def check_discussion (file_path ):
65- '''
66- FIXME: docstring telling people what you want them to write here.
67- '''
79+ """
80+ Checks the file ``pages/discussion.md`` for:
81+
82+ FIXME: tell what need to check.
83+ """
6884 pass
6985
86+ # TODO: Complete implementation of check_index
87+ # TODO: break check_index into pieces -- it's too long.
7088def check_index (file_path ):
71- '''
72- FIXME: docstring.
73- And break this up into pieces -- it's too long.
74- '''
89+ """
90+ Checks the file ``pages/index.md`` for:
91+
92+ - "layout: lesson" in YAML header
93+ - "title" as keyword in YAML header
94+ - introductory paragraph right after YAML header
95+ - line with "> ## Prerequisites"
96+ - non empty prerequisites
97+ - line with "## Topics"
98+ - items at topic list begin with "*"
99+ - links at topic list are valid
100+ - line with "## Other Resources"
101+ - items at other resources list begin with "*"
102+ - link at other resources list are valid
103+ """
75104 # State variables
76105 in_yaml = False
77106 yaml_metadata = []
@@ -80,85 +109,105 @@ def check_index(file_path):
80109 has_other_resources = False
81110
82111 # Load file and process it
83- with open (file_path , 'r' ) as lines :
112+ with open (file_path , "r" ) as lines :
84113 for line_number , line in enumerate (lines ):
85- if re .match (' ---' , line ): # what if there are multiple YAML blocks??
114+ if re .match (" ---" , line ): # what if there are multiple YAML blocks??
86115 in_yaml = not in_yaml
87116 elif in_yaml :
88117 yaml_metadata .append (line )
89- elif re .match (' > ## Prerequisites' , line ): # check this in the Markdown or in the generated HTML?
118+ elif re .match (" > ## Prerequisites" , line ): # check this in the Markdown or in the generated HTML?
90119 has_prerequisites = True
91- elif re .match (' ## Topics' , line ): # as above?
120+ elif re .match (" ## Topics" , line ): # as above?
92121 has_topics = True
93- elif re .match (' ## Other Resources' , line ): # as above
122+ elif re .match (" ## Other Resources" , line ): # as above
94123 has_other_resources = True
95124 else :
96125 ## Push this check into another function - this one is getting too long.
97126 # Check if local links are valid
98- matches = re .search (' \[.*\]\((?P<link>.*)\)' , line )
127+ matches = re .search (" \[.*\]\((?P<link>.*)\)" , line )
99128 if matches and not matches .group ("link" ).startswith ("http" ):
100129 link = os .path .join (os .path .dirname (file_path ), matches .group ("link" ))
101130 if link .endswith (".html" ):
102- link = link .replace ("html" , "md" ) # NO: what about ' 03-html-editing.html' ?
131+ link = link .replace ("html" , "md" ) # NO: what about " 03-html-editing.html" ?
103132 if not os .path .exists (link ):
104133 report_broken_link (file_path , line_number , link )
105134
106135 ## Again, this function is too long - break it into sub-functions.
107136 # Check YAML
108- yaml_metadata = yaml .load (' \n ' .join (yaml_metadata ))
109- check_yaml (yaml_metadata , { "minutes" } )
137+ yaml_metadata = yaml .load (" \n " .join (yaml_metadata ))
138+ check_yaml (yaml_metadata )
110139
111140 # Check sections
112141 ## Note the refactoring: replaces three conditionals with one.
113142 report_missing (has_prerequisites , file_path , "Prerequisites" )
114143 report_missing (has_topics , file_path , "Topics" )
115144 report_missing (has_other_resources , file_path , "Other Resources" )
116145
146+ # TODO Implement check_intructors
117147def check_intructors (file_path ):
118- '''
119- FIXME: docstring telling people what you want them to write here.
120- '''
148+ """
149+ Checks the file ``pages/instructors.md`` for:
150+
151+ - "title: Instructor"s Guide" in YAML header
152+ - line with "## Overall"
153+ - line with "## General Points"
154+ - lines with topics titles begin with "## "
155+ - points begin with "*" and following four space rules.
156+ """
121157 pass
122158
159+ # TODO Implement check_motivation
123160def check_motivation (file_path ):
124- '''
125- FIXME: docstring telling people what you want them to write here.
126- '''
161+ """
162+ Checks the file ``pages/motivation.md``.
163+
164+ FIXME: tell what need to check.
165+ """
127166 pass
128167
168+ # TODO Implement check_reference
129169def check_reference (file_path ):
130- '''
131- FIXME: docstring telling people what you want them to write here.
132- '''
170+ """
171+ Checks the file ``pages/reference.md`` for:
172+
173+ - ``layout: reference`` in YAML header
174+ - line with "## Glossary"
175+ - words definitions after at the "Glossary" as::
176+
177+ > **Key Word 1**: the definition
178+ > relevant to the lesson.
179+ """
133180 pass
134181
135182def check_file (file_path ):
136- '''
137- FIXME: docstring telling people what you want them to write here .
138- '''
139- ## Functions are objects, and so can be put in tables like the one below.
183+ """
184+ Call the correctly check function based on the name of the file .
185+ """
186+ # Pair of regex and function to call
140187 CONTROL = (
141- (' [0-9]{2}-.*' , check_lesson ),
142- (' discussion' , check_discussion ),
143- (' index' , check_index ),
144- (' instructors' , check_intructors ),
188+ (" [0-9]{2}-.*" , check_lesson ),
189+ (" discussion" , check_discussion ),
190+ (" index" , check_index ),
191+ (" instructors" , check_intructors ),
145192 ("motivation" , check_motivation ),
146193 ("reference" , check_reference )
147194 )
148195 for (pattern , checker ) in CONTROL :
149196 if re .search (pattern , file_path ):
150197 checker (file_path )
151198
152- ## main doesn't take sys.argv[1:] or the like? Will help with testing...
153- def main ():
154- '''
155- FIXME: docstring telling people what you want them to write here.
156- '''
157- lessons_file = os .listdir ("pages" )
158- for lesson in lessons_file :
159- if lesson .endswith ('.md' ):
160- ## Why not os.path.join('pages', lesson) ?
161- check_file ('pages/{}' .format (lesson ))
199+ def main (list_of_files ):
200+ """
201+ Call the check function for every file in ``list_of_files``.
202+
203+ If ``list_of_files`` is empty load all the files from ``pages`` directory.
204+ """
205+ if not list_of_files :
206+ list_of_files = [os .path .join ("pages" , filename ) for filename in os .listdir ("pages" )]
207+
208+ for filename in list_of_files :
209+ if filename .endswith (".md" ):
210+ check_file (filename )
162211
163212if __name__ == "__main__" :
164- main ()
213+ main (sys . argv [ 1 :] )
0 commit comments