Merge with template view
This commit is contained in:
@@ -49,7 +49,7 @@ def xpath(xml, query_string, **args):
|
||||
We should remove this with the move to lxml.
|
||||
We should also use lxml argument passing. '''
|
||||
doc = etree.fromstring(xml)
|
||||
print type(doc)
|
||||
#print type(doc)
|
||||
def escape(x):
|
||||
# TODO: This should escape the string. For now, we just assume it's made of valid characters.
|
||||
# Couldn't figure out how to escape for lxml in a few quick Googles
|
||||
@@ -60,7 +60,7 @@ def xpath(xml, query_string, **args):
|
||||
return x
|
||||
|
||||
args=dict( ((k, escape(args[k])) for k in args) )
|
||||
print args
|
||||
#print args
|
||||
results = doc.xpath(query_string.format(**args))
|
||||
return results
|
||||
|
||||
@@ -86,14 +86,20 @@ def item(l, default="", process=lambda x:x):
|
||||
|
||||
def id_tag(course):
|
||||
''' Tag all course elements with unique IDs '''
|
||||
default_ids = {'video':'youtube',
|
||||
old_ids = {'video':'youtube',
|
||||
'problem':'filename',
|
||||
'sequential':'id',
|
||||
'html':'filename',
|
||||
'vertical':'id',
|
||||
'tab':'id',
|
||||
'schematic':'id'}
|
||||
|
||||
'schematic':'id',
|
||||
'book' : 'id'}
|
||||
import courseware.modules
|
||||
default_ids = courseware.modules.get_default_ids()
|
||||
|
||||
#print default_ids, old_ids
|
||||
#print default_ids == old_ids
|
||||
|
||||
# Tag elements with unique IDs
|
||||
elements = course.xpath("|".join(['//'+c for c in default_ids]))
|
||||
for elem in elements:
|
||||
@@ -143,7 +149,7 @@ def course_file(user):
|
||||
filename = UserProfile.objects.get(user=user).courseware
|
||||
data_template = template_lookup.get_template(filename)
|
||||
|
||||
options = {'dev_content':True}
|
||||
options = {'dev_content':settings.DEV_CONTENT}
|
||||
|
||||
tree = etree.XML(data_template.render(**options))
|
||||
id_tag(tree)
|
||||
|
||||
@@ -41,6 +41,7 @@ class Command(BaseCommand):
|
||||
if os.path.exists(sections_dir):
|
||||
print "Checking all section includes are valid XML"
|
||||
for f in os.listdir(sections_dir):
|
||||
print f
|
||||
etree.parse(sections_dir+'/'+f)
|
||||
else:
|
||||
print "Skipping check of include files -- no section includes dir ("+sections_dir+")"
|
||||
|
||||
@@ -26,24 +26,10 @@ import track.views
|
||||
|
||||
import courseware.content_parser as content_parser
|
||||
|
||||
import courseware.modules.capa_module
|
||||
import courseware.modules.html_module
|
||||
import courseware.modules.schematic_module
|
||||
import courseware.modules.seq_module
|
||||
import courseware.modules.vertical_module
|
||||
import courseware.modules.video_module
|
||||
import courseware.modules
|
||||
|
||||
log = logging.getLogger("mitx.courseware")
|
||||
|
||||
## TODO: Add registration mechanism
|
||||
modx_modules={'problem':courseware.modules.capa_module.LoncapaModule,
|
||||
'video':courseware.modules.video_module.VideoModule,
|
||||
'html':courseware.modules.html_module.HtmlModule,
|
||||
'vertical':courseware.modules.vertical_module.VerticalModule,
|
||||
'sequential':courseware.modules.seq_module.SequentialModule,
|
||||
'tab':courseware.modules.seq_module.SequentialModule,
|
||||
'schematic':courseware.modules.schematic_module.SchematicModule}
|
||||
|
||||
def object_cache(cache, user, module_type, module_id):
|
||||
# We don't look up on user -- all queries include user
|
||||
# Additional lookup would require a DB hit the way Django
|
||||
@@ -74,18 +60,18 @@ def modx_dispatch(request, module=None, dispatch=None, id=None):
|
||||
|
||||
ajax_url = '/modx/'+module+'/'+id+'/'
|
||||
|
||||
id_tag=modx_modules[module].id_attribute
|
||||
id_tag=courseware.modules.get_module_class(module.id_attribute)
|
||||
|
||||
# Grab the XML corresponding to the request from course.xml
|
||||
xml = content_parser.module_xml(content_parser.course_file(request.user), module, id_tag, id)
|
||||
|
||||
# Create the module
|
||||
instance=modx_modules[module](xml,
|
||||
s.module_id,
|
||||
ajax_url=ajax_url,
|
||||
state=s.state,
|
||||
track_function = make_track_function(request),
|
||||
render_function = None)
|
||||
instance=courseware.modules.get_module_class(module)(xml,
|
||||
s.module_id,
|
||||
ajax_url=ajax_url,
|
||||
state=s.state,
|
||||
track_function = make_track_function(request),
|
||||
render_function = None)
|
||||
# Let the module handle the AJAX
|
||||
ajax_return=instance.handle_ajax(dispatch, request.POST)
|
||||
# Save the state back to the database
|
||||
@@ -100,7 +86,7 @@ def render_x_module(user, request, xml_module, module_object_preload):
|
||||
''' Generic module for extensions. This renders to HTML. '''
|
||||
# Check if problem has an instance in DB
|
||||
module_type=xml_module.tag
|
||||
module_class=modx_modules[module_type]
|
||||
module_class=courseware.modules.get_module_class(module_type)
|
||||
module_id=xml_module.get('id') #module_class.id_attribute) or ""
|
||||
|
||||
# Grab state from database
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
import os
|
||||
import os.path
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
import capa_module
|
||||
import html_module
|
||||
import schematic_module
|
||||
import seq_module
|
||||
import template_module
|
||||
import vertical_module
|
||||
import video_module
|
||||
|
||||
from courseware import content_parser
|
||||
|
||||
# Import all files in modules directory, excluding backups (# and . in name)
|
||||
# and __init__
|
||||
#
|
||||
# Stick them in a list
|
||||
# modx_module_list = []
|
||||
|
||||
# for f in os.listdir(os.path.dirname(__file__)):
|
||||
# if f!='__init__.py' and \
|
||||
# f[-3:] == ".py" and \
|
||||
# "." not in f[:-3] \
|
||||
# and '#' not in f:
|
||||
# mod_path = 'courseware.modules.'+f[:-3]
|
||||
# mod = __import__(mod_path, fromlist = "courseware.modules")
|
||||
# if 'Module' in mod.__dict__:
|
||||
# modx_module_list.append(mod)
|
||||
|
||||
#print modx_module_list
|
||||
modx_module_list = [capa_module, html_module, schematic_module, seq_module, template_module, vertical_module, video_module]
|
||||
#print modx_module_list
|
||||
|
||||
# Convert list to a dictionary for lookup by tag
|
||||
modx_modules = {}
|
||||
for module in modx_module_list:
|
||||
for tag in module.Module.get_xml_tags():
|
||||
modx_modules[tag] = module.Module
|
||||
|
||||
def get_module_class(tag):
|
||||
''' Given an XML tag (e.g. 'video'), return
|
||||
the associated module (e.g. video_module.Module).
|
||||
'''
|
||||
return modx_modules[tag]
|
||||
|
||||
def get_module_id(tag):
|
||||
''' Given an XML tag (e.g. 'video'), return
|
||||
the default ID for that module (e.g. 'youtube_id')
|
||||
'''
|
||||
return modx_modules[tag].id_attribute
|
||||
|
||||
def get_valid_tags():
|
||||
return modx_modules.keys()
|
||||
|
||||
def get_default_ids():
|
||||
tags = get_valid_tags()
|
||||
ids = map(get_module_id, tags)
|
||||
return dict(zip(tags, ids))
|
||||
|
||||
|
||||
@@ -26,15 +26,18 @@ import courseware.content_parser as content_parser
|
||||
|
||||
log = logging.getLogger("mitx.courseware")
|
||||
|
||||
class LoncapaModule(XModule):
|
||||
class Module(XModule):
|
||||
''' Interface between capa_problem and x_module. Originally a hack
|
||||
meant to be refactored out, but it seems to be serving a useful
|
||||
prupose now. We can e.g .destroy and create the capa_problem on a
|
||||
reset.
|
||||
'''
|
||||
xml_tags = ["problem"]
|
||||
|
||||
id_attribute = "filename"
|
||||
|
||||
@classmethod
|
||||
def get_xml_tags(c):
|
||||
return ["problem"]
|
||||
|
||||
def get_state(self):
|
||||
state = self.lcp.get_state()
|
||||
|
||||
@@ -7,14 +7,15 @@ from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
from x_module import XModule
|
||||
from lxml import etree
|
||||
|
||||
class HtmlModule(XModule):
|
||||
class Module(XModule):
|
||||
id_attribute = 'filename'
|
||||
|
||||
def get_state(self):
|
||||
return json.dumps({ })
|
||||
|
||||
def get_xml_tags():
|
||||
return "html"
|
||||
@classmethod
|
||||
def get_xml_tags(c):
|
||||
return ["html"]
|
||||
|
||||
def get_html(self):
|
||||
if self.filename==None:
|
||||
|
||||
@@ -6,14 +6,15 @@ from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
|
||||
from x_module import XModule
|
||||
|
||||
class SchematicModule(XModule):
|
||||
class Module(XModule):
|
||||
id_attribute = 'id'
|
||||
|
||||
def get_state(self):
|
||||
return json.dumps({ })
|
||||
|
||||
def get_xml_tags():
|
||||
return "schematic"
|
||||
@classmethod
|
||||
def get_xml_tags(c):
|
||||
return ["schematic"]
|
||||
|
||||
def get_html(self):
|
||||
return '<input type="hidden" class="schematic" name="{item_id}" height="480" width="640">'.format(item_id=self.item_id)
|
||||
|
||||
@@ -13,7 +13,7 @@ from x_module import XModule
|
||||
# OBSOLETE: This obsoletes 'type'
|
||||
class_priority = ['video', 'problem']
|
||||
|
||||
class SequentialModule(XModule):
|
||||
class Module(XModule):
|
||||
''' Layout module which lays out content in a temporal sequence
|
||||
'''
|
||||
id_attribute = 'id'
|
||||
@@ -21,7 +21,8 @@ class SequentialModule(XModule):
|
||||
def get_state(self):
|
||||
return json.dumps({ 'position':self.position })
|
||||
|
||||
def get_xml_tags():
|
||||
@classmethod
|
||||
def get_xml_tags(c):
|
||||
return ["sequential", 'tab']
|
||||
|
||||
def get_html(self):
|
||||
|
||||
29
courseware/modules/template_module.py
Normal file
29
courseware/modules/template_module.py
Normal file
@@ -0,0 +1,29 @@
|
||||
import json
|
||||
import os
|
||||
|
||||
## TODO: Abstract out from Django
|
||||
from django.conf import settings
|
||||
from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
|
||||
from x_module import XModule
|
||||
from lxml import etree
|
||||
|
||||
class Module(XModule):
|
||||
def get_state(self):
|
||||
return json.dumps({ })
|
||||
|
||||
@classmethod
|
||||
def get_xml_tags(c):
|
||||
tags = os.listdir(settings.DATA_DIR+'/custom_tags')
|
||||
return tags
|
||||
|
||||
def get_html(self):
|
||||
return self.html
|
||||
|
||||
def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None, track_function=None, render_function = None):
|
||||
XModule.__init__(self, xml, item_id, ajax_url, track_url, state, track_function, render_function)
|
||||
xmltree = etree.fromstring(xml)
|
||||
filename = xmltree.tag
|
||||
params = dict(xmltree.items())
|
||||
# print params
|
||||
self.html = render_to_string('custom_tags/'+filename, params)
|
||||
@@ -7,14 +7,15 @@ from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
from x_module import XModule
|
||||
from lxml import etree
|
||||
|
||||
class VerticalModule(XModule):
|
||||
class Module(XModule):
|
||||
id_attribute = 'id'
|
||||
|
||||
def get_state(self):
|
||||
return json.dumps({ })
|
||||
|
||||
def get_xml_tags():
|
||||
return "vertical"
|
||||
@classmethod
|
||||
def get_xml_tags(c):
|
||||
return ["vertical"]
|
||||
|
||||
def get_html(self):
|
||||
return render_to_string('vert_module.html',{'items':self.contents})
|
||||
|
||||
@@ -11,8 +11,8 @@ from x_module import XModule
|
||||
|
||||
log = logging.getLogger("mitx.courseware.modules")
|
||||
|
||||
class VideoModule(XModule):
|
||||
#id_attribute = 'youtube'
|
||||
class Module(XModule):
|
||||
id_attribute = 'youtube'
|
||||
video_time = 0
|
||||
|
||||
def handle_ajax(self, dispatch, get):
|
||||
@@ -28,9 +28,10 @@ class VideoModule(XModule):
|
||||
log.debug(u"STATE POSITION {0}".format(self.position))
|
||||
return json.dumps({ 'position':self.position })
|
||||
|
||||
def get_xml_tags():
|
||||
@classmethod
|
||||
def get_xml_tags(c):
|
||||
'''Tags in the courseware file guaranteed to correspond to the module'''
|
||||
return "video"
|
||||
return ["video"]
|
||||
|
||||
def video_list(self):
|
||||
l = self.youtube.split(',')
|
||||
|
||||
@@ -8,9 +8,10 @@ class XModule(object):
|
||||
Initialized on access with __init__, first time with state=None, and
|
||||
then with state
|
||||
'''
|
||||
id_attribute='name' # An attribute guaranteed to be unique
|
||||
id_attribute='id' # An attribute guaranteed to be unique
|
||||
|
||||
def get_xml_tags():
|
||||
@classmethod
|
||||
def get_xml_tags(c):
|
||||
''' Tags in the courseware file guaranteed to correspond to the module '''
|
||||
return []
|
||||
|
||||
|
||||
@@ -1,16 +1,36 @@
|
||||
"""
|
||||
This file demonstrates writing tests using the unittest module. These will pass
|
||||
when you run "manage.py test".
|
||||
import unittest
|
||||
|
||||
Replace this with more appropriate tests for your application.
|
||||
"""
|
||||
import numpy
|
||||
|
||||
from django.test import TestCase
|
||||
import courseware.modules
|
||||
import courseware.capa.calc as calc
|
||||
|
||||
class ModelsTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
class SimpleTest(TestCase):
|
||||
def test_basic_addition(self):
|
||||
"""
|
||||
Tests that 1 + 1 always equals 2.
|
||||
"""
|
||||
self.assertEqual(1 + 1, 2)
|
||||
def test_get_module_class(self):
|
||||
vc = courseware.modules.get_module_class('video')
|
||||
vc_str = "<class 'courseware.modules.video_module.Module'>"
|
||||
self.assertEqual(str(vc), vc_str)
|
||||
video_id = courseware.modules.get_default_ids()['video']
|
||||
self.assertEqual(video_id, 'youtube')
|
||||
|
||||
def test_calc(self):
|
||||
variables={'R1':2.0, 'R3':4.0}
|
||||
functions={'sin':numpy.sin, 'cos':numpy.cos}
|
||||
|
||||
self.assertEqual(calc.evaluator(variables, functions, "10000||sin(7+5)-6k"), 4000.0)
|
||||
self.assertEqual(calc.evaluator({'R1': 2.0, 'R3':4.0}, {}, "13"), 13)
|
||||
self.assertEqual(calc.evaluator(variables, functions, "13"), 13)
|
||||
self.assertEqual(calc.evaluator({'a': 2.2997471478310274, 'k': 9, 'm': 8, 'x': 0.66009498411213041}, {}, "5"), 5)
|
||||
self.assertEqual(calc.evaluator({},{}, "-1"), -1)
|
||||
self.assertEqual(calc.evaluator({},{}, "-0.33"), -.33)
|
||||
self.assertEqual(calc.evaluator({},{}, "-.33"), -.33)
|
||||
exception_happened = False
|
||||
try:
|
||||
evaluator({},{}, "5+7 QWSEKO")
|
||||
except:
|
||||
exception_happened = True
|
||||
self.assertTrue(exception_happened)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user