diff --git a/src/openedx_content/applets/sections/api.py b/src/openedx_content/applets/sections/api.py index 17ca8781..9c547355 100644 --- a/src/openedx_content/applets/sections/api.py +++ b/src/openedx_content/applets/sections/api.py @@ -8,7 +8,7 @@ from typing import Iterable from ..containers import api as containers_api -from ..containers.models import Container, ContainerVersion +from ..containers.models import ContainerVersion from ..publishing.models import LearningPackage from ..subsections.models import Subsection, SubsectionVersion from .models import Section, SectionVersion @@ -24,7 +24,7 @@ ] -def get_section(section_id: Container.PK, /): +def get_section(section_id: Section.PK, /): """Get a section""" return Section.objects.select_related("container").get(pk=section_id) @@ -61,7 +61,7 @@ def create_section_and_version( def create_next_section_version( - section: Section | Container.PK, + section: Section | Section.PK, *, title: str | None = None, subsections: Iterable[Subsection | SubsectionVersion] | None = None, diff --git a/src/openedx_content/applets/sections/models.py b/src/openedx_content/applets/sections/models.py index 3aba6a4c..78cb55a5 100644 --- a/src/openedx_content/applets/sections/models.py +++ b/src/openedx_content/applets/sections/models.py @@ -2,13 +2,13 @@ Models that implement sections """ -from typing import override +from typing import NewType, TypeAlias, cast, override from django.core.exceptions import ValidationError from django.db import models from ..containers.api import get_container_subclass_of -from ..containers.models import Container, ContainerVersion +from ..containers.models import Container, ContainerPK, ContainerVersion from ..publishing.models import PublishableEntity from ..subsections.models import Subsection @@ -17,6 +17,8 @@ "SectionVersion", ] +SectionPK = NewType("SectionPK", ContainerPK) + @Container.register_subclass class Section(Container): @@ -27,6 +29,8 @@ class Section(Container): entities and can be added to other containers. """ + PK: TypeAlias = SectionPK + type_code = "section" olx_tag_name = "chapter" # Serializes to OLX as `...`. @@ -37,6 +41,10 @@ class Section(Container): primary_key=True, ) + @property + def id(self) -> SectionPK: + return cast(SectionPK, self.publishable_entity_id) + @override @classmethod def validate_entity(cls, entity: PublishableEntity) -> None: diff --git a/src/openedx_content/applets/subsections/api.py b/src/openedx_content/applets/subsections/api.py index 9ff4a08b..cc665987 100644 --- a/src/openedx_content/applets/subsections/api.py +++ b/src/openedx_content/applets/subsections/api.py @@ -8,7 +8,7 @@ from typing import Iterable from ..containers import api as containers_api -from ..containers.models import Container, ContainerVersion +from ..containers.models import ContainerVersion from ..publishing.models import LearningPackage from ..units.models import Unit, UnitVersion from .models import Subsection, SubsectionVersion @@ -24,7 +24,7 @@ ] -def get_subsection(subsection_id: Container.PK, /): +def get_subsection(subsection_id: Subsection.PK, /): """Get a subsection""" return Subsection.objects.select_related("container").get(pk=subsection_id) @@ -61,7 +61,7 @@ def create_subsection_and_version( def create_next_subsection_version( - subsection: Subsection | Container.PK, + subsection: Subsection | Subsection.PK, *, title: str | None = None, units: Iterable[Unit | UnitVersion] | None = None, diff --git a/src/openedx_content/applets/subsections/models.py b/src/openedx_content/applets/subsections/models.py index ee470b6e..8484896b 100644 --- a/src/openedx_content/applets/subsections/models.py +++ b/src/openedx_content/applets/subsections/models.py @@ -2,13 +2,13 @@ Models that implement subsections """ -from typing import override +from typing import NewType, TypeAlias, cast, override from django.core.exceptions import ValidationError from django.db import models from ..containers.api import get_container_subclass_of -from ..containers.models import Container, ContainerVersion +from ..containers.models import Container, ContainerPK, ContainerVersion from ..publishing.models import PublishableEntity from ..units.models import Unit @@ -17,6 +17,8 @@ "SubsectionVersion", ] +SubsectionPK = NewType("SubsectionPK", ContainerPK) + @Container.register_subclass class Subsection(Container): @@ -27,6 +29,8 @@ class Subsection(Container): entities and can be added to other containers. """ + PK: TypeAlias = SubsectionPK + type_code = "subsection" olx_tag_name = "sequential" # Serializes to OLX as `...`. @@ -37,6 +41,10 @@ class Subsection(Container): primary_key=True, ) + @property + def id(self) -> SubsectionPK: + return cast(SubsectionPK, self.publishable_entity_id) + @override @classmethod def validate_entity(cls, entity: PublishableEntity) -> None: diff --git a/src/openedx_content/applets/units/api.py b/src/openedx_content/applets/units/api.py index 7994a10f..56c040d2 100644 --- a/src/openedx_content/applets/units/api.py +++ b/src/openedx_content/applets/units/api.py @@ -9,7 +9,7 @@ from ..components.models import Component, ComponentVersion from ..containers import api as containers_api -from ..containers.models import Container, ContainerVersion +from ..containers.models import ContainerVersion from ..publishing.models import LearningPackage from .models import Unit, UnitVersion @@ -24,7 +24,7 @@ ] -def get_unit(unit_id: Container.PK, /): +def get_unit(unit_id: Unit.PK, /): """Get a unit""" return Unit.objects.select_related("container").get(pk=unit_id) @@ -61,7 +61,7 @@ def create_unit_and_version( def create_next_unit_version( - unit: Unit | Container.PK, + unit: Unit | Unit.PK, *, title: str | None = None, components: Iterable[Component | ComponentVersion] | None = None, diff --git a/src/openedx_content/applets/units/models.py b/src/openedx_content/applets/units/models.py index 3594acb7..a1016fd4 100644 --- a/src/openedx_content/applets/units/models.py +++ b/src/openedx_content/applets/units/models.py @@ -2,12 +2,12 @@ Models that implement units """ -from typing import override +from typing import NewType, TypeAlias, cast, override from django.core.exceptions import ValidationError from django.db import models -from ..containers.models import Container, ContainerVersion +from ..containers.models import Container, ContainerPK, ContainerVersion from ..publishing.models import PublishableEntity __all__ = [ @@ -15,6 +15,8 @@ "UnitVersion", ] +UnitPK = NewType("UnitPK", ContainerPK) + @Container.register_subclass class Unit(Container): @@ -25,6 +27,8 @@ class Unit(Container): entities and can be added to other containers. """ + PK: TypeAlias = UnitPK + type_code = "unit" olx_tag_name = "vertical" # Serializes to OLX as `...`. @@ -35,6 +39,10 @@ class Unit(Container): primary_key=True, ) + @property + def id(self) -> UnitPK: + return cast(UnitPK, self.publishable_entity_id) + @override @classmethod def validate_entity(cls, entity: PublishableEntity) -> None: diff --git a/tests/openedx_content/applets/sections/test_api.py b/tests/openedx_content/applets/sections/test_api.py index c7024526..ba43edfd 100644 --- a/tests/openedx_content/applets/sections/test_api.py +++ b/tests/openedx_content/applets/sections/test_api.py @@ -8,7 +8,7 @@ from django.core.exceptions import ValidationError import openedx_content.api as content_api -from openedx_content.models_api import Container, Section, SectionVersion, Subsection, SubsectionVersion +from openedx_content.models_api import Section, SectionVersion, Subsection, SubsectionVersion from ..components.test_api import ComponentTestCase @@ -140,14 +140,14 @@ def test_get_section(self) -> None: def test_get_section_nonexistent(self) -> None: """Test `get_section()` when the subsection doesn't exist""" - FAKE_ID = cast(Container.PK, -500) + FAKE_ID = cast(Section.PK, -500) with pytest.raises(Section.DoesNotExist): content_api.get_section(FAKE_ID) def test_get_section_other_container_type(self) -> None: """Test `get_section()` when the provided PK is for a non-Subsection container""" with pytest.raises(Section.DoesNotExist): - content_api.get_section(self.unit_1.id) + content_api.get_section(self.unit_1.id) # type: ignore[arg-type] def test_section_queries(self) -> None: """ diff --git a/tests/openedx_content/applets/subsections/test_api.py b/tests/openedx_content/applets/subsections/test_api.py index 87727780..0466b3dc 100644 --- a/tests/openedx_content/applets/subsections/test_api.py +++ b/tests/openedx_content/applets/subsections/test_api.py @@ -1,13 +1,14 @@ """ Basic tests for the subsections API. """ + from typing import cast import pytest from django.core.exceptions import ValidationError import openedx_content.api as content_api -from openedx_content.models_api import Container, Subsection, SubsectionVersion, Unit, UnitVersion +from openedx_content.models_api import Subsection, SubsectionVersion, Unit, UnitVersion from ..components.test_api import ComponentTestCase @@ -117,14 +118,14 @@ def test_get_subsection(self) -> None: def test_get_subsection_nonexistent(self) -> None: """Test `get_subsection()` when the subsection doesn't exist""" - FAKE_ID = cast(Container.PK, -500) + FAKE_ID = cast(Subsection.PK, -500) with pytest.raises(Subsection.DoesNotExist): content_api.get_subsection(FAKE_ID) def test_get_subsection_other_container_type(self) -> None: """Test `get_subsection()` when the provided PK is for a non-Subsection container""" with pytest.raises(Subsection.DoesNotExist): - content_api.get_subsection(self.unit_1.id) + content_api.get_subsection(self.unit_1.id) # type: ignore[arg-type] def test_subsection_queries(self) -> None: """ diff --git a/tests/openedx_content/applets/units/test_api.py b/tests/openedx_content/applets/units/test_api.py index d21ff2a1..c5a969d7 100644 --- a/tests/openedx_content/applets/units/test_api.py +++ b/tests/openedx_content/applets/units/test_api.py @@ -1,13 +1,14 @@ """ Basic tests for the units API. """ + from typing import cast import pytest from django.core.exceptions import ValidationError import openedx_content.api as content_api -from openedx_content.models_api import Component, ComponentVersion, Container, Unit, UnitVersion +from openedx_content.models_api import Component, ComponentVersion, Unit, UnitVersion from tests.test_django_app.models import TestContainer from ..components.test_api import ComponentTestCase @@ -111,7 +112,7 @@ def test_get_unit(self) -> None: def test_get_unit_nonexistent(self) -> None: """Test `get_unit()` when the unit doesn't exist""" - FAKE_ID = cast(Container.PK, -500) + FAKE_ID = cast(Unit.PK, -500) with pytest.raises(Unit.DoesNotExist): content_api.get_unit(FAKE_ID) @@ -125,7 +126,7 @@ def test_get_unit_other_container_type(self) -> None: container_cls=TestContainer, ) with pytest.raises(Unit.DoesNotExist): - content_api.get_unit(other_container.id) + content_api.get_unit(other_container.id) # type: ignore[arg-type] def test_unit_queries(self) -> None: """