diff --git a/xblocks_contrib/annotatable/annotatable.py b/xblocks_contrib/annotatable/annotatable.py index 0c2c8755..2c5ebfd8 100644 --- a/xblocks_contrib/annotatable/annotatable.py +++ b/xblocks_contrib/annotatable/annotatable.py @@ -12,7 +12,6 @@ import markupsafe from django.utils.translation import gettext_noop as _ from lxml import etree -from opaque_keys.edx.keys import UsageKey from web_fragments.fragment import Fragment from xblock.core import XBlock from xblock.fields import Scope, String, XMLString @@ -96,18 +95,6 @@ class AnnotatableBlock(LegacyXmlMixin, XBlock): # List of supported highlight colors for annotations HIGHLIGHT_COLORS = ["yellow", "orange", "purple", "blue", "green"] - @property - def location(self): - return self.scope_ids.usage_id - - @location.setter - def location(self, value): - assert isinstance(value, UsageKey) - self.scope_ids = self.scope_ids._replace( - def_id=value, # Note: assigning a UsageKey as def_id is OK in old mongo / import system but wrong in split - usage_id=value, - ) - def _get_annotation_class_attr(self, index, el): # pylint: disable=unused-argument """Returns a dict with the CSS class attribute to set on the annotation and an XML key to delete from the element. @@ -279,8 +266,8 @@ def definition_to_xml(self, resource_fs): if not self.data: log.warning( "Could not serialize %s: No XBlock installed for '%s' tag.", - self.location, - self.location.block_type, + self.usage_key, + self.usage_key.block_type, ) return None @@ -297,6 +284,6 @@ def definition_to_xml(self, resource_fs): "Context: '{context}'" ).format( context=lines[line - 1][offset - 40:offset + 40], - loc=self.location, + loc=self.usage_key, ) - raise SerializationError(self.location, msg) from err + raise SerializationError(self.usage_key, msg) from err diff --git a/xblocks_contrib/annotatable/tests/test_annotatable.py b/xblocks_contrib/annotatable/tests/test_annotatable.py index 3251bbb8..d494ba4e 100644 --- a/xblocks_contrib/annotatable/tests/test_annotatable.py +++ b/xblocks_contrib/annotatable/tests/test_annotatable.py @@ -35,7 +35,7 @@ class AnnotatableBlockTestCase(unittest.TestCase): def setUp(self): super().setUp() runtime = TestRuntime() - scope_ids = ScopeIds("user_id", "block_type", "block_id", "course_id") + scope_ids = ScopeIds("user_id", "block_type", "block_id", "context_key") field_data = DictFieldData({"data": self.sample_xml}) self.annotatable = AnnotatableBlock(runtime, field_data, scope_ids) diff --git a/xblocks_contrib/html/html.py b/xblocks_contrib/html/html.py index 7d3c6301..537b83d2 100644 --- a/xblocks_contrib/html/html.py +++ b/xblocks_contrib/html/html.py @@ -15,7 +15,7 @@ from django.utils.translation import gettext_noop as _ from fs.errors import ResourceNotFound from lxml import etree -from opaque_keys.edx.keys import CourseKey, UsageKey +from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locator import LibraryLocatorV2 from path import Path as path from web_fragments.fragment import Fragment @@ -187,26 +187,6 @@ class HtmlBlockMixin(LegacyXmlMixin, XBlock): show_in_read_only_mode = True icon_class = "other" - @property - def category(self): - return self.scope_ids.block_type - - @property - def location(self): - return self.scope_ids.usage_id - - @location.setter - def location(self, value): - assert isinstance(value, UsageKey) - self.scope_ids = self.scope_ids._replace( - def_id=value, # Note: assigning a UsageKey as def_id is OK in old mongo / import system but wrong in split - usage_id=value, - ) - - @property - def url_name(self): - return self.location.block_id - @property def xblock_kvs(self): """ @@ -264,7 +244,7 @@ def get_html(self): data = data.replace("%%USER_EMAIL%%", email) # The course ID replacement is always safe to run. - data = data.replace("%%COURSE_ID%%", str(self.scope_ids.usage_id.context_key)) + data = data.replace("%%COURSE_ID%%", str(self.context_key)) return data def studio_view(self, context=None): @@ -324,7 +304,7 @@ def get_context(self): "module": self, "editable_metadata_fields": self.editable_metadata_fields, "data": self.data, - "base_asset_url": self.get_base_url_path_for_course_assets(self.location.course_key), + "base_asset_url": self.get_base_url_path_for_course_assets(self.context_key), "enable_latex_compiler": self.use_latex_compiler, "editor": self.editor, } @@ -545,8 +525,8 @@ def definition_to_xml(self, resource_fs): """ # Write html to file, return an empty tag - pathname = name_to_pathname(self.url_name) - filepath = "{category}/{pathname}.html".format(category=self.category, pathname=pathname) + pathname = name_to_pathname(self.usage_key.block_id) + filepath = "{category}/{pathname}.html".format(category=self.usage_key.block_type, pathname=pathname) resource_fs.makedirs(os.path.dirname(filepath), recreate=True) with resource_fs.open(filepath, "wb") as filestream: diff --git a/xblocks_contrib/problem/capa/responsetypes.py b/xblocks_contrib/problem/capa/responsetypes.py index b304a4fc..feacffa5 100644 --- a/xblocks_contrib/problem/capa/responsetypes.py +++ b/xblocks_contrib/problem/capa/responsetypes.py @@ -392,7 +392,7 @@ def make_hint_div( # pylint: disable=too-many-positional-arguments,too-many-arg # This is the "feedback hint" event event_info = {} - event_info["module_id"] = str(self.capa_block.location) + event_info["module_id"] = str(self.capa_block.usage_key) event_info["problem_part_id"] = self.id event_info["trigger_type"] = "single" # maybe be overwritten by log_extra event_info["hint_label"] = label diff --git a/xblocks_contrib/problem/capa/tests/helpers.py b/xblocks_contrib/problem/capa/tests/helpers.py index a91aabf1..2ce9d144 100644 --- a/xblocks_contrib/problem/capa/tests/helpers.py +++ b/xblocks_contrib/problem/capa/tests/helpers.py @@ -90,7 +90,7 @@ def mock_location_text(self): # pylint: disable=unused-argument return "i4x://Foo/bar/mock/abc" capa_block = Mock() - capa_block.location.__str__ = mock_location_text + capa_block.usage_key.__str__ = mock_location_text # The following comes into existence by virtue of being called # capa_block.runtime.publish return capa_block diff --git a/xblocks_contrib/problem/capa/tests/test_xqueue_submission.py b/xblocks_contrib/problem/capa/tests/test_xqueue_submission.py index 7f341b13..e021b745 100644 --- a/xblocks_contrib/problem/capa/tests/test_xqueue_submission.py +++ b/xblocks_contrib/problem/capa/tests/test_xqueue_submission.py @@ -19,6 +19,8 @@ def xqueue_service(): """ location = BlockUsageLocator(CourseLocator("test_org", "test_course", "test_run"), "problem", "ExampleProblem") block = Mock(scope_ids=ScopeIds("user1", "problem", location, location)) + block.usage_key = location + block.context_key = location.course_key block.max_score = Mock(return_value=10) return XQueueInterfaceSubmission(block) diff --git a/xblocks_contrib/problem/capa/util.py b/xblocks_contrib/problem/capa/util.py index 8533991b..c41c52c2 100644 --- a/xblocks_contrib/problem/capa/util.py +++ b/xblocks_contrib/problem/capa/util.py @@ -239,7 +239,7 @@ def get_course_id_from_capa_block(capa_block): if not capa_block: return None try: - return str(capa_block.scope_ids.usage_id.course_key) + return str(capa_block.context_key) except (AttributeError, TypeError): # AttributeError: # If the capa block lacks scope ids or has unexpected scope ids, we diff --git a/xblocks_contrib/problem/capa/xqueue_submission.py b/xblocks_contrib/problem/capa/xqueue_submission.py index 2c571282..98ef8bdf 100644 --- a/xblocks_contrib/problem/capa/xqueue_submission.py +++ b/xblocks_contrib/problem/capa/xqueue_submission.py @@ -55,11 +55,11 @@ def get_submission_params(self, header, payload): if not self.block: raise GetSubmissionParamsError() - course_id = str(self.block.scope_ids.usage_id.context_key) + course_id = str(self.block.context_key) item_type = self.block.scope_ids.block_type points_possible = self.block.max_score() - item_id = str(self.block.scope_ids.usage_id) + item_id = str(self.block.usage_key) try: grader_payload = self._parse_json(payload["grader_payload"], "grader_payload") diff --git a/xblocks_contrib/problem/capa_block.py b/xblocks_contrib/problem/capa_block.py index 3e6f9a84..e43b137a 100644 --- a/xblocks_contrib/problem/capa_block.py +++ b/xblocks_contrib/problem/capa_block.py @@ -23,7 +23,6 @@ from django.utils.encoding import smart_str from django.utils.functional import cached_property from lxml import etree -from opaque_keys.edx.keys import UsageKey from web_fragments.fragment import Fragment from webob import Response from webob.multidict import MultiDict @@ -118,8 +117,8 @@ def definition_to_xml(self, resource_fs): # pylint: disable=unused-argument if not self.data: log.warning( "Could not serialize %s: No XBlock installed for '%s' tag.", - self.location, - self.location.block_type, + self.usage_key, + self.usage_key.block_type, ) return None @@ -132,10 +131,10 @@ def definition_to_xml(self, resource_fs): # pylint: disable=unused-argument lines = self.data.split("\n") line, offset = err.position msg = ( - f"Unable to create xml for block {self.location}. " + f"Unable to create xml for block {self.usage_key}. " f"Context: '{lines[line - 1][offset - 40: offset + 40]}'" ) - raise SerializationError(self.location, msg) from err + raise SerializationError(self.usage_key, msg) from err @classmethod def parse_xml_new_runtime(cls, node, runtime, keys): @@ -170,28 +169,6 @@ class XModuleMixin(XBlock): on XModule-style internals and remove this class. """ - @property - def category(self): - """Return the block type/category.""" - return self.scope_ids.block_type - - @property - def location(self): - """Return the usage key identifying this block instance.""" - return self.scope_ids.usage_id - - @location.setter - def location(self, value): - assert isinstance(value, UsageKey) - self.scope_ids = self.scope_ids._replace( - def_id=value, # Note: assigning a UsageKey as def_id is OK in old mongo / import system but wrong in split - usage_id=value, - ) - - @property - def url_name(self): - return self.location.block_id - @property def xblock_kvs(self): """ @@ -868,7 +845,7 @@ def handle_ajax(self, dispatch, data): # pylint: disable=too-many-locals log.info( "Unable to find data when dispatching %s to %s for user %s", dispatch, - self.scope_ids.usage_id, + self.usage_key, self.scope_ids.user_id, ) _, _, traceback_obj = sys.exc_info() @@ -878,7 +855,7 @@ def handle_ajax(self, dispatch, data): # pylint: disable=too-many-locals log.exception( "Unknown error when dispatching %s to %s for user %s", dispatch, - self.scope_ids.usage_id, + self.usage_key, self.scope_ids.user_id, ) _, _, traceback_obj = sys.exc_info() @@ -909,7 +886,7 @@ def display_name_with_default(self): else fall back to problem category. """ if self.display_name is None or not self.display_name.strip(): - return self.location.block_type + return self.usage_key.block_type return self.display_name @@ -1070,7 +1047,7 @@ def max_score(self): try: lcp = LoncapaProblem( problem_text=self.data, - id=self.location.html_id(), + id=self.usage_key.html_id(), capa_system=capa_system, capa_block=self, state={}, @@ -1078,7 +1055,7 @@ def max_score(self): minimal_init=True, ) except responsetypes.LoncapaProblemError: - log.exception("LcpFatalError for block %s while getting max score", str(self.location)) + log.exception("LcpFatalError for block %s while getting max score", str(self.usage_key)) maximum_score = 0 else: maximum_score = lcp.get_max_score() @@ -1104,7 +1081,7 @@ def generate_report_data(self, user_state_iterator, limit_responses=None): "Answer ID": "98e6a8e915904d5389821a94e48babcf_10_1" }) """ - if self.category != "problem": + if self.scope_ids.block_type != "problem": raise NotImplementedError() if limit_responses == 0: @@ -1138,7 +1115,7 @@ def generate_report_data(self, user_state_iterator, limit_responses=None): try: lcp = LoncapaProblem( problem_text=self.data, - id=self.location.html_id(), + id=self.usage_key.html_id(), capa_system=capa_system, # We choose to run without a fully initialized CapaModule capa_block=None, @@ -1184,8 +1161,8 @@ def generate_report_data(self, user_state_iterator, limit_responses=None): # Capture a backtrace for errors from failed loncapa problems log.exception( "An error occurred generating a problem report on course %s, problem %s, and student %s", - self.scope_ids.usage_id.course_key, - self.scope_ids.usage_id, + self.context_key, + self.usage_key, self.scope_ids.user_id, ) # Also input error in report @@ -1235,7 +1212,7 @@ def lcp(self): # pylint: disable=method-hidden try: lcp = self.new_lcp(self.get_state_for_lcp()) except Exception as err: - msg = f"cannot create LoncapaProblem {str(self.location)}: {err}" + msg = f"cannot create LoncapaProblem {str(self.usage_key)}: {err}" raise LoncapaProblemError(msg).with_traceback(sys.exc_info()[2]) if self.score is None: @@ -1253,7 +1230,7 @@ def choose_new_seed(self): elif self.rerandomize == RANDOMIZATION.PER_STUDENT: user_id = self.runtime.service(self, "user").get_current_user().opt_attrs.get(ATTR_KEY_USER_ID) or 0 # see comment on randomization_bin - self.seed = randomization_bin(user_id, str(self.location).encode("utf-8")) + self.seed = randomization_bin(user_id, str(self.usage_key).encode("utf-8")) else: self.seed = struct.unpack("i", os.urandom(4))[0] @@ -1295,7 +1272,7 @@ def new_lcp(self, state, text=None): return LoncapaProblem( problem_text=text, - id=self.location.html_id(), + id=self.usage_key.html_id(), state=state, seed=self.get_seed(), capa_system=capa_system, @@ -1385,8 +1362,8 @@ def get_html(self): return render_to_string( "problem_ajax.html", { - "element_id": self.location.html_id(), - "id": str(self.location), + "element_id": self.usage_key.html_id(), + "id": str(self.usage_key), "ajax_url": self.ajax_url, "current_score": curr_score, "total_possible": total_possible, @@ -1400,7 +1377,7 @@ def handle_fatal_lcp_error(self, error): """ Log a fatal LoncapaProblem error and return an HTML message for display to the user. """ - log.exception("LcpFatalError Encountered for %s", str(self.location)) + log.exception("LcpFatalError Encountered for %s", str(self.usage_key)) if error: return HTML('
Error formatting HTML for problem:
{msg}').format(
msg=str(error)
@@ -1516,12 +1493,12 @@ def handle_problem_html_error(self, err):
`err` is the Exception encountered while rendering the problem HTML.
"""
problem_display_name = self.display_name_with_default
- problem_location = str(self.location)
+ problem_location = str(self.usage_key)
log.exception("ProblemGetHtmlError: %r, %r, %s", problem_display_name, problem_location, str(err))
if self.debug:
msg = HTML("[courseware.capa.capa_block] Failed to generate HTML for problem {url}").format(
- url=str(self.location)
+ url=str(self.usage_key)
)
msg += HTML("Error:
{msg}").format(msg=str(err))
msg += HTML("{tb}").format(tb=traceback.format_exc())
@@ -1642,7 +1619,7 @@ def get_demand_hint(self, hint_index):
# Log this demand-hint request. Note that this only logs the last hint requested (although now
# all previously shown hints are still displayed).
event_info = {}
- event_info["module_id"] = str(self.location)
+ event_info["module_id"] = str(self.usage_key)
event_info["hint_index"] = hint_index
event_info["hint_len"] = len(demand_hints)
event_info["hint_text"] = get_inner_html_from_xpath(demand_hints[hint_index])
@@ -1711,8 +1688,8 @@ def get_problem_html(self, encapsulate=True, submit_notification=False): # pyli
context = {
"problem": content,
- "id": str(self.location),
- "short_id": self.location.html_id(),
+ "id": str(self.usage_key),
+ "short_id": self.usage_key.html_id(),
"submit_button": submit_button,
"submit_button_submitting": submit_button_submitting,
"should_enable_submit_button": should_enable_submit_button,
@@ -1735,7 +1712,7 @@ def get_problem_html(self, encapsulate=True, submit_notification=False): # pyli
if encapsulate:
html = HTML('