Files
Kyle McCormick c70bfe980a build!: Switch to openedx-core (renamed from openedx-learning) (#38011)
build!: Switch to openedx-core (renamed from openedx-learning)

Instead of installing openedx-learning==0.32.0, we install openedx-core==0.34.1.
We update various class names, function names, docstrings, and comments to
represent the rename:

* We say "openedx-core" when referring to the whole repo or PyPI project
  * or occasionally "Open edX Core" if we want it to look nice in the docs.
* We say "openedx_content" to refer to the Content API within openedx-core,
   which is actually the thing we have been calling "Learning Core" all along.
  * In snake-case code, it's `*_openedx_content_*`.
  * In camel-case code, it's `*OpenedXContent*`

For consistency's sake we avoid anything else like oex_core, OeXCore,
OpenEdXCore, OexContent, openedx-content, OpenEdxContent, etc.
There should be no more references to learning_core, learning-core, Learning Core,
Learning-Core, LC, openedx-learning, openedx_learning, etc.

BREAKING CHANGE: for openedx-learning/openedx-core developers:
You may need to uninstall openedx-learning and re-install openedx-core
from your venv. If running tutor, you may need to un-mount openedx-learning,
rename the directory to openedx-core, re-mount it, and re-build.
The code APIs themselves are fully backwards-compatible.

Part of: https://github.com/openedx/openedx-core/issues/470
2026-02-18 22:38:25 +00:00

135 lines
3.7 KiB
Python

"""
Value objects
"""
from __future__ import annotations
import typing as t
from dataclasses import dataclass
from enum import Enum
from uuid import UUID
from django.utils.translation import gettext_lazy as _
from opaque_keys.edx.keys import UsageKey
from opaque_keys.edx.locator import (
CourseLocator,
LibraryContainerLocator,
LibraryLocator,
LibraryLocatorV2,
LibraryUsageLocatorV2,
)
from openedx.core.djangoapps.content_libraries.api import ContainerType
class CompositionLevel(Enum):
"""
Enumeration of composition levels for legacy content.
Defined in increasing order of complexity so that `is_higher_than` works correctly.
"""
# Components are individual XBlocks, e.g. Problem
Component = 'component'
# Container types currently supported by Content Libraries
Unit = ContainerType.Unit.value
Subsection = ContainerType.Subsection.value
Section = ContainerType.Section.value
@property
def is_container(self) -> bool:
return self is not self.Component
def is_higher_than(self, other: 'CompositionLevel') -> bool:
"""
Is this composition level 'above' (more complex than) the other?
"""
levels: list[CompositionLevel] = list(self.__class__)
return levels.index(self) > levels.index(other)
@classmethod
def supported_choices(cls) -> list[tuple[str, str]]:
"""
Returns all supported composition levels as a list of tuples,
for use in a Django Models ChoiceField.
"""
return [
(composition_level.value, composition_level.name)
for composition_level in cls
]
class RepeatHandlingStrategy(Enum):
"""
Enumeration of repeat handling strategies for imported content.
"""
Skip = 'skip'
Fork = 'fork'
Update = 'update'
@classmethod
def supported_choices(cls) -> list[tuple[str, str]]:
"""
Returns all supported repeat handling strategies as a list of tuples,
for use in a Django Models ChoiceField.
"""
return [
(strategy.value, strategy.name)
for strategy in cls
]
@classmethod
def default(cls) -> RepeatHandlingStrategy:
"""
Returns the default repeat handling strategy.
"""
return cls.Skip
SourceContextKey: t.TypeAlias = CourseLocator | LibraryLocator
@dataclass(frozen=True)
class ModulestoreMigration:
"""
Metadata on a migration of a course or legacy library to a v2 library in openedx_content.
"""
pk: int
source_key: SourceContextKey
target_key: LibraryLocatorV2
target_title: str
target_collection_slug: str | None
target_collection_title: str | None
is_failed: bool
task_uuid: UUID # the UserTask which executed this migration
@dataclass(frozen=True)
class ModulestoreBlockMigrationResult:
"""
Base class for a modulestore block that was part of an attempted migration to openedx_content.
"""
source_key: UsageKey
is_failed: t.ClassVar[bool]
@dataclass(frozen=True)
class ModulestoreBlockMigrationSuccess(ModulestoreBlockMigrationResult):
"""
Info on a modulestore block which has been successfully migrated to an openedx_content entity
"""
target_entity_pk: int
target_key: LibraryUsageLocatorV2 | LibraryContainerLocator
target_title: str
target_version_num: int | None
is_failed: t.ClassVar[bool] = False
@dataclass(frozen=True)
class ModulestoreBlockMigrationFailure(ModulestoreBlockMigrationResult):
"""
Info on a modulestore block which failed to be migrated into openedx_content
"""
unsupported_reason: str
is_failed: t.ClassVar[bool] = True