Breaking devstack change

Hello :wave:

Context: this change affects only devstacks running the most recent version of the master branch. It does not affect named releases or production deployments.
More context: this is a part of the Content Core Platform Simplification project.

Currently, various terms refer to XBlocks: “xblocks” (or “blocks”), “descriptors”, “modules”, or “items”. This makes the code a lot less approachable and understandable. Since we are getting rid of a lot of tech debt, we are doing a small refactor of this terminology in the edx-platform to make it consistent. However, it means that we need to introduce some breaking changes. We have just merged one of the related PRs that replaced all occurrences of the term “module” with “block”.

Because of this, you need to reinstall all entry points for XBlocks. To do this, run the following commands in LMS and Studio containers, and restart them.

make local-requirements &&\
sed -i 's/xmodule.hidden_module.HiddenDescriptor/xmodule.hidden_block.HiddenBlock/' /edx/etc/{lms,studio}.yml &&\
find . -name '*.pyc' -delete

Example errors you may encounter without running these commands:

ModuleNotFoundError: No module named 'xmodule.capa_module'
Traceback (most recent call last):
  File "/edx/app/edxapp/edx-platform/openedx/core/djangoapps/user_api/accounts/utils.py", line 174, in retrieve_last_sitewide_block_completed
    item = modulestore().get_item(candidate_block_key, depth=1)
  File "/edx/app/edxapp/edx-platform/xmodule/modulestore/mixed.py", line 81, in inner
    retval = func(field_decorator=strip_key_collection, *args, **kwargs)
  File "/edx/app/edxapp/edx-platform/xmodule/modulestore/mixed.py", line 247, in get_item
    return store.get_item(usage_key, depth, **kwargs)
  File "/edx/app/edxapp/edx-platform/xmodule/modulestore/split_mongo/split_draft.py", line 283, in get_item
    return super().get_item(usage_key, depth=depth, **kwargs)
  File "/edx/app/edxapp/edx-platform/xmodule/modulestore/split_mongo/split.py", line 1183, in get_item
    items = self._load_items(course, [BlockKey.from_usage_key(usage_key)], depth, **kwargs)
  File "/edx/app/edxapp/edx-platform/xmodule/modulestore/split_mongo/split.py", line 780, in _load_items
    return [runtime.load_item(block_key, course_entry, **kwargs) for block_key in block_keys]
  File "/edx/app/edxapp/edx-platform/xmodule/modulestore/split_mongo/split.py", line 780, in <listcomp>
    return [runtime.load_item(block_key, course_entry, **kwargs) for block_key in block_keys]
  File "/edx/app/edxapp/edx-platform/xmodule/modulestore/split_mongo/caching_descriptor_system.py", line 121, in _load_item
    class_ = self.load_block_type(block_data.block_type)
  File "/edx/app/edxapp/edx-platform/xmodule/x_module.py", line 1112, in load_block_type
    return super().load_block_type(block_type)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/xblock/runtime.py", line 621, in load_block_type
    return XBlock.load_class(block_type, self.default_class, self.select)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/xblock/plugin.py", line 115, in load_class
    PLUGIN_CACHE[key] = cls._load_class_entry_point(selected_entry_point)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/xblock/plugin.py", line 70, in _load_class_entry_point
    class_ = entry_point.load()
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/pkg_resources/__init__.py", line 2471, in load
    return self.resolve()
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/pkg_resources/__init__.py", line 2477, in resolve
    module = __import__(self.module_name, fromlist=['__name__'], level=0)
