From ec97387d3ed6ecd2938a84b0334ef38f72925f2e Mon Sep 17 00:00:00 2001 From: Braden MacDonald <braden@opencraft.com> Date: Sat, 7 Sep 2019 14:27:08 -0700 Subject: [PATCH] Move new Blockstore key types to external opaque-keys library. --- .../core/djangoapps/content_libraries/api.py | 8 +- .../core/djangoapps/content_libraries/keys.py | 132 ---------- .../content_libraries/library_bundle.py | 10 +- .../migrations/0001_initial.py | 2 +- .../djangoapps/content_libraries/models.py | 5 +- .../content_libraries/serializers.py | 3 +- .../djangoapps/content_libraries/views.py | 4 +- openedx/core/djangoapps/xblock/api.py | 5 +- .../xblock/learning_context/keys.py | 226 ------------------ .../learning_context/learning_context.py | 10 +- .../xblock/learning_context/manager.py | 5 +- .../xblock/runtime/blockstore_runtime.py | 2 +- .../djangoapps/xblock/runtime/id_managers.py | 4 +- .../djangoapps/xblock/runtime/olx_parsing.py | 5 +- requirements/edx/base.txt | 4 +- requirements/edx/development.txt | 4 +- requirements/edx/paver.txt | 2 +- requirements/edx/testing.txt | 4 +- setup.py | 9 - 19 files changed, 38 insertions(+), 406 deletions(-) delete mode 100644 openedx/core/djangoapps/content_libraries/keys.py delete mode 100644 openedx/core/djangoapps/xblock/learning_context/keys.py diff --git a/openedx/core/djangoapps/content_libraries/api.py b/openedx/core/djangoapps/content_libraries/api.py index ae875457762..be3d1b809b2 100644 --- a/openedx/core/djangoapps/content_libraries/api.py +++ b/openedx/core/djangoapps/content_libraries/api.py @@ -9,6 +9,7 @@ import attr from django.core.validators import validate_unicode_slug from django.db import IntegrityError from lxml import etree +from opaque_keys.edx.locator import BundleDefinitionLocator, LibraryLocatorV2, LibraryUsageLocatorV2 from organizations.models import Organization import six from xblock.core import XBlock @@ -17,7 +18,6 @@ from xblock.exceptions import XBlockNotFoundError from cms.djangoapps.contentstore.views.helpers import xblock_type_display_name from openedx.core.djangoapps.content_libraries.library_bundle import LibraryBundle from openedx.core.djangoapps.xblock.api import get_block_display_name, load_block -from openedx.core.djangoapps.xblock.learning_context.keys import BundleDefinitionLocator from openedx.core.djangoapps.xblock.learning_context.manager import get_learning_context_impl from openedx.core.djangoapps.xblock.runtime.olx_parsing import XBlockInclude from openedx.core.lib.blockstore_api import ( @@ -33,7 +33,6 @@ from openedx.core.lib.blockstore_api import ( delete_draft, ) from openedx.core.djangolib.blockstore_cache import BundleCache -from .keys import LibraryLocatorV2, LibraryUsageLocatorV2 from .models import ContentLibrary, ContentLibraryPermission log = logging.getLogger(__name__) @@ -275,7 +274,7 @@ def get_library_block(usage_key): def_key = lib_context.definition_for_usage(usage_key) if def_key is None: raise ContentLibraryBlockNotFound(usage_key) - lib_bundle = LibraryBundle(usage_key.library_slug, def_key.bundle_uuid, draft_name=DRAFT_NAME) + lib_bundle = LibraryBundle(usage_key.lib_key, def_key.bundle_uuid, draft_name=DRAFT_NAME) return LibraryXBlockMetadata( usage_key=usage_key, def_key=def_key, @@ -337,8 +336,7 @@ def create_library_block(library_key, block_type, definition_id): # Make sure the new ID is not taken already: new_usage_id = definition_id # Since this is a top level XBlock, usage_id == definition_id usage_key = LibraryUsageLocatorV2( - library_org=library_key.org, - library_slug=library_key.slug, + lib_key=library_key, block_type=block_type, usage_id=new_usage_id, ) diff --git a/openedx/core/djangoapps/content_libraries/keys.py b/openedx/core/djangoapps/content_libraries/keys.py deleted file mode 100644 index afd35e538cd..00000000000 --- a/openedx/core/djangoapps/content_libraries/keys.py +++ /dev/null @@ -1,132 +0,0 @@ -""" -Key/locator types for Blockstore-based content libraries -""" -# Disable warnings about _to_deprecated_string etc. which we don't want to implement: -# pylint: disable=abstract-method, no-member -from __future__ import absolute_import, division, print_function, unicode_literals - -from opaque_keys import InvalidKeyError - -from openedx.core.djangoapps.xblock.learning_context.keys import ( - check_key_string_field, - BlockUsageKeyV2, - LearningContextKey, -) - - -class LibraryLocatorV2(LearningContextKey): - """ - A key that represents a Blockstore-based content library. - - When serialized, these keys look like: - lib:MITx:reallyhardproblems - lib:hogwarts:p300-potions-exercises - """ - CANONICAL_NAMESPACE = 'lib' - KEY_FIELDS = ('org', 'slug') - __slots__ = KEY_FIELDS - CHECKED_INIT = False - - def __init__(self, org, slug): - """ - Construct a GlobalUsageLocator - """ - check_key_string_field(org) - check_key_string_field(slug) - super(LibraryLocatorV2, self).__init__(org=org, slug=slug) - - def _to_string(self): - """ - Serialize this key as a string - """ - return ":".join((self.org, self.slug)) - - @classmethod - def _from_string(cls, serialized): - """ - Instantiate this key from a serialized string - """ - try: - (org, slug) = serialized.split(':') - except ValueError: - raise InvalidKeyError(cls, serialized) - return cls(org=org, slug=slug) - - def make_definition_usage(self, definition_key, usage_id=None): - """ - Return a usage key, given the given the specified definition key and - usage_id. - """ - return LibraryUsageLocatorV2( - library_org=self.org, - library_slug=self.slug, - block_type=definition_key.block_type, - usage_id=usage_id, - ) - - def for_branch(self, branch): - """ - Compatibility helper. - Some code calls .for_branch(None) on course keys. By implementing this, - it improves backwards compatibility between library keys and course - keys. - """ - if branch is not None: - raise ValueError("Cannot call for_branch on a content library key, except for_branch(None).") - return self - - -class LibraryUsageLocatorV2(BlockUsageKeyV2): - """ - An XBlock in a Blockstore-based content library. - - When serialized, these keys look like: - lb:MITx:reallyhardproblems:problem:problem1 - """ - CANONICAL_NAMESPACE = 'lb' # "Library Block" - KEY_FIELDS = ('library_org', 'library_slug', 'block_type', 'usage_id') - __slots__ = KEY_FIELDS - CHECKED_INIT = False - - def __init__(self, library_org, library_slug, block_type, usage_id): - """ - Construct a LibraryUsageLocatorV2 - """ - check_key_string_field(library_org) - check_key_string_field(library_slug) - check_key_string_field(block_type) - check_key_string_field(usage_id) - super(LibraryUsageLocatorV2, self).__init__( - library_org=library_org, - library_slug=library_slug, - block_type=block_type, - usage_id=usage_id, - ) - - @property - def context_key(self): - return LibraryLocatorV2(org=self.library_org, slug=self.library_slug) - - @property - def block_id(self): - """ - Get the 'block ID' which is another name for the usage ID. - """ - return self.usage_id - - def _to_string(self): - """ - Serialize this key as a string - """ - return ":".join((self.library_org, self.library_slug, self.block_type, self.usage_id)) - - @classmethod - def _from_string(cls, serialized): - """ - Instantiate this key from a serialized string - """ - try: - (library_org, library_slug, block_type, usage_id) = serialized.split(':') - except ValueError: - raise InvalidKeyError(cls, serialized) - return cls(library_org=library_org, library_slug=library_slug, block_type=block_type, usage_id=usage_id) diff --git a/openedx/core/djangoapps/content_libraries/library_bundle.py b/openedx/core/djangoapps/content_libraries/library_bundle.py index 1481f7c77d6..e0e3283e5ee 100644 --- a/openedx/core/djangoapps/content_libraries/library_bundle.py +++ b/openedx/core/djangoapps/content_libraries/library_bundle.py @@ -5,12 +5,11 @@ from __future__ import absolute_import, division, print_function, unicode_litera import logging from django.utils.lru_cache import lru_cache +from opaque_keys.edx.locator import BundleDefinitionLocator, LibraryUsageLocatorV2 from xblock.core import XBlock from xblock.plugin import PluginMissingError -from openedx.core.djangoapps.content_libraries.keys import LibraryUsageLocatorV2 from openedx.core.djangoapps.content_libraries.models import ContentLibrary -from openedx.core.djangoapps.xblock.learning_context.keys import BundleDefinitionLocator from openedx.core.djangoapps.xblock.runtime.blockstore_runtime import xml_for_definition from openedx.core.djangoapps.xblock.runtime.olx_parsing import ( BundleFormatException, @@ -85,8 +84,7 @@ def usage_for_child_include(parent_usage, parent_definition, parsed_include): # <xblock-include> but that requires much more complex logic.) usage_id = parent_usage.usage_id + "-" + usage_id return LibraryUsageLocatorV2( - library_org=parent_usage.library_org, - library_slug=parent_usage.library_slug, + lib_key=parent_usage.lib_key, block_type=parsed_include.block_type, usage_id=usage_id, ) @@ -169,7 +167,7 @@ class LibraryBundle(object): own_usage_keys = [] for olx_file_path in self.get_olx_files(): block_type, usage_id, _unused = olx_file_path.split('/') - usage_key = LibraryUsageLocatorV2(self.library_key.org, self.library_key.slug, block_type, usage_id) + usage_key = LibraryUsageLocatorV2(self.library_key, block_type, usage_id) own_usage_keys.append(usage_key) usage_keys_with_parents = self.get_bundle_includes().keys() @@ -234,7 +232,7 @@ class LibraryBundle(object): olx_path=bfile.path, **version_arg ) - usage_key = LibraryUsageLocatorV2(self.library_key.org, self.library_key.slug, block_type, usage_id) + usage_key = LibraryUsageLocatorV2(self.library_key, block_type, usage_id) add_definitions_children(usage_key, def_key) self.cache.set(cache_key, usages_found) diff --git a/openedx/core/djangoapps/content_libraries/migrations/0001_initial.py b/openedx/core/djangoapps/content_libraries/migrations/0001_initial.py index 354583ae598..8f2eb6761f1 100644 --- a/openedx/core/djangoapps/content_libraries/migrations/0001_initial.py +++ b/openedx/core/djangoapps/content_libraries/migrations/0001_initial.py @@ -21,7 +21,7 @@ class Migration(migrations.Migration): name='ContentLibrary', fields=[ ('id', models.AutoField(primary_key=True, serialize=False)), - ('slug', models.SlugField()), + ('slug', models.SlugField(allow_unicode=True)), ('bundle_uuid', models.UUIDField(unique=True)), ('allow_public_learning', models.BooleanField(default=False, help_text='\n Allow any user (even unregistered users) to view and interact with\n content in this library (in the LMS; not in Studio). If this is not\n enabled, then the content in this library is not directly accessible\n in the LMS, and learners will only ever see this content if it is\n explicitly added to a course. If in doubt, leave this unchecked.\n ')), ('allow_public_read', models.BooleanField(default=False, help_text="\n Allow any user with Studio access to view this library's content in\n Studio, use it in their courses, and copy content out of this\n library. If in doubt, leave this unchecked.\n ")), diff --git a/openedx/core/djangoapps/content_libraries/models.py b/openedx/core/djangoapps/content_libraries/models.py index bb03c0748c3..f1680c18d6e 100644 --- a/openedx/core/djangoapps/content_libraries/models.py +++ b/openedx/core/djangoapps/content_libraries/models.py @@ -6,11 +6,10 @@ from __future__ import absolute_import, division, print_function, unicode_litera from django.contrib.auth import get_user_model from django.db import models from django.utils.translation import ugettext_lazy as _ +from opaque_keys.edx.locator import LibraryLocatorV2 from organizations.models import Organization import six -from openedx.core.djangoapps.content_libraries.keys import LibraryLocatorV2 - User = get_user_model() @@ -45,7 +44,7 @@ class ContentLibrary(models.Model): # library's opaque key: # e.g. "lib:org:slug" is the opaque key for a library. org = models.ForeignKey(Organization, on_delete=models.PROTECT, null=False) - slug = models.SlugField() + slug = models.SlugField(allow_unicode=True) bundle_uuid = models.UUIDField(unique=True, null=False) # How is this library going to be used? diff --git a/openedx/core/djangoapps/content_libraries/serializers.py b/openedx/core/djangoapps/content_libraries/serializers.py index a87fcfff360..09190e55488 100644 --- a/openedx/core/djangoapps/content_libraries/serializers.py +++ b/openedx/core/djangoapps/content_libraries/serializers.py @@ -4,6 +4,7 @@ Serializers for the content libraries REST API # pylint: disable=abstract-method from __future__ import absolute_import, division, print_function, unicode_literals +from django.core.validators import validate_unicode_slug from rest_framework import serializers @@ -16,7 +17,7 @@ class ContentLibraryMetadataSerializer(serializers.Serializer): # is a reserved prop name in React id = serializers.CharField(source="key", read_only=True) org = serializers.SlugField(source="key.org") - slug = serializers.SlugField(source="key.slug") + slug = serializers.CharField(source="key.slug", validators=(validate_unicode_slug, )) bundle_uuid = serializers.UUIDField(format='hex_verbose', read_only=True) collection_uuid = serializers.UUIDField(format='hex_verbose', write_only=True) title = serializers.CharField() diff --git a/openedx/core/djangoapps/content_libraries/views.py b/openedx/core/djangoapps/content_libraries/views.py index f4e3185be93..cff56df0757 100644 --- a/openedx/core/djangoapps/content_libraries/views.py +++ b/openedx/core/djangoapps/content_libraries/views.py @@ -5,6 +5,7 @@ from __future__ import absolute_import, division, print_function, unicode_litera from functools import wraps import logging +from opaque_keys.edx.locator import LibraryLocatorV2, LibraryUsageLocatorV2 from organizations.models import Organization from rest_framework.exceptions import NotFound, ValidationError from rest_framework.views import APIView @@ -13,7 +14,6 @@ from rest_framework.response import Response from openedx.core.lib.api.view_utils import view_auth_classes from . import api -from .keys import LibraryLocatorV2, LibraryUsageLocatorV2 from .serializers import ( ContentLibraryMetadataSerializer, ContentLibraryUpdateSerializer, @@ -155,7 +155,7 @@ class LibraryCommitView(APIView): @convert_exceptions def delete(self, request, lib_key_str): # pylint: disable=unused-argument """ - Revent the draft changes made to the specified block and its + Revert the draft changes made to the specified block and its descendants. Restore it to the last published version """ key = LibraryLocatorV2.from_string(lib_key_str) diff --git a/openedx/core/djangoapps/xblock/api.py b/openedx/core/djangoapps/xblock/api.py index b9b24b30016..12890bf0ecf 100644 --- a/openedx/core/djangoapps/xblock/api.py +++ b/openedx/core/djangoapps/xblock/api.py @@ -12,13 +12,14 @@ import logging from django.urls import reverse from django.utils.translation import ugettext as _ +from opaque_keys.edx.keys import UsageKeyV2 +from opaque_keys.edx.locator import BundleDefinitionLocator from rest_framework.exceptions import NotFound import six from xblock.core import XBlock from xblock.exceptions import NoSuchViewError from openedx.core.djangoapps.xblock.apps import get_xblock_app_config -from openedx.core.djangoapps.xblock.learning_context.keys import BundleDefinitionLocator, BlockUsageKeyV2 from openedx.core.djangoapps.xblock.learning_context.manager import get_learning_context_impl from openedx.core.djangoapps.xblock.runtime.blockstore_runtime import BlockstoreXBlockRuntime, xml_for_definition from openedx.core.djangoapps.xblock.runtime.runtime import XBlockRuntimeSystem @@ -100,7 +101,7 @@ def resolve_definition(block_or_key): """ if isinstance(block_or_key, BundleDefinitionLocator): return block_or_key - elif isinstance(block_or_key, BlockUsageKeyV2): + elif isinstance(block_or_key, UsageKeyV2): context_impl = get_learning_context_impl(block_or_key) return context_impl.definition_for_usage(block_or_key) elif isinstance(block_or_key, XBlock): diff --git a/openedx/core/djangoapps/xblock/learning_context/keys.py b/openedx/core/djangoapps/xblock/learning_context/keys.py deleted file mode 100644 index f20ddbbac89..00000000000 --- a/openedx/core/djangoapps/xblock/learning_context/keys.py +++ /dev/null @@ -1,226 +0,0 @@ -""" -New key/locator types that work with Blockstore and the new "Learning Context" -concept. - -We will probably move these key types into the "opaque-keys" repository once -they are stable. -""" -# Disable warnings about _to_deprecated_string etc. which we don't want to implement. -# And fix warnings about key fields, which pylint doesn't see as member variables. -# pylint: disable=abstract-method, no-member -from __future__ import absolute_import, division, print_function, unicode_literals -import re -from uuid import UUID -import warnings - -from opaque_keys import InvalidKeyError, OpaqueKey -from opaque_keys.edx.keys import DefinitionKey, UsageKey -import six - - -def check_key_string_field(value, regexp=r'^[\w\-.]+$'): - """ - Helper method to verify that a key's string field(s) meet certain - requirements: - Are a non-empty string - Match the specified regular expression - """ - if not isinstance(value, six.string_types): - raise TypeError("Expected a string") - if not value or not re.match(regexp, value): - raise ValueError("'{}' is not a valid field value for this key type.".format(value)) - - -def check_draft_name(value): - """ - Check that the draft name is valid (unambiguously not a bundle version - nubmer). - - Valid: studio_draft, foo-bar, import348975938 - Invalid: 1, 15, 873452847357834 - """ - if not isinstance(value, six.string_types) or not value: - raise TypeError("Expected a non-empty string") - if value.isdigit(): - raise ValueError("Cannot use an integer draft name as it conflicts with bundle version nubmers") - - -class BundleDefinitionLocator(DefinitionKey): - """ - Implementation of the DefinitionKey type, for XBlock content stored in - Blockstore bundles. This is a low-level identifier used within the Open edX - system for identifying and retrieving OLX. - - A "Definition" is a specific OLX file in a specific BundleVersion - (or sometimes rather than a BundleVersion, it may point to a named draft.) - The OLX file, and thus the definition key, defines Scope.content fields as - well as defaults for Scope.settings and Scope.children fields. However the - definition has no parent and no position in any particular course or other - context - both of which require a *usage key* and not just a definition key. - The same block definition (.olx file) can be used in multiple places in a - course, each with a different usage key. - - Example serialized definition keys follow. - - The 'html' type OLX file "html/introduction/definition.xml" in bundle - 11111111-1111-1111-1111-111111111111, bundle version 5: - - bundle-olx:11111111-1111-1111-1111-111111111111:5:html:html/introduction/definition.xml - - The 'problem' type OLX file "problem324234.xml" in bundle - 22222222-2222-2222-2222-222222222222, draft 'studio-draft': - - bundle-olx:22222222-2222-2222-2222-222222222222:studio-draft:problem:problem/324234.xml - - (The serialized version is somewhat long and verbose because it should - rarely be used except for debugging - the in-memory python key instance will - be used most of the time, and users will rarely/never see definition keys.) - - User state should never be stored using a BundleDefinitionLocator as the - key. State should always be stored against a usage locator, which refers to - a particular definition being used in a particular context. - - Each BundleDefinitionLocator holds the following data - 1. Bundle UUID and [bundle version OR draft name] - 2. Block type (e.g. 'html', 'problem', etc.) - 3. Path to OLX file - - Note that since the data in an .olx file can only ever change in a bundle - draft (not in a specific bundle version), an XBlock that is actively making - changes to its Scope.content/Scope.settings field values must have a - BundleDefinitionLocator with a draft name (not a bundle version). - """ - CANONICAL_NAMESPACE = 'bundle-olx' - KEY_FIELDS = ('bundle_uuid', 'block_type', 'olx_path', '_version_or_draft') - __slots__ = KEY_FIELDS - CHECKED_INIT = False - - def __init__(self, bundle_uuid, block_type, olx_path, bundle_version=None, draft_name=None, _version_or_draft=None): - """ - Instantiate a new BundleDefinitionLocator - """ - if not isinstance(bundle_uuid, UUID): - bundle_uuid = UUID(bundle_uuid) - check_key_string_field(block_type) - check_key_string_field(olx_path, regexp=r'^[\w\-./]+$') - # For now the following is a convention; we could remove this restriction in the future given new use cases. - assert block_type + '/' in olx_path, 'path should contain block type, e.g. html/id/definition.xml for html' - - if (bundle_version is not None) + (draft_name is not None) + (_version_or_draft is not None) != 1: - raise ValueError("Exactly one of [bundle_version, draft_name, _version_or_draft] must be specified") - if _version_or_draft is not None: - if isinstance(_version_or_draft, int): - pass # This is a bundle version number. - else: - # This is a draft name, not a bundle version: - check_draft_name(_version_or_draft) - elif draft_name is not None: - check_draft_name(draft_name) - _version_or_draft = draft_name - else: - assert isinstance(bundle_version, int) - _version_or_draft = bundle_version - - super(BundleDefinitionLocator, self).__init__( - bundle_uuid=bundle_uuid, - block_type=block_type, - olx_path=olx_path, - _version_or_draft=_version_or_draft, - ) - - @property - def bundle_version(self): - return self._version_or_draft if isinstance(self._version_or_draft, int) else None - - @property - def draft_name(self): - return self._version_or_draft if not isinstance(self._version_or_draft, int) else None - - def _to_string(self): - """ - Return a string representing this BundleDefinitionLocator - """ - return ":".join(( - six.text_type(self.bundle_uuid), six.text_type(self._version_or_draft), self.block_type, self.olx_path, - )) - - @classmethod - def _from_string(cls, serialized): - """ - Return a BundleDefinitionLocator by parsing the given serialized string - """ - try: - (bundle_uuid_str, _version_or_draft, block_type, olx_path) = serialized.split(':', 3) - except ValueError: - raise InvalidKeyError(cls, serialized) - - bundle_uuid = UUID(bundle_uuid_str) - if not block_type or not olx_path: - raise InvalidKeyError(cls, serialized) - - if _version_or_draft.isdigit(): - _version_or_draft = int(_version_or_draft) - - return cls( - bundle_uuid=bundle_uuid, - block_type=block_type, - olx_path=olx_path, - _version_or_draft=_version_or_draft, - ) - - -class LearningContextKey(OpaqueKey): - """ - A key that idenitifies a course, a library, a program, - or some other collection of content where learning happens. - """ - KEY_TYPE = 'context_key' - __slots__ = () - - def make_definition_usage(self, definition_key, usage_id=None): - """ - Return a usage key, given the given the specified definition key and - usage_id. - """ - raise NotImplementedError() - - -class BlockUsageKeyV2(UsageKey): - """ - Abstract base class that encodes an XBlock used in a specific learning - context (e.g. a course). - - Definition + Learning Context = Usage - """ - @property - def context_key(self): - raise NotImplementedError() - - @property - def definition_key(self): - """ - Returns the definition key for this usage. - """ - # Because this key definition is likely going to be moved into the - # opaque-keys package, we cannot put the logic here for getting the - # definition. - raise NotImplementedError( - "To get the definition key, use: " - "get_learning_context_impl(usage_key).definition_for_usage(usage_key)" - ) - - @property - def course_key(self): - warnings.warn("Use .context_key instead of .course_key", DeprecationWarning, stacklevel=2) - return self.context_key - - def html_id(self): - """ - Return an id which can be used on an html page as an id attr of an html - element. This is only in here for backwards-compatibility with XModules; - don't use in new code. - """ - warnings.warn(".html_id is deprecated", DeprecationWarning, stacklevel=2) - # HTML5 allows ID values to contain any characters at all other than spaces. - # These key types don't allow spaces either, so no transform is needed. - return six.text_type(self) diff --git a/openedx/core/djangoapps/xblock/learning_context/learning_context.py b/openedx/core/djangoapps/xblock/learning_context/learning_context.py index 49fa17e40c2..457e7f22256 100644 --- a/openedx/core/djangoapps/xblock/learning_context/learning_context.py +++ b/openedx/core/djangoapps/xblock/learning_context/learning_context.py @@ -31,7 +31,7 @@ class LearningContext(object): user: a Django User object (may be an AnonymousUser) - usage_key: the BlockUsageKeyV2 subclass used for this learning context + usage_key: the UsageKeyV2 subclass used for this learning context Must return a boolean. """ @@ -45,7 +45,7 @@ class LearningContext(object): user: a Django User object (may be an AnonymousUser) - usage_key: the BlockUsageKeyV2 subclass used for this learning context + usage_key: the UsageKeyV2 subclass used for this learning context Must return a boolean. """ @@ -57,7 +57,7 @@ class LearningContext(object): BundleDefinitionLocator which specifies the actual XBlock definition (as a path to an OLX in a specific blockstore bundle). - usage_key: the BlockUsageKeyV2 subclass used for this learning context + usage_key: the UsageKeyV2 subclass used for this learning context Must return a BundleDefinitionLocator if the XBlock exists in this context, or None otherwise. @@ -71,7 +71,7 @@ class LearningContext(object): The child is always from an <xblock-include /> element. - parent_usage: the BlockUsageKeyV2 subclass key of the parent + parent_usage: the UsageKeyV2 subclass key of the parent parent_definition: the BundleDefinitionLocator key of the parent (same as returned by definition_for_usage(parent_usage) but included here @@ -80,7 +80,7 @@ class LearningContext(object): parsed_include: the XBlockInclude tuple containing the data from the parsed <xblock-include /> element. See xblock.runtime.olx_parsing. - Must return a BlockUsageKeyV2 subclass + Must return a UsageKeyV2 subclass """ raise NotImplementedError diff --git a/openedx/core/djangoapps/xblock/learning_context/manager.py b/openedx/core/djangoapps/xblock/learning_context/manager.py index d354966ee4a..f6eb3c701f6 100644 --- a/openedx/core/djangoapps/xblock/learning_context/manager.py +++ b/openedx/core/djangoapps/xblock/learning_context/manager.py @@ -3,9 +3,10 @@ Helper methods for working with learning contexts """ from __future__ import absolute_import, division, print_function, unicode_literals +from opaque_keys.edx.keys import LearningContextKey, UsageKeyV2 + from openedx.core.djangoapps.xblock.apps import get_xblock_app_config from openedx.core.lib.plugins import PluginManager -from .keys import LearningContextKey, BlockUsageKeyV2 class LearningContextPluginManager(PluginManager): @@ -35,7 +36,7 @@ def get_learning_context_impl(key): """ if isinstance(key, LearningContextKey): context_type = key.CANONICAL_NAMESPACE # e.g. 'lib' - elif isinstance(key, BlockUsageKeyV2): + elif isinstance(key, UsageKeyV2): context_type = key.context_key.CANONICAL_NAMESPACE else: # Maybe this is an older modulestore key etc. diff --git a/openedx/core/djangoapps/xblock/runtime/blockstore_runtime.py b/openedx/core/djangoapps/xblock/runtime/blockstore_runtime.py index 7947577babe..a7a6a0224d2 100644 --- a/openedx/core/djangoapps/xblock/runtime/blockstore_runtime.py +++ b/openedx/core/djangoapps/xblock/runtime/blockstore_runtime.py @@ -6,10 +6,10 @@ from __future__ import absolute_import, division, print_function, unicode_litera import logging from lxml import etree +from opaque_keys.edx.locator import BundleDefinitionLocator from xblock.exceptions import NoSuchDefinition, NoSuchUsage from xblock.fields import ScopeIds -from openedx.core.djangoapps.xblock.learning_context.keys import BundleDefinitionLocator from openedx.core.djangoapps.xblock.learning_context.manager import get_learning_context_impl from openedx.core.djangoapps.xblock.runtime.runtime import XBlockRuntime from openedx.core.djangoapps.xblock.runtime.olx_parsing import parse_xblock_include diff --git a/openedx/core/djangoapps/xblock/runtime/id_managers.py b/openedx/core/djangoapps/xblock/runtime/id_managers.py index 9aae9afa311..2ba498eef32 100644 --- a/openedx/core/djangoapps/xblock/runtime/id_managers.py +++ b/openedx/core/djangoapps/xblock/runtime/id_managers.py @@ -4,9 +4,9 @@ our newer Open edX-specific opaque key formats. """ from __future__ import absolute_import, division, print_function, unicode_literals +from opaque_keys.edx.keys import UsageKeyV2 from xblock.runtime import IdReader -from openedx.core.djangoapps.xblock.learning_context.keys import BlockUsageKeyV2 from openedx.core.djangoapps.xblock.learning_context.manager import get_learning_context_impl @@ -23,7 +23,7 @@ class OpaqueKeyReader(IdReader): Returns: The `definition_id` the usage is derived from """ - if isinstance(usage_id, BlockUsageKeyV2): + if isinstance(usage_id, UsageKeyV2): return get_learning_context_impl(usage_id).definition_for_usage(usage_id) raise TypeError("This version of get_definition_id doesn't support the given key type.") diff --git a/openedx/core/djangoapps/xblock/runtime/olx_parsing.py b/openedx/core/djangoapps/xblock/runtime/olx_parsing.py index 04de70232ca..edb1e759639 100644 --- a/openedx/core/djangoapps/xblock/runtime/olx_parsing.py +++ b/openedx/core/djangoapps/xblock/runtime/olx_parsing.py @@ -4,14 +4,15 @@ Helpful methods to use when parsing OLX (XBlock XML) from __future__ import absolute_import, division, print_function, unicode_literals from collections import namedtuple -from openedx.core.djangoapps.xblock.learning_context.keys import BundleDefinitionLocator +from opaque_keys.edx.locator import BundleDefinitionLocator + from openedx.core.djangolib.blockstore_cache import get_bundle_direct_links_with_cache class BundleFormatException(Exception): """ Raised when certain errors are found when parsing the OLX in a content - libary bundle. + library bundle. """ diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index fe15add5a20..502a5043737 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -98,7 +98,7 @@ drf-yasg==1.16 edx-ace==0.1.10 edx-analytics-data-api-client==0.15.3 edx-bulk-grades==0.6.0 -edx-ccx-keys==0.2.2 +edx-ccx-keys==1.0.0 edx-celeryutils==0.3.0 edx-completion==2.0.0 edx-django-oauth2-provider==1.3.5 @@ -110,7 +110,7 @@ edx-enterprise==1.9.12 edx-i18n-tools==0.4.8 edx-milestones==0.2.3 edx-oauth2-provider==1.3.0 -edx-opaque-keys[django]==1.0.1 +edx-opaque-keys[django]==2.0.0 edx-organizations==2.1.0 edx-proctoring-proctortrack==1.0.5 edx-proctoring==2.0.8 diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index c3658c75af5..826adb84222 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -121,7 +121,7 @@ drf-yasg==1.16 edx-ace==0.1.10 edx-analytics-data-api-client==0.15.3 edx-bulk-grades==0.6.0 -edx-ccx-keys==0.2.2 +edx-ccx-keys==1.0.0 edx-celeryutils==0.3.0 edx-completion==2.0.0 edx-django-oauth2-provider==1.3.5 @@ -134,7 +134,7 @@ edx-i18n-tools==0.4.8 edx-lint==1.3.0 edx-milestones==0.2.3 edx-oauth2-provider==1.3.0 -edx-opaque-keys[django]==1.0.1 +edx-opaque-keys[django]==2.0.0 edx-organizations==2.1.0 edx-proctoring-proctortrack==1.0.5 edx-proctoring==2.0.8 diff --git a/requirements/edx/paver.txt b/requirements/edx/paver.txt index eef8f1fa12b..a4c62d73b5d 100644 --- a/requirements/edx/paver.txt +++ b/requirements/edx/paver.txt @@ -7,7 +7,7 @@ argh==0.26.2 # via watchdog certifi==2019.9.11 # via requests chardet==3.0.4 # via requests -edx-opaque-keys==1.0.1 +edx-opaque-keys==2.0.0 idna==2.8 # via requests lazy==1.1 libsass==0.10.0 diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index 38f44b19026..e4843a9fc24 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -118,7 +118,7 @@ drf-yasg==1.16 edx-ace==0.1.10 edx-analytics-data-api-client==0.15.3 edx-bulk-grades==0.6.0 -edx-ccx-keys==0.2.2 +edx-ccx-keys==1.0.0 edx-celeryutils==0.3.0 edx-completion==2.0.0 edx-django-oauth2-provider==1.3.5 @@ -131,7 +131,7 @@ edx-i18n-tools==0.4.8 edx-lint==1.3.0 edx-milestones==0.2.3 edx-oauth2-provider==1.3.0 -edx-opaque-keys[django]==1.0.1 +edx-opaque-keys[django]==2.0.0 edx-organizations==2.1.0 edx-proctoring-proctortrack==1.0.5 edx-proctoring==2.0.8 diff --git a/setup.py b/setup.py index 316ba828f59..027ba4891d2 100644 --- a/setup.py +++ b/setup.py @@ -103,15 +103,6 @@ setup( "user_authn = openedx.core.djangoapps.user_authn.apps:UserAuthnConfig", "instructor = lms.djangoapps.instructor.apps:InstructorConfig", ], - 'definition_key': [ - 'bundle-olx = openedx.core.djangoapps.xblock.learning_context.keys:BundleDefinitionLocator', - ], - 'context_key': [ - 'lib = openedx.core.djangoapps.content_libraries.keys:LibraryLocatorV2', - ], - 'usage_key': [ - 'lb = openedx.core.djangoapps.content_libraries.keys:LibraryUsageLocatorV2', - ], 'openedx.learning_context': [ 'lib = openedx.core.djangoapps.content_libraries.library_context:LibraryContextImpl', ], -- GitLab