-#!/usr/bin/env python
-
'''Check that a workshop's index.html metadata is valid. See the
docstrings on the checking functions for a summary of the checks.
'''
+
import sys
import os
import re
from datetime import date
-from util import Reporter, split_metadata
-
+from util import Reporter, split_metadata, load_yaml, check_unwanted_files
# Metadata field patterns.
EMAIL_PATTERN = r'[^@]+@[^@]+\.[^@]+'
URL_PATTERN = r'https?://.+'
# Defaults.
-CARPENTRIES = ("dc", "swc")
+CARPENTRIES = ("dc", "swc", "lc", "cp")
DEFAULT_CONTACT_EMAIL = 'admin@software-carpentry.org'
-USAGE = 'Usage: "check-workshop path/to/root/directory"'
+USAGE = 'Usage: "workshop_check.py path/to/root/directory"'
# Country and language codes. Note that codes mean different things: 'ar'
# is 'Arabic' as a language but 'Argentina' as a country.
@look_for_fixme
def check_carpentry(layout):
- '''"carpentry" in YAML header must be "dc" or "swc".'''
+ '''"carpentry" in YAML header must be "dc", "swc", "lc", or "cp".'''
return layout in CARPENTRIES
and 4-digit year. Examples include 'Feb 18-20, 2025' and 'Feb 18
and 20, 2025'. It may be in languages other than English, but the
month name should be kept short to aid formatting of the main
- Software Carpentry web site.
+ Carpentries web site.
"""
if ',' not in date:
try:
lat, lng = latlng.split(',')
lat = float(lat)
- long = float(lng)
- return (-90.0 <= lat <= 90.0) and (-180.0 <= long <= 180.0)
+ lng = float(lng)
+ return (-90.0 <= lat <= 90.0) and (-180.0 <= lng <= 180.0)
except ValueError:
return False
@look_for_fixme
-def check_email(email):
+def check_emails(emails):
"""
- 'contact' must be a valid email address consisting of characters,
- an '@', and more characters. It should not be the default contact
- email address 'admin@software-carpentry.org'.
+ 'emails' must be a comma-separated list of valid email addresses.
+ The list may be empty. A valid email address consists of characters,
+ an '@', and more characters. It should not contain the default contact
"""
- return bool(re.match(EMAIL_PATTERN, email)) and \
- (email != DEFAULT_CONTACT_EMAIL)
+ # YAML automatically loads list-like strings as lists.
+ if (isinstance(emails, list) and len(emails) >= 0):
+ for email in emails:
+ if ((not bool(re.match(EMAIL_PATTERN, email))) or (email == DEFAULT_CONTACT_EMAIL)):
+ return False
+ else:
+ return False
+
+ return True
def check_eventbrite(eventbrite):
@look_for_fixme
-def check_etherpad(etherpad):
+def check_collaborative_notes(collaborative_notes):
"""
- 'etherpad' must be a valid URL.
+ 'collaborative_notes' must be a valid URL.
"""
- return bool(re.match(URL_PATTERN, etherpad))
+ return bool(re.match(URL_PATTERN, collaborative_notes))
@look_for_fixme
'helper list isn\'t a valid list of format ' +
'["First helper", "Second helper",..]'),
- 'contact': (True, check_email,
- 'contact email invalid or still set to ' +
- '"{0}".'.format(DEFAULT_CONTACT_EMAIL)),
+ 'email': (True, check_emails,
+ 'contact email list isn\'t a valid list of format ' +
+ '["me@example.org", "you@example.org",..] or contains incorrectly formatted email addresses or ' +
+ '"{0}".'.format(DEFAULT_CONTACT_EMAIL)),
'eventbrite': (False, check_eventbrite, 'Eventbrite key appears invalid'),
- 'etherpad': (False, check_etherpad, 'Etherpad URL appears invalid'),
+ 'collaborative_notes': (False, check_collaborative_notes, 'Collaborative Notes URL appears invalid'),
'venue': (False, check_pass, 'venue name not specified'),
}
# REQUIRED is all required categories.
-REQUIRED = set([k for k in HANDLERS if HANDLERS[k][0]])
+REQUIRED = {k for k in HANDLERS if HANDLERS[k][0]}
# OPTIONAL is all optional categories.
-OPTIONAL = set([k for k in HANDLERS if not HANDLERS[k][0]])
+OPTIONAL = {k for k in HANDLERS if not HANDLERS[k][0]}
def check_blank_lines(reporter, raw):
Blank lines are not allowed in category headers.
"""
- lines = [(i, x) for (i, x) in enumerate(raw.strip().split('\n')) if not x.strip()]
+ lines = [(i, x) for (i, x) in enumerate(
+ raw.strip().split('\n')) if not x.strip()]
reporter.check(not lines,
None,
'Blank line(s) in header: {0}',
kind)
carpentry = config.get('carpentry', None)
- reporter.check(carpentry in ('swc', 'dc'),
+ reporter.check(carpentry in ('swc', 'dc', 'lc', 'cp'),
filename,
'Missing or unknown carpentry: {0}',
carpentry)
reporter = Reporter()
check_config(reporter, config_file)
- with open(index_file) as reader:
+ check_unwanted_files(root_dir, reporter)
+ with open(index_file, encoding='utf-8') as reader:
data = reader.read()
check_file(reporter, index_file, data)
reporter.report()