ModuleNotFoundError: No module named 'xmodule.capa_module'
ModuleNotFoundError: No module named 'xmodule.course_module'
Traceback (most recent call last):
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/lib/python3.8/contextlib.py", line 75, in inner
    return func(*args, **kwds)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/views/generic/base.py", line 70, in view
    return self.dispatch(request, *args, **kwargs)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/rest_framework/views.py", line 509, in dispatch
    response = self.handle_exception(exc)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/rest_framework/views.py", line 469, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
    raise exc
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/rest_framework/views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)
  File "/edx/app/edxapp/edx-platform/lms/djangoapps/course_home_api/course_metadata/views.py", line 125, in get
    'tabs': get_course_tab_list(request.user, course),
  File "/edx/app/edxapp/edx-platform/lms/djangoapps/courseware/tabs.py", line 330, in get_course_tab_list
    for tab in xmodule_tab_list:
  File "/edx/app/edxapp/edx-platform/xmodule/tabs.py", line 470, in iterate_displayable
    if tab.is_enabled(course, user=user) and (include_hidden or not (user and tab.is_hidden)):
  File "/edx/app/edxapp/edx-platform/lms/djangoapps/course_wiki/tab.py", line 43, in is_enabled
    if course.allow_public_wiki_access:
  File "/edx/app/edxapp/edx-platform/openedx/core/djangoapps/content/course_overviews/models.py", line 835, in allow_public_wiki_access
    return self._original_course.allow_public_wiki_access
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/django/utils/functional.py", line 48, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/edx/app/edxapp/edx-platform/openedx/core/djangoapps/content/course_overviews/models.py", line 828, in _original_course
    return modulestore().get_course(self.id)
  File "/edx/app/edxapp/edx-platform/xmodule/modulestore/mixed.py", line 81, in inner
    retval = func(field_decorator=strip_key_collection, *args, **kwargs)
  File "/edx/app/edxapp/edx-platform/xmodule/modulestore/mixed.py", line 403, in get_course
    return store.get_course(course_key, depth=depth, **kwargs)
  File "/usr/lib/python3.8/contextlib.py", line 75, in inner
    return func(*args, **kwds)
  File "/edx/app/edxapp/edx-platform/xmodule/modulestore/split_mongo/split_draft.py", line 61, in get_course
    return super().get_course(course_id, depth=depth, **kwargs)
  File "/edx/app/edxapp/edx-platform/xmodule/modulestore/split_mongo/split.py", line 1106, in get_course
    return self._get_structure(course_id, depth, **kwargs)
  File "/edx/app/edxapp/edx-platform/xmodule/modulestore/split_mongo/split.py", line 1096, in _get_structure
    result = self._load_items(structure_entry, [root], depth, **kwargs)
  File "/edx/app/edxapp/edx-platform/xmodule/modulestore/split_mongo/split.py", line 780, in _load_items
    return [runtime.load_item(block_key, course_entry, **kwargs) for block_key in block_keys]
  File "/edx/app/edxapp/edx-platform/xmodule/modulestore/split_mongo/split.py", line 780, in <listcomp>
    return [runtime.load_item(block_key, course_entry, **kwargs) for block_key in block_keys]
  File "/edx/app/edxapp/edx-platform/xmodule/modulestore/split_mongo/caching_descriptor_system.py", line 121, in _load_item
    class_ = self.load_block_type(block_data.block_type)
  File "/edx/app/edxapp/edx-platform/xmodule/x_module.py", line 1112, in load_block_type
    return super().load_block_type(block_type)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/xblock/runtime.py", line 621, in load_block_type
    return XBlock.load_class(block_type, self.default_class, self.select)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/xblock/plugin.py", line 115, in load_class
    PLUGIN_CACHE[key] = cls._load_class_entry_point(selected_entry_point)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/xblock/plugin.py", line 70, in _load_class_entry_point
    class_ = entry_point.load()
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/pkg_resources/__init__.py", line 2471, in load
    return self.resolve()
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/site-packages/pkg_resources/__init__.py", line 2477, in resolve
    module = __import__(self.module_name, fromlist=['__name__'], level=0)
ModuleNotFoundError: No module named 'xmodule.course_module'
ModuleNotFoundError: No module named 'xmodule.hidden_module'
Traceback (most recent call last):
  File "/edx/app/edxapp/edx-platform/xmodule/modulestore/split_mongo/split.py", line 660, in __init__
    class_ = getattr(import_module(module_path), class_name)
  File "/edx/app/edxapp/venvs/edxapp/lib/python3.8/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 973, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'xmodule.hidden_module'
5 Likes

Is this also something that we’ll want to include in the Palm release notes since it will affect end-users of Named releases at that point?

I don’t think it’s necessary.

  1. If somebody upgrades the devstack from Olive to Palm, they will need to install dependencies anyway. Most requirements-related recipes in the Makefile trigger make local-requirements.
  2. The changes in the /edx/etc/{lms,studio}.yml will be included in Docker images once we merge this PR tomorrow. Recreating a container will replace these files.
1 Like