Commit 26ae88fa by Victor Shnayder

Factor out get_item_error() into a new ModuleStoreBase class

* may be temporary if we move errors into the items themselves.
parent 64346d72
...@@ -3,10 +3,13 @@ This module provides an abstraction for working with XModuleDescriptors ...@@ -3,10 +3,13 @@ This module provides an abstraction for working with XModuleDescriptors
that are stored in a database an accessible using their Location as an identifier that are stored in a database an accessible using their Location as an identifier
""" """
import logging
import re import re
from collections import namedtuple from collections import namedtuple
from .exceptions import InvalidLocationError, InsufficientSpecificationError from .exceptions import InvalidLocationError, InsufficientSpecificationError
import logging from xmodule.errortracker import ErrorLog, make_error_tracker
log = logging.getLogger('mitx.' + 'modulestore') log = logging.getLogger('mitx.' + 'modulestore')
...@@ -290,3 +293,38 @@ class ModuleStore(object): ...@@ -290,3 +293,38 @@ class ModuleStore(object):
''' '''
raise NotImplementedError raise NotImplementedError
class ModuleStoreBase(ModuleStore):
'''
Implement interface functionality that can be shared.
'''
def __init__(self):
'''
Set up the error-tracking logic.
'''
self._location_errors = {} # location -> ErrorLog
def _get_errorlog(self, location):
"""
If we already have an errorlog for this location, return it. Otherwise,
create one.
"""
location = Location(location)
if location not in self._location_errors:
self._location_errors[location] = make_error_tracker()
return self._location_errors[location]
def get_item_errors(self, location):
"""
Return list of errors for this location, if any. Raise the same
errors as get_item if location isn't present.
NOTE: For now, the only items that track errors are CourseDescriptors in
the xml datastore. This will return an empty list for all other items
and datastores.
"""
# check that item is present and raise the promised exceptions if needed
self.get_item(location)
errorlog = self._get_errorlog(location)
return errorlog.errors
...@@ -11,7 +11,7 @@ from xmodule.x_module import XModuleDescriptor ...@@ -11,7 +11,7 @@ from xmodule.x_module import XModuleDescriptor
from xmodule.mako_module import MakoDescriptorSystem from xmodule.mako_module import MakoDescriptorSystem
from mitxmako.shortcuts import render_to_string from mitxmako.shortcuts import render_to_string
from . import ModuleStore, Location from . import ModuleStoreBase, Location
from .exceptions import (ItemNotFoundError, from .exceptions import (ItemNotFoundError,
NoPathToItem, DuplicateItemError) NoPathToItem, DuplicateItemError)
...@@ -38,7 +38,7 @@ class CachingDescriptorSystem(MakoDescriptorSystem): ...@@ -38,7 +38,7 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
resources_fs: a filesystem, as per MakoDescriptorSystem resources_fs: a filesystem, as per MakoDescriptorSystem
error_tracker: error_tracker: a function that logs errors for later display to users
render_template: a function for rendering templates, as per render_template: a function for rendering templates, as per
MakoDescriptorSystem MakoDescriptorSystem
...@@ -73,7 +73,7 @@ def location_to_query(location): ...@@ -73,7 +73,7 @@ def location_to_query(location):
return query return query
class MongoModuleStore(ModuleStore): class MongoModuleStore(ModuleStoreBase):
""" """
A Mongodb backed ModuleStore A Mongodb backed ModuleStore
""" """
...@@ -81,6 +81,9 @@ class MongoModuleStore(ModuleStore): ...@@ -81,6 +81,9 @@ class MongoModuleStore(ModuleStore):
# TODO (cpennington): Enable non-filesystem filestores # TODO (cpennington): Enable non-filesystem filestores
def __init__(self, host, db, collection, fs_root, port=27017, default_class=None, def __init__(self, host, db, collection, fs_root, port=27017, default_class=None,
error_tracker=null_error_tracker): error_tracker=null_error_tracker):
ModuleStoreBase.__init__(self)
self.collection = pymongo.connection.Connection( self.collection = pymongo.connection.Connection(
host=host, host=host,
port=port port=port
......
...@@ -12,7 +12,7 @@ from xmodule.course_module import CourseDescriptor ...@@ -12,7 +12,7 @@ from xmodule.course_module import CourseDescriptor
from xmodule.mako_module import MakoDescriptorSystem from xmodule.mako_module import MakoDescriptorSystem
from cStringIO import StringIO from cStringIO import StringIO
from . import ModuleStore, Location from . import ModuleStoreBase, Location
from .exceptions import ItemNotFoundError from .exceptions import ItemNotFoundError
etree.set_default_parser( etree.set_default_parser(
...@@ -98,7 +98,7 @@ class ImportSystem(XMLParsingSystem, MakoDescriptorSystem): ...@@ -98,7 +98,7 @@ class ImportSystem(XMLParsingSystem, MakoDescriptorSystem):
error_tracker, process_xml, **kwargs) error_tracker, process_xml, **kwargs)
class XMLModuleStore(ModuleStore): class XMLModuleStore(ModuleStoreBase):
""" """
An XML backed ModuleStore An XML backed ModuleStore
""" """
...@@ -118,13 +118,12 @@ class XMLModuleStore(ModuleStore): ...@@ -118,13 +118,12 @@ class XMLModuleStore(ModuleStore):
course_dirs: If specified, the list of course_dirs to load. Otherwise, course_dirs: If specified, the list of course_dirs to load. Otherwise,
load all course dirs load all course dirs
""" """
ModuleStoreBase.__init__(self)
self.eager = eager self.eager = eager
self.data_dir = path(data_dir) self.data_dir = path(data_dir)
self.modules = {} # location -> XModuleDescriptor self.modules = {} # location -> XModuleDescriptor
self.courses = {} # course_dir -> XModuleDescriptor for the course self.courses = {} # course_dir -> XModuleDescriptor for the course
self.location_errors = {} # location -> ErrorLog
if default_class is None: if default_class is None:
self.default_class = None self.default_class = None
...@@ -148,12 +147,14 @@ class XMLModuleStore(ModuleStore): ...@@ -148,12 +147,14 @@ class XMLModuleStore(ModuleStore):
for course_dir in course_dirs: for course_dir in course_dirs:
try: try:
# make a tracker, then stick in the right place once the course loads # Special-case code here, since we don't have a location for the
# and we know its location # course before it loads.
# So, make a tracker to track load-time errors, then put in the right
# place after the course loads and we have its location
errorlog = make_error_tracker() errorlog = make_error_tracker()
course_descriptor = self.load_course(course_dir, errorlog.tracker) course_descriptor = self.load_course(course_dir, errorlog.tracker)
self.courses[course_dir] = course_descriptor self.courses[course_dir] = course_descriptor
self.location_errors[course_descriptor.location] = errorlog self._location_errors[course_descriptor.location] = errorlog
except: except:
msg = "Failed to load course '%s'" % course_dir msg = "Failed to load course '%s'" % course_dir
log.exception(msg) log.exception(msg)
...@@ -221,23 +222,6 @@ class XMLModuleStore(ModuleStore): ...@@ -221,23 +222,6 @@ class XMLModuleStore(ModuleStore):
raise ItemNotFoundError(location) raise ItemNotFoundError(location)
def get_item_errors(self, location):
"""
Return list of errors for this location, if any. Raise the same
errors as get_item if location isn't present.
NOTE: This only actually works for courses in the xml datastore--
will return an empty list for all other modules.
"""
location = Location(location)
# check that item is present
self.get_item(location)
# now look up errors
if location in self.location_errors:
return self.location_errors[location].errors
return []
def get_courses(self, depth=0): def get_courses(self, depth=0):
""" """
Returns a list of course descriptors. If there were errors on loading, Returns a list of course descriptors. If there were errors on loading,
...@@ -245,9 +229,11 @@ class XMLModuleStore(ModuleStore): ...@@ -245,9 +229,11 @@ class XMLModuleStore(ModuleStore):
""" """
return self.courses.values() return self.courses.values()
def create_item(self, location): def create_item(self, location):
raise NotImplementedError("XMLModuleStores are read-only") raise NotImplementedError("XMLModuleStores are read-only")
def update_item(self, location, data): def update_item(self, location, data):
""" """
Set the data in the item specified by the location to Set the data in the item specified by the location to
...@@ -258,6 +244,7 @@ class XMLModuleStore(ModuleStore): ...@@ -258,6 +244,7 @@ class XMLModuleStore(ModuleStore):
""" """
raise NotImplementedError("XMLModuleStores are read-only") raise NotImplementedError("XMLModuleStores are read-only")
def update_children(self, location, children): def update_children(self, location, children):
""" """
Set the children for the item specified by the location to Set the children for the item specified by the location to
...@@ -268,6 +255,7 @@ class XMLModuleStore(ModuleStore): ...@@ -268,6 +255,7 @@ class XMLModuleStore(ModuleStore):
""" """
raise NotImplementedError("XMLModuleStores are read-only") raise NotImplementedError("XMLModuleStores are read-only")
def update_metadata(self, location, metadata): def update_metadata(self, location, metadata):
""" """
Set the metadata for the item specified by the location to Set the metadata for the item specified by the location to
......
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