Skip to content

Commit 3d135d3

Browse files
authored
Sync upstream lesson_check (carpentries-incubator#345)
* Sync upstream lesson_check * Exclude `vendor` (not always hidden) from Jekyll
1 parent 4b7115a commit 3d135d3

File tree

4 files changed

+53
-50
lines changed

4 files changed

+53
-50
lines changed

CODE_OF_CONDUCT.md

+3
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,7 @@ we pledge to follow the [Carpentry Code of Conduct][coc].
88
Instances of abusive, harassing, or otherwise unacceptable behavior
99
may be reported by following our [reporting guidelines][coc-reporting].
1010

11+
[coc]: https://docs.carpentries.org/topic_folders/policies/code-of-conduct.html
12+
[coc-reporting]: https://docs.carpentries.org/topic_folders/policies/incident-reporting.html
13+
1114
{% include links.md %}

_config.yml

+1
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ exclude:
159159
- bin/
160160
- .Rproj.user/
161161
- .vendor/
162+
- vendor/
162163
- .docker-vendor/
163164

164165
# Turn on built-in syntax highlighting.

_episodes/16-parallel.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ Pi: 3.140944, memory: 0.022351741790771484 GiB
180180
{{ site.local.prompt }} python pi-serial.py 100000000
181181
Pi: 3.14182724, memory: 2.2351741790771484 GiB
182182
```
183-
{: .bash }
183+
{: .language-bash }
184184

185185
Here we can see that the estimated amount of memory required scales linearly
186186
with the number of samples used.
@@ -278,7 +278,7 @@ Pi: 3.1425492, memory: 0.22351741790771484 GiB, time: 0.351212 s
278278
{{ site.local.prompt }} python pi-serial.py 100000000
279279
Pi: 3.14146608, memory: 2.2351741790771484 GiB, time: 3.735195 s
280280
```
281-
{: .bash }
281+
{: .language-bash }
282282

283283
Here we can see that the amount of time required scales approximately linearly
284284
with the number of samples used.

bin/lesson_check.py

+47-48
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#!/usr/bin/env python3
2-
31
"""
42
Check lesson files and their contents.
53
"""
@@ -32,20 +30,20 @@
3230
# specially. This list must include all the Markdown files listed in the
3331
# 'bin/initialize' script.
3432
REQUIRED_FILES = {
35-
'%/CODE_OF_CONDUCT.md': True,
36-
'%/CONTRIBUTING.md': False,
37-
'%/LICENSE.md': True,
38-
'%/MAINTENANCE.md': False,
39-
'%/README.md': False,
40-
'%/_extras/discuss.md': True,
41-
'%/_extras/guide.md': True,
42-
'%/index.md': True,
43-
'%/reference.md': True,
44-
'%/setup.md': True,
33+
'CODE_OF_CONDUCT.md': True,
34+
'CONTRIBUTING.md': False,
35+
'LICENSE.md': True,
36+
'MAINTENANCE.md': False,
37+
'README.md': False,
38+
os.path.join('_extras', 'discuss.md'): True,
39+
os.path.join('_extras', 'guide.md'): True,
40+
'index.md': True,
41+
'reference.md': True,
42+
'setup.md': True,
4543
}
4644

4745
# Episode filename pattern.
48-
P_EPISODE_FILENAME = re.compile(r'/_episodes/(\d\d)-[-\w]+.md$')
46+
P_EPISODE_FILENAME = re.compile(r'(\d\d)-[-\w]+.md$')
4947

5048
# Pattern to match lines ending with whitespace.
5149
P_TRAILING_WHITESPACE = re.compile(r'\s+$')
@@ -79,32 +77,12 @@
7977
}
8078

8179
# What kinds of code fragments are allowed?
80+
# We allow all 'language-*' code blocks below
8281
KNOWN_CODEBLOCKS = {
83-
'bash',
8482
'error',
85-
'html',
86-
'language-bash',
87-
'language-c',
88-
'language-chapel',
89-
'language-cpp',
90-
'language-d',
91-
'language-fortran',
92-
'language-go',
93-
'language-java',
94-
'language-julia',
95-
'language-lua',
96-
'language-make',
97-
'language-matlab',
98-
'language-perl',
99-
'language-python',
100-
'language-r',
101-
'language-rust',
102-
'language-scala',
103-
'language-shell',
104-
'language-sql',
10583
'output',
106-
'python',
107-
'source'
84+
'source',
85+
'warning'
10886
}
10987

11088
# What fields are required in teaching episode metadata?
@@ -134,9 +112,15 @@ def main():
134112

135113
args = parse_args()
136114
args.reporter = Reporter()
137-
check_config(args.reporter, args.source_dir)
115+
life_cycle = check_config(args.reporter, args.source_dir)
116+
# pre-alpha lessons should report without error
117+
if life_cycle == "pre-alpha":
118+
args.permissive = True
138119
check_source_rmd(args.reporter, args.source_dir, args.parser)
139-
args.references = read_references(args.reporter, args.reference_path)
120+
121+
args.references = {}
122+
if not using_remote_theme(args.source_dir):
123+
args.references = read_references(args.reporter, args.reference_path)
140124

