Skip to content

Commit

Permalink
refactor: LibraryCollectionLocator to obtain org and lib slug from li…
Browse files Browse the repository at this point in the history
…b_key
  • Loading branch information
ChrisChV committed Aug 31, 2024
1 parent e3ff649 commit f2a904f
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 30 deletions.
15 changes: 5 additions & 10 deletions opaque_keys/edx/keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@
from __future__ import annotations
import json
from abc import abstractmethod
from typing import TYPE_CHECKING
import warnings

from typing_extensions import Self # For python 3.11 plus, can just use "from typing import Self"

from opaque_keys import OpaqueKey

if TYPE_CHECKING:
from opaque_keys.edx.locator import LibraryLocatorV2

Check warning on line 15 in opaque_keys/edx/keys.py

View check run for this annotation

Codecov / codecov/patch

opaque_keys/edx/keys.py#L15

Added line #L15 was not covered by tests


class LearningContextKey(OpaqueKey): # pylint: disable=abstract-method
"""
Expand Down Expand Up @@ -97,23 +101,14 @@ class LibraryCollectionKey(OpaqueKey):
__slots__ = ()

@property
@abstractmethod
def org(self) -> str | None: # pragma: no cover
"""
The organization that this collection belongs to.
"""
raise NotImplementedError()

@property
@abstractmethod
def lib(self) -> str | None: # pragma: no cover
"""
The lib for this collection.
"""
raise NotImplementedError()

@property
def library_key(self) -> LearningContextKey: # pragma: no cover
def library_key(self) -> LibraryLocatorV2: # pragma: no cover
"""
Get the key of the library that this collection belongs to.
"""
Expand Down
32 changes: 19 additions & 13 deletions opaque_keys/edx/locator.py
Original file line number Diff line number Diff line change
Expand Up @@ -1629,51 +1629,57 @@ class LibraryCollectionLocator(CheckFieldMixin, LibraryCollectionKey):
lib-collection:org:lib:collection-id
"""
CANONICAL_NAMESPACE = 'lib-collection'
KEY_FIELDS = ('org', 'lib', 'usage_id')
org: str
lib: str
KEY_FIELDS = ('lib_key', 'collection_id')
lib_key: LibraryLocatorV2
usage_id: str
collection_id: str

__slots__ = KEY_FIELDS
CHECKED_INIT = False

# Allow usage IDs to contian unicode characters
USAGE_ID_REGEXP = re.compile(r'^[\w\-.]+$', flags=re.UNICODE)

def __init__(self, lib_key: LibraryLocatorV2, usage_id: str):
def __init__(self, lib_key: LibraryLocatorV2, collection_id: str):
"""
Construct a CollectionLocator
"""
if not isinstance(lib_key, LibraryLocatorV2):
raise TypeError("lib_key must be a LibraryLocatorV2")

self._check_key_string_field("usage_id", usage_id, regexp=self.USAGE_ID_REGEXP)
self._check_key_string_field("collection_id", collection_id, regexp=self.USAGE_ID_REGEXP)
super().__init__(
org=lib_key.org,
lib=lib_key.slug,
lib_key=lib_key,
usage_id=usage_id,
collection_id=collection_id,
)

@property
def library_key(self) -> LibraryLocatorV2:
"""
Get the key of the library that this collection belongs to.
"""
return self.lib_key

@property
def org(self) -> str | None: # pragma: no cover
"""
The organization that this collection belongs to.
"""
return self.lib_key.org

def _to_string(self) -> str:
"""
Serialize this key as a string
"""
return ":".join((self.org, self.lib, self.usage_id))
return ":".join((self.lib_key.org, self.lib_key.slug, self.collection_id))

@classmethod
def _from_string(cls, serialized: str) -> Self:
"""
Instantiate this key from a serialized string
"""
try:
(org, lib, usage_id) = serialized.split(':')
lib_key = LibraryLocatorV2(org, lib)
return cls(lib_key, usage_id)
(org, lib_slug, collection_id) = serialized.split(':')
lib_key = LibraryLocatorV2(org, lib_slug)
return cls(lib_key, collection_id)
except (ValueError, TypeError) as error:
raise InvalidKeyError(cls, serialized) from error

Check warning on line 1685 in opaque_keys/edx/locator.py

View check run for this annotation

Codecov / codecov/patch

opaque_keys/edx/locator.py#L1684-L1685

Added lines #L1684 - L1685 were not covered by tests
12 changes: 5 additions & 7 deletions opaque_keys/edx/tests/test_collection_locators.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,21 @@ def test_coll_key_constructor(self):
lib = 'LibraryX'
code = 'test-problem-bank'
lib_key = LibraryLocatorV2(org=org, slug=lib)
coll_key = LibraryCollectionLocator(lib_key=lib_key, usage_id=code)
coll_key = LibraryCollectionLocator(lib_key=lib_key, collection_id=code)
lib_key = coll_key.library_key
self.assertEqual(str(coll_key), "lib-collection:TestX:LibraryX:test-problem-bank")
self.assertEqual(coll_key.org, org)
self.assertEqual(coll_key.lib, lib)
self.assertEqual(coll_key.usage_id, code)
self.assertEqual(coll_key.collection_id, code)
self.assertEqual(lib_key.org, org)
self.assertEqual(lib_key.slug, lib)

def test_coll_key_constructor_bad_ids(self):
lib_key = LibraryLocatorV2(org="TestX", slug="lib1")

with self.assertRaises(ValueError):
LibraryCollectionLocator(lib_key=lib_key, usage_id='usage-!@#{$%^&*}')
LibraryCollectionLocator(lib_key=lib_key, collection_id='usage-!@#{$%^&*}')
with self.assertRaises(TypeError):
LibraryCollectionLocator(lib_key=None, usage_id='usage')
LibraryCollectionLocator(lib_key=None, collection_id='usage')

def test_coll_key_from_string(self):
org = 'TestX'
Expand All @@ -56,8 +55,7 @@ def test_coll_key_from_string(self):
lib_key = coll_key.library_key
self.assertEqual(str(coll_key), str_key)
self.assertEqual(coll_key.org, org)
self.assertEqual(coll_key.lib, lib)
self.assertEqual(coll_key.usage_id, code)
self.assertEqual(coll_key.collection_id, code)
self.assertEqual(lib_key.org, org)
self.assertEqual(lib_key.slug, lib)

Expand Down

0 comments on commit f2a904f

Please sign in to comment.