Commit 7eeedd47 by David Ormsbee

Merge pull request #634 from MITx/feature/victor/per-run-info

Feature/victor/per run info
parents 978ff5b4 550889ea
......@@ -208,7 +208,8 @@ __IMPORTANT__: A student's state for a particular content element is tied to the
* Note: We will be expanding our understanding and format for metadata in the not-too-distant future, but for now it is simply a set of key-value pairs.
### Policy file location
* The policy for a course run `some_url_name` lives in `policies/some_url_name.json`
* The policy for a course run `some_url_name` should live in `policies/some_url_name/policy.json` (NOTE: the old format of putting it in `policies/some_url_name.json` will also work, but we suggest using the subdirectory to have all the per-course policy files in one place)
* Grading policy files go in `policies/some_url_name/grading_policy.json` (if there's only one course run, can also put it directly in the course root: `/grading_policy.json`)
### Policy file contents
* The file format is "json", and is best shown by example, as in the tutorial above (though also feel free to google :)
......@@ -218,6 +219,45 @@ Values are dictionaries of the form {"metadata-key" : "metadata-value"}.
* The order in which things appear does not matter, though it may be helpful to organize the file in the same order as things appear in the content.
* NOTE: json is picky about commas. If you have trailing commas before closing braces, it will complain and refuse to parse the file. This can be irritating at first.
### Grading policy file contents
TODO: This needs to be improved, but for now here's a sketch of how grading works:
* First we grade on individual problems. Correct and total are methods on CapaProblem.
`problem_score = (correct , total)`
* If a problem weight is in the xml, then re-weight the problem to be worth that many points
`if problem_weight:`
`problem_score = (correct * weight / total, weight)`
* Now sum up all of problems in a section to get the percent for that section
`section_percent = \sum_problems_correct / \sum_problems_total`
* Now we have all of the percents for all of the graded sections. This is the gradesheet that we pass to to a subclass of CourseGrader.
* A WeightedSubsectionsGrader contains several SingleSectionGraders and AssignmentFormatGraders. Each of those graders is run first before WeightedSubsectionsGrader computes the final grade.
- SingleSectionGrader (within a WeightedSubsectionsGrader) contains one section
`grader_percent = section_percent`
- AssignmentFormatGrader (within a WegithedSubsectionsGrader) contains multiple sections matching a certain format
drop the lowest X sections
`grader_percent = \sum_section_percent / \count_section`
- WeightedSubsectionsGrader
`final_grade_percent = \sum_(grader_percent * grader_weight)`
* Round the final grade up to the nearest percentage point
`final_grade_percent = round(final_grade_percent * 100 + 0.05) / 100`
### Available metadata
__Not inherited:__
......@@ -316,6 +356,22 @@ before the week 1 material to make it easy to find in the file.
* Prefer the most "semantic" name for containers: e.g., use problemset rather than vertical for a problem set. That way, if we decide to display problem sets differently, we don't have to change the xml.
# Other file locations (info and about)
With different course runs, we may want different course info and about materials. This is now supported by putting files in as follows:
/
about/
foo.html -- shared default for all runs
url_name1/
foo.html -- version used for url_name1
bar.html -- bar for url_name1
url_name2/
bar.html -- bar for url_name2
-- url_name2 will use default foo.html
and the same works for the `info` directory.
----
(Dev note: This file is generated from the mitx repo, in `doc/xml-format.md`. Please make edits there.)
......@@ -64,6 +64,22 @@ def course_image_url(course):
path = course.metadata['data_dir'] + "/images/course_image.jpg"
return try_staticfiles_lookup(path)
def find_file(fs, dirs, filename):
"""
Looks for a filename in a list of dirs on a filesystem, in the specified order.
fs: an OSFS filesystem
dirs: a list of path objects
filename: a string
Returns d / filename if found in dir d, else raises ResourceNotFoundError.
"""
for d in dirs:
filepath = path(d) / filename
if fs.exists(filepath):
return filepath
raise ResourceNotFoundError("Could not find {0}".format(filename))
def get_course_about_section(course, section_key):
"""
This returns the snippet of html to be rendered on the course about page,
......@@ -97,8 +113,13 @@ def get_course_about_section(course, section_key):
'requirements', 'syllabus', 'textbook', 'faq', 'more_info',
'number', 'instructors', 'overview',
'effort', 'end_date', 'prerequisites']:
try:
with course.system.resources_fs.open(path("about") / section_key + ".html") as htmlFile:
fs = course.system.resources_fs
# first look for a run-specific version
dirs = [path("about") / course.url_name, path("about")]
filepath = find_file(fs, dirs, section_key + ".html")
with fs.open(filepath) as htmlFile:
return replace_urls(htmlFile.read().decode('utf-8'),
course.metadata['data_dir'])
except ResourceNotFoundError:
......@@ -133,7 +154,12 @@ def get_course_info_section(course, section_key):
if section_key in ['handouts', 'guest_handouts', 'updates', 'guest_updates']:
try:
with course.system.resources_fs.open(path("info") / section_key + ".html") as htmlFile:
fs = course.system.resources_fs
# first look for a run-specific version
dirs = [path("info") / course.url_name, path("info")]
filepath = find_file(fs, dirs, section_key + ".html")
with fs.open(filepath) as htmlFile:
# Replace '/static/' urls
info_html = replace_urls(htmlFile.read().decode('utf-8'), course.metadata['data_dir'])
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment