"""
Deprecated OpaqueKey implementations used by XML and Mongo modulestores
"""
from __future__ import absolute_import
import re
import warnings
from opaque_keys.edx.keys import i4xEncoder as real_i4xEncoder
from opaque_keys.edx.locator import AssetLocator, BlockUsageLocator, CourseLocator, Locator
# This file passes through to protected members of the non-deprecated classes,
# and that's ok. It also may not implement all of the current UsageKey methods.
# pylint: disable=protected-access, abstract-method
[docs]class i4xEncoder(real_i4xEncoder): # pylint: disable=invalid-name
"""Deprecated. Use :class:`keys.i4xEncoder`"""
def __init__(self, *args, **kwargs):
"""Deprecated. Use :class:`keys.i4xEncoder.default`"""
warnings.warn(
"locations.i4xEncoder.default is deprecated! Please use keys.i4xEncoder.default",
DeprecationWarning,
stacklevel=2
)
super(i4xEncoder, self).__init__(*args, **kwargs)
[docs]class SlashSeparatedCourseKey(CourseLocator):
"""Deprecated. Use :class:`locator.CourseLocator`"""
def __init__(self, org, course, run, **kwargs):
warnings.warn(
"SlashSeparatedCourseKey is deprecated! Please use locator.CourseLocator",
DeprecationWarning,
stacklevel=2
)
super(SlashSeparatedCourseKey, self).__init__(org, course, run, deprecated=True, **kwargs)
@classmethod
[docs] def from_deprecated_string(cls, serialized):
"""Deprecated. Use :class:`locator.CourseLocator.from_string`"""
warnings.warn(
"SlashSeparatedCourseKey is deprecated! Please use locator.CourseLocator",
DeprecationWarning,
stacklevel=2
)
return CourseLocator.from_string(serialized)
@classmethod
[docs] def from_string(cls, serialized):
"""Deprecated. Use :meth:`locator.CourseLocator.from_string`."""
warnings.warn(
"SlashSeparatedCourseKey is deprecated! Please use locator.CourseLocator",
DeprecationWarning,
stacklevel=2
)
return CourseLocator.from_string(serialized)
[docs] def replace(self, **kwargs):
"""
Return: a new :class:`SlashSeparatedCourseKey` with specific ``kwargs`` replacing
their corresponding values.
Using CourseLocator's replace function results in a mismatch of __init__ args and kwargs.
Replace tries to instantiate a SlashSeparatedCourseKey object with CourseLocator args and kwargs.
"""
# Deprecation value is hard coded as True in __init__ and therefore does not need to be passed through.
return SlashSeparatedCourseKey(
kwargs.pop('org', self.org),
kwargs.pop('course', self.course),
kwargs.pop('run', self.run),
**kwargs
)
[docs]class LocationBase(object):
"""Deprecated. Base class for :class:`Location` and :class:`AssetLocation`"""
DEPRECATED_TAG = None # Subclasses should define what DEPRECATED_TAG is
@classmethod
def _deprecation_warning(cls):
"""Display a deprecation warning for the given cls"""
if issubclass(cls, Location):
warnings.warn(
"Location is deprecated! Please use locator.BlockUsageLocator",
DeprecationWarning,
stacklevel=3
)
elif issubclass(cls, AssetLocation):
warnings.warn(
"AssetLocation is deprecated! Please use locator.AssetLocator",
DeprecationWarning,
stacklevel=3
)
else:
warnings.warn(
"{} is deprecated!".format(cls),
DeprecationWarning,
stacklevel=3
)
@property
def tag(self):
"""Deprecated. Returns the deprecated tag for this Location."""
warnings.warn(
"Tag is no longer supported as a property of Locators.",
DeprecationWarning,
stacklevel=2
)
return self.DEPRECATED_TAG
@classmethod
def _check_location_part(cls, val, regexp):
"""Deprecated. See CourseLocator._check_location_part"""
cls._deprecation_warning()
return CourseLocator._check_location_part(val, regexp)
@classmethod
def _clean(cls, value, invalid):
"""Deprecated. See BlockUsageLocator._clean"""
cls._deprecation_warning()
return BlockUsageLocator._clean(value, invalid)
@classmethod
[docs] def clean(cls, value):
"""Deprecated. See BlockUsageLocator.clean"""
cls._deprecation_warning()
return BlockUsageLocator.clean(value)
@classmethod
[docs] def clean_keeping_underscores(cls, value):
"""Deprecated. See BlockUsageLocator.clean_keeping_underscores"""
cls._deprecation_warning()
return BlockUsageLocator.clean_keeping_underscores(value)
@classmethod
[docs] def clean_for_url_name(cls, value):
"""Deprecated. See BlockUsageLocator.clean_for_url_name"""
cls._deprecation_warning()
return BlockUsageLocator.clean_for_url_name(value)
@classmethod
[docs] def clean_for_html(cls, value):
"""Deprecated. See BlockUsageLocator.clean_for_html"""
cls._deprecation_warning()
return BlockUsageLocator.clean_for_html(value)
def __init__(self, org, course, run, category, name, revision=None, **kwargs):
self._deprecation_warning()
course_key = kwargs.pop('course_key', CourseLocator(
org=org,
course=course,
run=run,
branch=revision,
deprecated=True
))
super(LocationBase, self).__init__(course_key, category, name, deprecated=True, **kwargs)
@classmethod
[docs] def from_deprecated_string(cls, serialized):
"""Deprecated. Use :meth:`locator.BlockUsageLocator.from_string`."""
cls._deprecation_warning()
return BlockUsageLocator.from_string(serialized)
@classmethod
[docs] def from_string(cls, serialized):
"""Deprecated. Use :meth:`locator.BlockUsageLocator.from_string`."""
cls._deprecation_warning()
return BlockUsageLocator.from_string(serialized)
@classmethod
def _from_deprecated_son(cls, id_dict, run):
"""Deprecated. See BlockUsageLocator._from_deprecated_son"""
cls._deprecation_warning()
return BlockUsageLocator._from_deprecated_son(id_dict, run)
[docs]class Location(LocationBase, BlockUsageLocator):
"""Deprecated. Use :class:`locator.BlockUsageLocator`"""
DEPRECATED_TAG = 'i4x'
[docs] def replace(self, **kwargs):
"""
Return: a new :class:`Location` with specific ``kwargs`` replacing
their corresponding values.
Using BlockUsageLocator's replace function results in a mismatch of __init__ args and kwargs.
Replace tries to instantiate a Location object with BlockUsageLocator's args and kwargs.
"""
# NOTE: Deprecation value is hard coded as True in __init__ and therefore does not need to be passed through.
return Location(
kwargs.pop('org', self.course_key.org),
kwargs.pop('course', self.course_key.course),
kwargs.pop('run', self.course_key.run),
kwargs.pop('category', self.category),
kwargs.pop('name', self.name),
revision=kwargs.pop('revision', self.revision),
**kwargs
)
[docs]class DeprecatedLocation(BlockUsageLocator):
"""
The short-lived location:org+course+run+block_type+block_id syntax
"""
CANONICAL_NAMESPACE = 'location'
URL_RE_SOURCE = r"""
(?P<org>{ALLOWED_ID_CHARS}+)\+(?P<course>{ALLOWED_ID_CHARS}+)\+(?P<run>{ALLOWED_ID_CHARS}+)\+
(?P<block_type>{ALLOWED_ID_CHARS}+)\+
(?P<block_id>{ALLOWED_ID_CHARS}+)
""".format(ALLOWED_ID_CHARS=Locator.ALLOWED_ID_CHARS)
URL_RE = re.compile('^' + URL_RE_SOURCE + r'\Z', re.VERBOSE | re.UNICODE)
def __init__(self, course_key, block_type, block_id):
if course_key.version_guid is not None:
raise ValueError("DeprecatedLocations don't support course versions")
if course_key.branch is not None:
raise ValueError("DeprecatedLocations don't support course branches")
super(DeprecatedLocation, self).__init__(course_key, block_type, block_id)
@classmethod
def _from_string(cls, serialized):
"""
see super
"""
# Allow access to _from_string protected method
parsed_parts = cls.parse_url(serialized)
course_key = CourseLocator(
parsed_parts.get('org'), parsed_parts.get('course'), parsed_parts.get('run'),
# specifically not saying deprecated=True b/c that would lose the run on serialization
)
block_id = parsed_parts.get('block_id')
return cls(course_key, parsed_parts.get('block_type'), block_id)
def _to_string(self):
"""
Return a string representing this location.
"""
parts = [self.org, self.course, self.run, self.block_type, self.block_id]
return u"+".join(parts)
[docs]class AssetLocation(LocationBase, AssetLocator):
"""Deprecated. Use :class:`locator.AssetLocator`"""
DEPRECATED_TAG = 'c4x'
[docs] def replace(self, **kwargs):
"""
Return: a new :class:`AssetLocation` with specific ``kwargs`` replacing
their corresponding values.
Using AssetLocator's replace function results in a mismatch of __init__ args and kwargs.
Replace tries to instantiate an AssetLocation object with AssetLocators args and kwargs.
"""
# NOTE: Deprecation value is hard coded as True in __init__ and therefore does not need to be passed through.
return AssetLocation(
kwargs.pop('org', self.org),
kwargs.pop('course', self.course),
kwargs.pop('run', self.run),
kwargs.pop('category', self.category),
kwargs.pop('name', self.name),
revision=kwargs.pop('revision', self.revision),
**kwargs
)
@classmethod
def _from_deprecated_string(cls, serialized):
"""Deprecated. See AssetLocator._from_deprecated_string"""
cls._deprecation_warning()
return AssetLocator._from_deprecated_string(serialized)
@classmethod
def _from_deprecated_son(cls, id_dict, run):
"""Deprecated. See BlockUsageLocator._from_deprecated_son"""
cls._deprecation_warning()
return AssetLocator._from_deprecated_son(id_dict, run)
@classmethod
[docs] def from_deprecated_string(cls, serialized):
return cls._from_deprecated_string(serialized)