Commit c9430659 by Piotr Mitros

Merge with template view

parents 20ada529 9ab2f591
...@@ -49,7 +49,7 @@ def xpath(xml, query_string, **args): ...@@ -49,7 +49,7 @@ def xpath(xml, query_string, **args):
We should remove this with the move to lxml. We should remove this with the move to lxml.
We should also use lxml argument passing. ''' We should also use lxml argument passing. '''
doc = etree.fromstring(xml) doc = etree.fromstring(xml)
print type(doc) #print type(doc)
def escape(x): def escape(x):
# TODO: This should escape the string. For now, we just assume it's made of valid characters. # 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 # Couldn't figure out how to escape for lxml in a few quick Googles
...@@ -60,7 +60,7 @@ def xpath(xml, query_string, **args): ...@@ -60,7 +60,7 @@ def xpath(xml, query_string, **args):
return x return x
args=dict( ((k, escape(args[k])) for k in args) ) args=dict( ((k, escape(args[k])) for k in args) )
print args #print args
results = doc.xpath(query_string.format(**args)) results = doc.xpath(query_string.format(**args))
return results return results
...@@ -86,14 +86,20 @@ def item(l, default="", process=lambda x:x): ...@@ -86,14 +86,20 @@ def item(l, default="", process=lambda x:x):
def id_tag(course): def id_tag(course):
''' Tag all course elements with unique IDs ''' ''' Tag all course elements with unique IDs '''
default_ids = {'video':'youtube', old_ids = {'video':'youtube',
'problem':'filename', 'problem':'filename',
'sequential':'id', 'sequential':'id',
'html':'filename', 'html':'filename',
'vertical':'id', 'vertical':'id',
'tab':'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 # Tag elements with unique IDs
elements = course.xpath("|".join(['//'+c for c in default_ids])) elements = course.xpath("|".join(['//'+c for c in default_ids]))
for elem in elements: for elem in elements:
...@@ -143,7 +149,7 @@ def course_file(user): ...@@ -143,7 +149,7 @@ def course_file(user):
filename = UserProfile.objects.get(user=user).courseware filename = UserProfile.objects.get(user=user).courseware
data_template = template_lookup.get_template(filename) data_template = template_lookup.get_template(filename)
options = {'dev_content':True} options = {'dev_content':settings.DEV_CONTENT}
tree = etree.XML(data_template.render(**options)) tree = etree.XML(data_template.render(**options))
id_tag(tree) id_tag(tree)
......
...@@ -41,6 +41,7 @@ class Command(BaseCommand): ...@@ -41,6 +41,7 @@ class Command(BaseCommand):
if os.path.exists(sections_dir): if os.path.exists(sections_dir):
print "Checking all section includes are valid XML" print "Checking all section includes are valid XML"
for f in os.listdir(sections_dir): for f in os.listdir(sections_dir):
print f
etree.parse(sections_dir+'/'+f) etree.parse(sections_dir+'/'+f)
else: else:
print "Skipping check of include files -- no section includes dir ("+sections_dir+")" print "Skipping check of include files -- no section includes dir ("+sections_dir+")"
......
...@@ -26,24 +26,10 @@ import track.views ...@@ -26,24 +26,10 @@ import track.views
import courseware.content_parser as content_parser import courseware.content_parser as content_parser
import courseware.modules.capa_module import courseware.modules
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
log = logging.getLogger("mitx.courseware") 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): def object_cache(cache, user, module_type, module_id):
# We don't look up on user -- all queries include user # We don't look up on user -- all queries include user
# Additional lookup would require a DB hit the way Django # Additional lookup would require a DB hit the way Django
...@@ -74,18 +60,18 @@ def modx_dispatch(request, module=None, dispatch=None, id=None): ...@@ -74,18 +60,18 @@ def modx_dispatch(request, module=None, dispatch=None, id=None):
ajax_url = '/modx/'+module+'/'+id+'/' 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 # 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) xml = content_parser.module_xml(content_parser.course_file(request.user), module, id_tag, id)
# Create the module # Create the module
instance=modx_modules[module](xml, instance=courseware.modules.get_module_class(module)(xml,
s.module_id, s.module_id,
ajax_url=ajax_url, ajax_url=ajax_url,
state=s.state, state=s.state,
track_function = make_track_function(request), track_function = make_track_function(request),
render_function = None) render_function = None)
# Let the module handle the AJAX # Let the module handle the AJAX
ajax_return=instance.handle_ajax(dispatch, request.POST) ajax_return=instance.handle_ajax(dispatch, request.POST)
# Save the state back to the database # Save the state back to the database
...@@ -100,7 +86,7 @@ def render_x_module(user, request, xml_module, module_object_preload): ...@@ -100,7 +86,7 @@ def render_x_module(user, request, xml_module, module_object_preload):
''' Generic module for extensions. This renders to HTML. ''' ''' Generic module for extensions. This renders to HTML. '''
# Check if problem has an instance in DB # Check if problem has an instance in DB
module_type=xml_module.tag 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 "" module_id=xml_module.get('id') #module_class.id_attribute) or ""
# Grab state from database # Grab state from database
......
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 ...@@ -26,15 +26,18 @@ import courseware.content_parser as content_parser
log = logging.getLogger("mitx.courseware") log = logging.getLogger("mitx.courseware")
class LoncapaModule(XModule): class Module(XModule):
''' Interface between capa_problem and x_module. Originally a hack ''' Interface between capa_problem and x_module. Originally a hack
meant to be refactored out, but it seems to be serving a useful 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 prupose now. We can e.g .destroy and create the capa_problem on a
reset. reset.
''' '''
xml_tags = ["problem"]
id_attribute = "filename" id_attribute = "filename"
@classmethod
def get_xml_tags(c):
return ["problem"]
def get_state(self): def get_state(self):
state = self.lcp.get_state() state = self.lcp.get_state()
......
...@@ -7,14 +7,15 @@ from mitxmako.shortcuts import render_to_response, render_to_string ...@@ -7,14 +7,15 @@ from mitxmako.shortcuts import render_to_response, render_to_string
from x_module import XModule from x_module import XModule
from lxml import etree from lxml import etree
class HtmlModule(XModule): class Module(XModule):
id_attribute = 'filename' id_attribute = 'filename'
def get_state(self): def get_state(self):
return json.dumps({ }) return json.dumps({ })
def get_xml_tags(): @classmethod
return "html" def get_xml_tags(c):
return ["html"]
def get_html(self): def get_html(self):
if self.filename==None: if self.filename==None:
......
...@@ -6,14 +6,15 @@ from mitxmako.shortcuts import render_to_response, render_to_string ...@@ -6,14 +6,15 @@ from mitxmako.shortcuts import render_to_response, render_to_string
from x_module import XModule from x_module import XModule
class SchematicModule(XModule): class Module(XModule):
id_attribute = 'id' id_attribute = 'id'
def get_state(self): def get_state(self):
return json.dumps({ }) return json.dumps({ })
def get_xml_tags(): @classmethod
return "schematic" def get_xml_tags(c):
return ["schematic"]
def get_html(self): def get_html(self):
return '<input type="hidden" class="schematic" name="{item_id}" height="480" width="640">'.format(item_id=self.item_id) 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 ...@@ -13,7 +13,7 @@ from x_module import XModule
# OBSOLETE: This obsoletes 'type' # OBSOLETE: This obsoletes 'type'
class_priority = ['video', 'problem'] class_priority = ['video', 'problem']
class SequentialModule(XModule): class Module(XModule):
''' Layout module which lays out content in a temporal sequence ''' Layout module which lays out content in a temporal sequence
''' '''
id_attribute = 'id' id_attribute = 'id'
...@@ -21,7 +21,8 @@ class SequentialModule(XModule): ...@@ -21,7 +21,8 @@ class SequentialModule(XModule):
def get_state(self): def get_state(self):
return json.dumps({ 'position':self.position }) return json.dumps({ 'position':self.position })
def get_xml_tags(): @classmethod
def get_xml_tags(c):
return ["sequential", 'tab'] return ["sequential", 'tab']
def get_html(self): def get_html(self):
......
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 ...@@ -7,14 +7,15 @@ from mitxmako.shortcuts import render_to_response, render_to_string
from x_module import XModule from x_module import XModule
from lxml import etree from lxml import etree
class VerticalModule(XModule): class Module(XModule):
id_attribute = 'id' id_attribute = 'id'
def get_state(self): def get_state(self):
return json.dumps({ }) return json.dumps({ })
def get_xml_tags(): @classmethod
return "vertical" def get_xml_tags(c):
return ["vertical"]
def get_html(self): def get_html(self):
return render_to_string('vert_module.html',{'items':self.contents}) return render_to_string('vert_module.html',{'items':self.contents})
......
...@@ -11,8 +11,8 @@ from x_module import XModule ...@@ -11,8 +11,8 @@ from x_module import XModule
log = logging.getLogger("mitx.courseware.modules") log = logging.getLogger("mitx.courseware.modules")
class VideoModule(XModule): class Module(XModule):
#id_attribute = 'youtube' id_attribute = 'youtube'
video_time = 0 video_time = 0
def handle_ajax(self, dispatch, get): def handle_ajax(self, dispatch, get):
...@@ -28,9 +28,10 @@ class VideoModule(XModule): ...@@ -28,9 +28,10 @@ class VideoModule(XModule):
log.debug(u"STATE POSITION {0}".format(self.position)) log.debug(u"STATE POSITION {0}".format(self.position))
return json.dumps({ 'position':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''' '''Tags in the courseware file guaranteed to correspond to the module'''
return "video" return ["video"]
def video_list(self): def video_list(self):
l = self.youtube.split(',') l = self.youtube.split(',')
......
...@@ -8,9 +8,10 @@ class XModule(object): ...@@ -8,9 +8,10 @@ class XModule(object):
Initialized on access with __init__, first time with state=None, and Initialized on access with __init__, first time with state=None, and
then with state 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 ''' ''' Tags in the courseware file guaranteed to correspond to the module '''
return [] return []
......
""" import unittest
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".
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_get_module_class(self):
def test_basic_addition(self): vc = courseware.modules.get_module_class('video')
""" vc_str = "<class 'courseware.modules.video_module.Module'>"
Tests that 1 + 1 always equals 2. self.assertEqual(str(vc), vc_str)
""" video_id = courseware.modules.get_default_ids()['video']
self.assertEqual(1 + 1, 2) 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)
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