Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
a6c8d90a
Commit
a6c8d90a
authored
Oct 24, 2012
by
Calen Pennington
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #958 from MITx/feature/cdodge/import-grading-policy
Feature/cdodge/import grading policy
parents
ef1ba6d9
ae4df32e
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
123 additions
and
105 deletions
+123
-105
common/lib/xmodule/xmodule/course_module.py
+121
-11
common/lib/xmodule/xmodule/graders.py
+0
-63
common/lib/xmodule/xmodule/modulestore/xml.py
+0
-29
common/lib/xmodule/xmodule/modulestore/xml_importer.py
+2
-2
No files found.
common/lib/xmodule/xmodule/course_module.py
View file @
a6c8d90a
from
fs.errors
import
ResourceNotFoundError
import
logging
import
json
from
lxml
import
etree
from
path
import
path
# NOTE (THK): Only used for detecting presence of syllabus
import
requests
import
time
from
cStringIO
import
StringIO
from
xmodule.util.decorators
import
lazyproperty
from
xmodule.graders
import
load_grading_policy
from
xmodule.modulestore
import
Location
from
xmodule.seq_module
import
SequenceDescriptor
,
SequenceModule
from
xmodule.xml_module
import
XmlDescriptor
from
xmodule.timeparse
import
parse_time
,
stringify_time
from
xmodule.graders
import
grader_from_conf
log
=
logging
.
getLogger
(
__name__
)
edx_xml_parser
=
etree
.
XMLParser
(
dtd_validation
=
False
,
load_dtd
=
False
,
remove_comments
=
True
,
remove_blank_text
=
True
)
class
CourseDescriptor
(
SequenceDescriptor
):
module_class
=
SequenceModule
...
...
@@ -96,16 +102,119 @@ class CourseDescriptor(SequenceDescriptor):
# disable the syllabus content for courses that do not provide a syllabus
self
.
syllabus_present
=
self
.
system
.
resources_fs
.
exists
(
path
(
'syllabus'
))
def
set_grading_policy
(
self
,
policy_str
):
"""Parse the policy specified in policy_str, and save it"""
try
:
self
.
_grading_policy
=
load_grading_policy
(
policy_str
)
except
:
self
.
system
.
error_tracker
(
"Failed to load grading policy"
)
# Setting this to an empty dictionary will lead to errors when
# grading needs to happen, but should allow course staff to see
# the error log.
self
.
_grading_policy
=
{}
self
.
set_grading_policy
(
self
.
definition
[
'data'
]
.
get
(
'grading_policy'
,
None
))
def
set_grading_policy
(
self
,
course_policy
):
if
course_policy
is
None
:
course_policy
=
{}
"""
The JSON object can have the keys GRADER and GRADE_CUTOFFS. If either is
missing, it reverts to the default.
"""
default_policy_string
=
"""
{
"GRADER" : [
{
"type" : "Homework",
"min_count" : 12,
"drop_count" : 2,
"short_label" : "HW",
"weight" : 0.15
},
{
"type" : "Lab",
"min_count" : 12,
"drop_count" : 2,
"category" : "Labs",
"weight" : 0.15
},
{
"type" : "Midterm",
"name" : "Midterm Exam",
"short_label" : "Midterm",
"weight" : 0.3
},
{
"type" : "Final",
"name" : "Final Exam",
"short_label" : "Final",
"weight" : 0.4
}
],
"GRADE_CUTOFFS" : {
"A" : 0.87,
"B" : 0.7,
"C" : 0.6
}
}
"""
# Load the global settings as a dictionary
grading_policy
=
json
.
loads
(
default_policy_string
)
# Override any global settings with the course settings
grading_policy
.
update
(
course_policy
)
# Here is where we should parse any configurations, so that we can fail early
grading_policy
[
'GRADER'
]
=
grader_from_conf
(
grading_policy
[
'GRADER'
])
self
.
_grading_policy
=
grading_policy
@classmethod
def
read_grading_policy
(
cls
,
paths
,
system
):
"""Load a grading policy from the specified paths, in order, if it exists."""
# Default to a blank policy
policy_str
=
""
for
policy_path
in
paths
:
if
not
system
.
resources_fs
.
exists
(
policy_path
):
continue
log
.
debug
(
"Loading grading policy from {0}"
.
format
(
policy_path
))
try
:
with
system
.
resources_fs
.
open
(
policy_path
)
as
grading_policy_file
:
policy_str
=
grading_policy_file
.
read
()
# if we successfully read the file, stop looking at backups
break
except
(
IOError
):
msg
=
"Unable to load course settings file from '{0}'"
.
format
(
policy_path
)
log
.
warning
(
msg
)
return
policy_str
@classmethod
def
from_xml
(
cls
,
xml_data
,
system
,
org
=
None
,
course
=
None
):
instance
=
super
(
CourseDescriptor
,
cls
)
.
from_xml
(
xml_data
,
system
,
org
,
course
)
# bleh, have to parse the XML here to just pull out the url_name attribute
course_file
=
StringIO
(
xml_data
)
xml_obj
=
etree
.
parse
(
course_file
,
parser
=
edx_xml_parser
)
.
getroot
()
policy_dir
=
None
url_name
=
xml_obj
.
get
(
'url_name'
,
xml_obj
.
get
(
'slug'
))
if
url_name
:
policy_dir
=
'policies/'
+
url_name
# Try to load grading policy
paths
=
[
'grading_policy.json'
]
if
policy_dir
:
paths
=
[
policy_dir
+
'grading_policy.json'
]
+
paths
policy
=
json
.
loads
(
cls
.
read_grading_policy
(
paths
,
system
))
# cdodge: import the grading policy information that is on disk and put into the
# descriptor 'definition' bucket as a dictionary so that it is persisted in the DB
instance
.
definition
[
'data'
][
'grading_policy'
]
=
policy
# now set the current instance. set_grading_policy() will apply some inheritance rules
instance
.
set_grading_policy
(
policy
)
return
instance
@classmethod
def
definition_from_xml
(
cls
,
xml_object
,
system
):
...
...
@@ -284,3 +393,4 @@ class CourseDescriptor(SequenceDescriptor):
def
org
(
self
):
return
self
.
location
.
org
common/lib/xmodule/xmodule/graders.py
View file @
a6c8d90a
...
...
@@ -13,69 +13,6 @@ log = logging.getLogger("mitx.courseware")
# Section either indicates the name of the problem or the name of the section
Score
=
namedtuple
(
"Score"
,
"earned possible graded section"
)
def
load_grading_policy
(
course_policy_string
):
"""
This loads a grading policy from a string (usually read from a file),
which can be a JSON object or an empty string.
The JSON object can have the keys GRADER and GRADE_CUTOFFS. If either is
missing, it reverts to the default.
"""
default_policy_string
=
"""
{
"GRADER" : [
{
"type" : "Homework",
"min_count" : 12,
"drop_count" : 2,
"short_label" : "HW",
"weight" : 0.15
},
{
"type" : "Lab",
"min_count" : 12,
"drop_count" : 2,
"category" : "Labs",
"weight" : 0.15
},
{
"type" : "Midterm",
"name" : "Midterm Exam",
"short_label" : "Midterm",
"weight" : 0.3
},
{
"type" : "Final",
"name" : "Final Exam",
"short_label" : "Final",
"weight" : 0.4
}
],
"GRADE_CUTOFFS" : {
"A" : 0.87,
"B" : 0.7,
"C" : 0.6
}
}
"""
# Load the global settings as a dictionary
grading_policy
=
json
.
loads
(
default_policy_string
)
# Load the course policies as a dictionary
course_policy
=
{}
if
course_policy_string
:
course_policy
=
json
.
loads
(
course_policy_string
)
# Override any global settings with the course settings
grading_policy
.
update
(
course_policy
)
# Here is where we should parse any configurations, so that we can fail early
grading_policy
[
'GRADER'
]
=
grader_from_conf
(
grading_policy
[
'GRADER'
])
return
grading_policy
def
aggregate_scores
(
scores
,
section_name
=
"summary"
):
"""
...
...
common/lib/xmodule/xmodule/modulestore/xml.py
View file @
a6c8d90a
...
...
@@ -341,27 +341,6 @@ class XMLModuleStore(ModuleStoreBase):
return
{}
def
read_grading_policy
(
self
,
paths
,
tracker
):
"""Load a grading policy from the specified paths, in order, if it exists."""
# Default to a blank policy
policy_str
=
""
for
policy_path
in
paths
:
if
not
os
.
path
.
exists
(
policy_path
):
continue
log
.
debug
(
"Loading grading policy from {0}"
.
format
(
policy_path
))
try
:
with
open
(
policy_path
)
as
grading_policy_file
:
policy_str
=
grading_policy_file
.
read
()
# if we successfully read the file, stop looking at backups
break
except
(
IOError
):
msg
=
"Unable to load course settings file from '{0}'"
.
format
(
policy_path
)
tracker
(
msg
)
log
.
warning
(
msg
)
return
policy_str
def
load_course
(
self
,
course_dir
,
tracker
):
"""
...
...
@@ -444,14 +423,6 @@ class XMLModuleStore(ModuleStoreBase):
# after we have the course descriptor.
XModuleDescriptor
.
compute_inherited_metadata
(
course_descriptor
)
# Try to load grading policy
paths
=
[
self
.
data_dir
/
course_dir
/
'grading_policy.json'
]
if
policy_dir
:
paths
=
[
policy_dir
/
'grading_policy.json'
]
+
paths
policy_str
=
self
.
read_grading_policy
(
paths
,
tracker
)
course_descriptor
.
set_grading_policy
(
policy_str
)
log
.
debug
(
'========> Done with course import from {0}'
.
format
(
course_dir
))
return
course_descriptor
...
...
common/lib/xmodule/xmodule/modulestore/xml_importer.py
View file @
a6c8d90a
...
...
@@ -76,11 +76,12 @@ def import_from_xml(store, data_dir, course_dirs=None,
all course dirs
"""
module_store
=
XMLModuleStore
(
data_dir
,
default_class
=
default_class
,
course_dirs
=
course_dirs
,
load_error_modules
=
load_error_modules
,
load_error_modules
=
load_error_modules
)
# NOTE: the XmlModuleStore does not implement get_items() which would be a preferable means
...
...
@@ -123,6 +124,5 @@ def import_from_xml(store, data_dir, course_dirs=None,
# NOTE: It's important to use own_metadata here to avoid writing
# inherited metadata everywhere.
store
.
update_metadata
(
module
.
location
,
dict
(
module
.
own_metadata
))
return
module_store
,
course_items
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment