Centralize startup code, and execute in all contexts
Inspired by: http://eldarion.com/blog/2013/02/14/entry-point-hook-django-projects/ Moves startup code to lms.startup and cms.startup, and calls the startup methods in wsgi.py and manage.py for both projects.
This commit is contained in:
14
common/lib/django_startup.py
Normal file
14
common/lib/django_startup.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from importlib import import_module
|
||||
from django.conf import settings
|
||||
|
||||
def autostartup():
|
||||
"""
|
||||
Execute app.startup:run() for all installed django apps
|
||||
"""
|
||||
for app in settings.INSTALLED_APPS:
|
||||
try:
|
||||
mod = import_module('{}.startup')
|
||||
if hasattr(mod, 'run'):
|
||||
mod.run()
|
||||
except ImportError:
|
||||
continue
|
||||
@@ -386,13 +386,6 @@ class ModuleStore(object):
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def set_modulestore_configuration(self, config_dict):
|
||||
'''
|
||||
Allows for runtime configuration of the modulestore. In particular this is how the
|
||||
application (LMS/CMS) can pass down Django related configuration information, e.g. caches, etc.
|
||||
'''
|
||||
raise NotImplementedError
|
||||
|
||||
def get_modulestore_type(self, course_id):
|
||||
"""
|
||||
Returns a type which identifies which modulestore is servicing the given
|
||||
@@ -405,13 +398,14 @@ class ModuleStoreBase(ModuleStore):
|
||||
'''
|
||||
Implement interface functionality that can be shared.
|
||||
'''
|
||||
def __init__(self):
|
||||
def __init__(self, metadata_inheritance_cache_subsystem=None, request_cache=None, modulestore_update_signal=None):
|
||||
'''
|
||||
Set up the error-tracking logic.
|
||||
'''
|
||||
self._location_errors = {} # location -> ErrorLog
|
||||
self.modulestore_configuration = {}
|
||||
self.modulestore_update_signal = None # can be set by runtime to route notifications of datastore changes
|
||||
self.metadata_inheritance_cache_subsystem = metadata_inheritance_cache_subsystem
|
||||
self.modulestore_update_signal = modulestore_update_signal
|
||||
self.request_cache = request_cache
|
||||
|
||||
def _get_errorlog(self, location):
|
||||
"""
|
||||
@@ -455,27 +449,6 @@ class ModuleStoreBase(ModuleStore):
|
||||
return c
|
||||
return None
|
||||
|
||||
@property
|
||||
def metadata_inheritance_cache_subsystem(self):
|
||||
"""
|
||||
Exposes an accessor to the runtime configuration for the metadata inheritance cache
|
||||
"""
|
||||
return self.modulestore_configuration.get('metadata_inheritance_cache_subsystem', None)
|
||||
|
||||
@property
|
||||
def request_cache(self):
|
||||
"""
|
||||
Exposes an accessor to the runtime configuration for the request cache
|
||||
"""
|
||||
return self.modulestore_configuration.get('request_cache', None)
|
||||
|
||||
def set_modulestore_configuration(self, config_dict):
|
||||
"""
|
||||
This is the base implementation of the interface, all we need to do is store
|
||||
two possible configurations as attributes on the class
|
||||
"""
|
||||
self.modulestore_configuration = config_dict
|
||||
|
||||
|
||||
def namedtuple_to_son(namedtuple, prefix=''):
|
||||
"""
|
||||
|
||||
@@ -8,8 +8,17 @@ from __future__ import absolute_import
|
||||
from importlib import import_module
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.cache import get_cache, InvalidCacheBackendError
|
||||
from django.dispatch import Signal
|
||||
from xmodule.modulestore.loc_mapper_store import LocMapperStore
|
||||
|
||||
# We may not always have the request_cache module available
|
||||
try:
|
||||
from request_cache.middleware import RequestCache
|
||||
HAS_REQUEST_CACHE = True
|
||||
except ImportError:
|
||||
HAS_REQUEST_CACHE = False
|
||||
|
||||
_MODULESTORES = {}
|
||||
|
||||
FUNCTION_KEYS = ['render_template']
|
||||
@@ -39,7 +48,20 @@ def create_modulestore_instance(engine, options):
|
||||
if key in _options and isinstance(_options[key], basestring):
|
||||
_options[key] = load_function(_options[key])
|
||||
|
||||
if HAS_REQUEST_CACHE:
|
||||
request_cache = RequestCache.get_request_cache()
|
||||
else:
|
||||
request_cache = None
|
||||
|
||||
try:
|
||||
metadata_inheritance_cache = get_cache('mongo_metadata_inheritance')
|
||||
except InvalidCacheBackendError:
|
||||
metadata_inheritance_cache = get_cache('default')
|
||||
|
||||
return class_(
|
||||
metadata_inheritance_cache_subsystem=metadata_inheritance_cache,
|
||||
request_cache=request_cache,
|
||||
modulestore_update_signal=Signal(providing_args=['modulestore', 'course_id', 'location']),
|
||||
**_options
|
||||
)
|
||||
|
||||
|
||||
@@ -17,12 +17,12 @@ class MixedModuleStore(ModuleStoreBase):
|
||||
"""
|
||||
ModuleStore that can be backed by either XML or Mongo
|
||||
"""
|
||||
def __init__(self, mappings, stores):
|
||||
def __init__(self, mappings, stores, **kwargs):
|
||||
"""
|
||||
Initialize a MixedModuleStore. Here we look into our passed in kwargs which should be a
|
||||
collection of other modulestore configuration informations
|
||||
"""
|
||||
super(MixedModuleStore, self).__init__()
|
||||
super(MixedModuleStore, self).__init__(**kwargs)
|
||||
|
||||
self.modulestores = {}
|
||||
self.mappings = mappings
|
||||
@@ -132,14 +132,6 @@ class MixedModuleStore(ModuleStoreBase):
|
||||
"""
|
||||
return self._get_modulestore_for_courseid(course_id).get_parent_locations(location, course_id)
|
||||
|
||||
def set_modulestore_configuration(self, config_dict):
|
||||
"""
|
||||
This implementation of the interface method will pass along the configuration to all ModuleStore
|
||||
instances
|
||||
"""
|
||||
for store in self.modulestores.values():
|
||||
store.set_modulestore_configuration(config_dict)
|
||||
|
||||
def get_modulestore_type(self, course_id):
|
||||
"""
|
||||
Returns a type which identifies which modulestore is servicing the given
|
||||
|
||||
@@ -270,15 +270,18 @@ class MongoModuleStore(ModuleStoreBase):
|
||||
def __init__(self, host, db, collection, fs_root, render_template,
|
||||
port=27017, default_class=None,
|
||||
error_tracker=null_error_tracker,
|
||||
user=None, password=None, **kwargs):
|
||||
user=None, password=None, mongo_options=None, **kwargs):
|
||||
|
||||
super(MongoModuleStore, self).__init__()
|
||||
super(MongoModuleStore, self).__init__(**kwargs)
|
||||
|
||||
if mongo_options is None:
|
||||
mongo_options = {}
|
||||
|
||||
self.collection = pymongo.connection.Connection(
|
||||
host=host,
|
||||
port=port,
|
||||
tz_aware=True,
|
||||
**kwargs
|
||||
**mongo_options
|
||||
)[db][collection]
|
||||
|
||||
if user is not None and password is not None:
|
||||
|
||||
@@ -50,15 +50,18 @@ class SplitMongoModuleStore(ModuleStoreBase):
|
||||
port=27017, default_class=None,
|
||||
error_tracker=null_error_tracker,
|
||||
user=None, password=None,
|
||||
mongo_options=None,
|
||||
**kwargs):
|
||||
|
||||
ModuleStoreBase.__init__(self)
|
||||
if mongo_options is None:
|
||||
mongo_options = {}
|
||||
|
||||
self.db = pymongo.database.Database(pymongo.MongoClient(
|
||||
host=host,
|
||||
port=port,
|
||||
tz_aware=True,
|
||||
**kwargs
|
||||
**mongo_options
|
||||
), db)
|
||||
|
||||
self.course_index = self.db[collection + '.active_versions']
|
||||
|
||||
@@ -5,9 +5,16 @@ from uuid import uuid4
|
||||
from xmodule.tests import DATA_DIR
|
||||
from xmodule.modulestore import Location, MONGO_MODULESTORE_TYPE, XML_MODULESTORE_TYPE
|
||||
from xmodule.modulestore.exceptions import ItemNotFoundError
|
||||
from xmodule.modulestore.mixed import MixedModuleStore
|
||||
from xmodule.modulestore.xml_importer import import_from_xml
|
||||
|
||||
# Mixed modulestore depends on django, so we'll manually configure some django settings
|
||||
# before importing the module
|
||||
from django.conf import settings
|
||||
if not settings.configured:
|
||||
settings.configure()
|
||||
|
||||
from xmodule.modulestore.mixed import MixedModuleStore
|
||||
|
||||
|
||||
HOST = 'localhost'
|
||||
PORT = 27017
|
||||
@@ -234,22 +241,3 @@ class TestMixedModuleStore(object):
|
||||
assert_equals(Location(parents[0]).org, 'edX')
|
||||
assert_equals(Location(parents[0]).course, 'toy')
|
||||
assert_equals(Location(parents[0]).name, '2012_Fall')
|
||||
|
||||
# pylint: disable=W0212
|
||||
def test_set_modulestore_configuration(self):
|
||||
config = {'foo': 'bar'}
|
||||
self.store.set_modulestore_configuration(config)
|
||||
assert_equals(
|
||||
config,
|
||||
self.store._get_modulestore_for_courseid(IMPORT_COURSEID).modulestore_configuration
|
||||
)
|
||||
|
||||
assert_equals(
|
||||
config,
|
||||
self.store._get_modulestore_for_courseid(XML_COURSEID1).modulestore_configuration
|
||||
)
|
||||
|
||||
assert_equals(
|
||||
config,
|
||||
self.store._get_modulestore_for_courseid(XML_COURSEID2).modulestore_configuration
|
||||
)
|
||||
|
||||
@@ -257,7 +257,7 @@ class XMLModuleStore(ModuleStoreBase):
|
||||
"""
|
||||
An XML backed ModuleStore
|
||||
"""
|
||||
def __init__(self, data_dir, default_class=None, course_dirs=None, load_error_modules=True):
|
||||
def __init__(self, data_dir, default_class=None, course_dirs=None, load_error_modules=True, **kwargs):
|
||||
"""
|
||||
Initialize an XMLModuleStore from data_dir
|
||||
|
||||
@@ -269,7 +269,7 @@ class XMLModuleStore(ModuleStoreBase):
|
||||
course_dirs: If specified, the list of course_dirs to load. Otherwise,
|
||||
load all course dirs
|
||||
"""
|
||||
super(XMLModuleStore, self).__init__()
|
||||
super(XMLModuleStore, self).__init__(**kwargs)
|
||||
|
||||
self.data_dir = path(data_dir)
|
||||
self.modules = defaultdict(dict) # course_id -> dict(location -> XModuleDescriptor)
|
||||
|
||||
@@ -8,10 +8,9 @@ from pkg_resources import resource_string
|
||||
from .capa_module import ComplexEncoder
|
||||
from .x_module import XModule
|
||||
from xmodule.raw_module import RawDescriptor
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xmodule.modulestore.exceptions import ItemNotFoundError
|
||||
from .timeinfo import TimeInfo
|
||||
from xblock.core import Dict, String, Scope, Boolean, Integer, Float
|
||||
from xblock.core import Dict, String, Scope, Boolean, Float
|
||||
from xmodule.fields import Date, Timedelta
|
||||
|
||||
from xmodule.open_ended_grading_classes.peer_grading_service import PeerGradingService, GradingServiceError, MockPeerGradingService
|
||||
@@ -104,7 +103,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
|
||||
|
||||
if self.use_for_single_location:
|
||||
try:
|
||||
self.linked_problem = modulestore().get_instance(self.system.course_id, self.link_to_location)
|
||||
self.linked_problem = self.system.get_module(self.link_to_location)
|
||||
except ItemNotFoundError:
|
||||
log.error("Linked location {0} for peer grading module {1} does not exist".format(
|
||||
self.link_to_location, self.location))
|
||||
@@ -632,3 +631,11 @@ class PeerGradingDescriptor(PeerGradingFields, RawDescriptor):
|
||||
non_editable_fields = super(PeerGradingDescriptor, self).non_editable_metadata_fields
|
||||
non_editable_fields.extend([PeerGradingFields.due, PeerGradingFields.graceperiod])
|
||||
return non_editable_fields
|
||||
|
||||
def get_required_module_descriptors(self):
|
||||
"""Returns a list of XModuleDescritpor instances upon which this module depends, but are
|
||||
not children of this module"""
|
||||
if self.use_for_single_location:
|
||||
return [self.system.load_item(self.link_to_location)]
|
||||
else:
|
||||
return []
|
||||
|
||||
@@ -2,7 +2,6 @@ from xmodule.x_module import XModule
|
||||
from xmodule.raw_module import RawDescriptor
|
||||
from lxml import etree
|
||||
from mako.template import Template
|
||||
from xmodule.modulestore.django import modulestore
|
||||
|
||||
|
||||
class CustomTagModule(XModule):
|
||||
@@ -56,7 +55,7 @@ class CustomTagDescriptor(RawDescriptor):
|
||||
# cdodge: look up the template as a module
|
||||
template_loc = self.location.replace(category='custom_tag_template', name=template_name)
|
||||
|
||||
template_module = modulestore().get_instance(system.course_id, template_loc)
|
||||
template_module = system.load_item(template_loc)
|
||||
template_module_data = template_module.data
|
||||
template = Template(template_module_data)
|
||||
return template.render(**params)
|
||||
|
||||
@@ -322,7 +322,8 @@ class CapaModuleTest(unittest.TestCase):
|
||||
|
||||
# We have to set up Django settings in order to use QueryDict
|
||||
from django.conf import settings
|
||||
settings.configure()
|
||||
if not settings.configured:
|
||||
settings.configure()
|
||||
|
||||
# Valid GET param dict
|
||||
valid_get_dict = self._querydict_from_dict({'input_1': 'test',
|
||||
|
||||
@@ -24,9 +24,6 @@ from xmodule.editing_module import TabsEditingDescriptor
|
||||
from xmodule.raw_module import EmptyDataRawDescriptor
|
||||
from xmodule.xml_module import is_pointer_tag, name_to_pathname
|
||||
from xmodule.modulestore import Location
|
||||
from xmodule.modulestore.mongo import MongoModuleStore
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xmodule.contentstore.content import StaticContent
|
||||
from xblock.core import Scope, String, Boolean, Float, List, Integer
|
||||
|
||||
import datetime
|
||||
|
||||
Reference in New Issue
Block a user