141125
docs = read_all_markdown(args.source_dir, args.parser)
142126
check_fileset(args.source_dir, args.reporter, list(docs.keys()))
@@ -180,7 +164,7 @@ def parse_args():
180164
default=False,
181165
action="store_true",
182166
dest='permissive',
183-
help='Do not raise an error even if there are issues')
167+
help='Do not raise an error even if issues are detected')
184168

185169
args, extras = parser.parse_known_args()
186170
require(args.parser is not None,
@@ -190,6 +174,10 @@ def parse_args():
190174

191175
return args
192176

177+
def using_remote_theme(source_dir):
178+
config_file = os.path.join(source_dir, '_config.yml')
179+
config = load_yaml(config_file)
180+
return 'remote_theme' in config
193181

194182
def check_config(reporter, source_dir):
195183
"""Check configuration file."""
@@ -211,6 +199,9 @@ def check_config(reporter, source_dir):
211199
reporter.check(defaults in config.get('defaults', []),
212200
'configuration',
213201
'"root" not set to "." in configuration')
202+
if 'life_cycle' not in config:
203+
config['life_cycle'] = None
204+
return config['life_cycle']
214205

215206
def check_source_rmd(reporter, source_dir, parser):
216207
"""Check that Rmd episode files include `source: Rmd`"""
@@ -237,7 +228,7 @@ def read_references(reporter, ref_path):
237228
result = {}
238229
urls_seen = set()
239230

240-
with open(ref_path, 'r') as reader:
231+
with open(ref_path, 'r', encoding='utf-8') as reader:
241232
for (num, line) in enumerate(reader, 1):
242233

243234
if P_INTERNAL_INCLUDE_LINK.search(line): continue
@@ -299,17 +290,20 @@ def check_fileset(source_dir, reporter, filenames_present):
299290
"""Are all required files present? Are extraneous files present?"""
300291

301292
# Check files with predictable names.
302-
required = [p.replace('%', source_dir) for p in REQUIRED_FILES]
293+
required = [os.path.join(source_dir, p) for p in REQUIRED_FILES]
303294
missing = set(required) - set(filenames_present)
304295
for m in missing:
305296
reporter.add(None, 'Missing required file {0}', m)
306297

307-
# Check episode files' names.
298+
# Check names of episode files.
308299
seen = []
309300
for filename in filenames_present:
310301
if '_episodes' not in filename:
311302
continue
312-
m = P_EPISODE_FILENAME.search(filename)
303+
304+
# split path to check episode name
305+
base_name = os.path.basename(filename)
306+
m = P_EPISODE_FILENAME.search(base_name)
313307
if m and m.group(1):
314308
seen.append(m.group(1))
315309
else:
@@ -421,7 +415,8 @@ def check_codeblock_classes(self):
421415

422416
for node in self.find_all(self.doc, {'type': 'codeblock'}):
423417
cls = self.get_val(node, 'attr', 'class')
424-
self.reporter.check(cls in KNOWN_CODEBLOCKS,
418+
self.reporter.check(cls is not None and (cls in KNOWN_CODEBLOCKS
419+
or cls.startswith('language-')),
425420
(self.filename, self.get_loc(node)),
426421
'Unknown or missing code block type {0}',
427422
cls)
@@ -493,8 +488,6 @@ def get_loc(self, node):
493488

494489
class CheckNonJekyll(CheckBase):
495490
"""Check a file that isn't translated by Jekyll."""
496-
def __init__(self, args, filename, metadata, metadata_len, text, lines, doc):
497-
super().__init__(args, filename, metadata, metadata_len, text, lines, doc)
498491

499492
def check_metadata(self):
500493
self.reporter.check(self.metadata is None,
@@ -523,7 +516,8 @@ def check(self):
523516
"""Run extra tests."""
524517

525518
super().check()
526-
self.check_reference_inclusion()
519+
if not using_remote_theme():
520+
self.check_reference_inclusion()
527521

528522
def check_metadata(self):
529523
super().check_metadata()
@@ -563,6 +557,11 @@ def check_reference_inclusion(self):
563557
require(last_line,
564558
'No non-empty lines in {0}'.format(self.filename))
565559

560+
include_filename = os.path.split(self.args.reference_path)[-1]
561+
if include_filename not in last_line:
562+
self.reporter.add(self.filename,
563+
'episode does not include "{0}"',
564+
include_filename)
566565

567566

568567
class CheckReference(CheckBase):
@@ -586,7 +585,7 @@ def __init__(self, args, filename, metadata, metadata_len, text, lines, doc):
586585
(re.compile(r'README\.md'), CheckNonJekyll),
587586
(re.compile(r'index\.md'), CheckIndex),
588587
(re.compile(r'reference\.md'), CheckReference),
589-
(re.compile(r'_episodes/.*\.md'), CheckEpisode),
588+
(re.compile(os.path.join('_episodes', '*\.md')), CheckEpisode),
590589
(re.compile(r'.*\.md'), CheckGeneric),
591590
(re.compile(r'.*\.snip'), CheckNonJekyll)
592591
]

0 commit comments

Comments
 (0)