diff --git a/README.rst b/README.rst index fd4a41600..40e4b68d9 100644 --- a/README.rst +++ b/README.rst @@ -11,7 +11,10 @@ Overview The ``openedx-core`` project holds Django apps which represent core teaching & learning platform concepts. -Each app exposes stable, public API of Python functions and Django models. Some apps additionally provides REST APIs. These APIs are suitable for use in ``openedx-platform`` as well as in community-developed Open edX plugins. +Each app exposes a public API of Python functions and Django models; some apps also provide REST APIs. These APIs are suitable for use in openedx-platform and in community-developed Open edX plugins. + +APIs marked "UNSTABLE" are subject to change at any time. All other APIs are considered stable, and any breaking changes will be announced through the community DEPR (deprecation and removal) process. + Motivation ---------- @@ -44,10 +47,10 @@ We have a few different identifier types in the schema, and we try to avoid ``_i See Also ~~~~~~~~ -The structure of this repo follows [OEP-0049](https://open-edx-proposals.readthedocs.io/en/latest/architectural-decisions/oep-0049-django-app-patterns.html) where possible, and also borrows inspiration from: +The structure of this repo follows `OEP-0049 `_ where possible, and also borrows inspiration from: -* [Scaling Django to 500 apps](https://2021.djangocon.us/talks/scaling-django-to-500-apps/) (Dan Palmer, DjangoCon US 2021) -* [Django structure for scale and longevity](https://www.youtube.com/watch?v=yG3ZdxBb1oo) (Radoslav Georgiev, EuroPython 2018) +* `Scaling Django to 500 apps `_ (Dan Palmer, DjangoCon US 2021) +* `Django structure for scale and longevity `_ (Radoslav Georgiev, EuroPython 2018) Code Overview ------------- @@ -63,11 +66,6 @@ The code in this repository is licensed under the AGPL 3.0 unless otherwise note Please see `LICENSE.txt `_ for details. -How To Contribute ------------------ - -This repo is in a very experimental state. Discussion using GitHub Issues is welcome, but you probably don't want to make contributions as everything can shift around drastically with little notice. - Reporting Security Issues ------------------------- diff --git a/setup.py b/setup.py index d451c1d6a..94e328c82 100755 --- a/setup.py +++ b/setup.py @@ -80,7 +80,7 @@ def is_requirement(line): zip_safe=False, keywords='Python edx', classifiers=[ - 'Development Status :: 3 - Alpha', + 'Development Status :: 4 - Beta', 'Framework :: Django', 'Framework :: Django :: 5.2', 'Intended Audience :: Developers', diff --git a/src/openedx_content/applets/backup_restore/api.py b/src/openedx_content/applets/backup_restore/api.py index 1f768b0b0..8f880aa7b 100644 --- a/src/openedx_content/applets/backup_restore/api.py +++ b/src/openedx_content/applets/backup_restore/api.py @@ -8,6 +8,16 @@ from ..publishing.api import get_learning_package_by_ref from .zipper import LearningPackageUnzipper, LearningPackageZipper +# The public API that will be re-exported by openedx_content.api +# is listed in the __all__ entries below. Internal helper functions that are +# private to this module should start with an underscore. If a function does not +# start with an underscore AND it is not in __all__, that function is considered +# to be callable only by other applets in the openedx_content package. +__all__ = [ + "create_zip_file", + "load_learning_package", +] + def create_zip_file( package_ref: str, path: str, user: UserType | None = None, origin_server: str | None = None diff --git a/src/openedx_content/applets/collections/api.py b/src/openedx_content/applets/collections/api.py index 40692ca03..b0b4a43f1 100644 --- a/src/openedx_content/applets/collections/api.py +++ b/src/openedx_content/applets/collections/api.py @@ -1,5 +1,5 @@ """ -Collections API (warning: UNSTABLE, in progress API) +Collections API """ from __future__ import annotations diff --git a/src/openedx_content/applets/components/api.py b/src/openedx_content/applets/components/api.py index 2a08fb159..fc4b1e843 100644 --- a/src/openedx_content/applets/components/api.py +++ b/src/openedx_content/applets/components/api.py @@ -1,5 +1,5 @@ """ -Components API (warning: UNSTABLE, in progress API) +Components API These functions are often going to be simple-looking write operations, but there is bookkeeping logic needed across multiple models to keep state consistent. You @@ -33,7 +33,7 @@ # is listed in the __all__ entries below. Internal helper functions that are # private to this module should start with an underscore. If a function does not # start with an underscore AND it is not in __all__, that function is considered -# to be callable only by other apps in the authoring package. +# to be callable only by other applets in the openedx_content package. __all__ = [ "get_or_create_component_type", "create_component", diff --git a/src/openedx_content/applets/containers/api.py b/src/openedx_content/applets/containers/api.py index 9f0756a58..8398abc47 100644 --- a/src/openedx_content/applets/containers/api.py +++ b/src/openedx_content/applets/containers/api.py @@ -1,5 +1,5 @@ """ -Containers API (warning: UNSTABLE, in progress API) +Containers API """ from __future__ import annotations @@ -43,10 +43,8 @@ # is listed in the __all__ entries below. Internal helper functions that are # private to this module should start with an underscore. If a function does not # start with an underscore AND it is not in __all__, that function is considered -# to be callable only by other apps in the authoring package. +# to be callable only by other applets in the openedx_content package. __all__ = [ - # 🛑 UNSTABLE: All APIs related to containers are unstable until we've figured - # out our approach to dynamic content (randomized, A/B tests, etc.) "ContainerSubclass", "ContainerImplementationMissingError", "create_container", @@ -76,7 +74,6 @@ @dataclass(frozen=True) class ContainerEntityListEntry: """ - [ 🛑 UNSTABLE ] Data about a single entity in a container, e.g. a component in a unit. """ @@ -145,7 +142,6 @@ def create_container( can_stand_alone: bool = True, ) -> ContainerModel: """ - [ 🛑 UNSTABLE ] Create a new container. Args: @@ -185,7 +181,6 @@ def create_container( def create_entity_list() -> EntityList: """ - [ 🛑 UNSTABLE ] Create a new entity list. This is an structure that holds a list of entities that will be referenced by the container. @@ -201,7 +196,6 @@ def create_entity_list_with_rows( learning_package_id: LearningPackage.ID | None, ) -> EntityList: """ - [ 🛑 UNSTABLE ] Create new entity list rows for an entity list. Args: @@ -307,7 +301,6 @@ def create_container_version( created_by: int | None, ) -> ContainerVersion: """ - [ 🛑 UNSTABLE ] Create a new container version. Args: @@ -357,7 +350,6 @@ def create_container_and_version( can_stand_alone: bool = True, ) -> tuple[ContainerModel, ContainerVersionModel]: """ - [ 🛑 UNSTABLE ] Create a new container and its initial version. Args: learning_package_id: The learning package ID. @@ -472,7 +464,6 @@ def create_next_container_version( force_version_num: int | None = None, ) -> ContainerVersion: """ - [ 🛑 UNSTABLE ] Create the next version of a container. A new version of the container is created only when its metadata changes: @@ -545,7 +536,6 @@ def create_next_container_version( def get_container(pk: Container.ID) -> Container: """ - [ 🛑 UNSTABLE ] Get a container by its primary key. This returns the Container, not any specific version. It may not be published, or may have been soft deleted. @@ -561,7 +551,6 @@ def get_container(pk: Container.ID) -> Container: def get_container_version(container_version_pk: int) -> ContainerVersion: """ - [ 🛑 UNSTABLE ] Get a container version by its primary key. Args: @@ -575,7 +564,6 @@ def get_container_version(container_version_pk: int) -> ContainerVersion: def get_container_by_code(learning_package_id: LearningPackage.ID, /, container_code: str) -> Container: """ - [ 🛑 UNSTABLE ] Get a container by its learning package and container code. Args: @@ -641,7 +629,6 @@ def get_containers( include_deleted: bool | None = False, ) -> QuerySet[Container]: """ - [ 🛑 UNSTABLE ] Get all containers in the given learning package. Args: @@ -669,7 +656,6 @@ def get_entities_in_container( select_related_version: str | None = None, ) -> list[ContainerEntityListEntry]: """ - [ 🛑 UNSTABLE ] Get the list of entities and their versions in the current draft or published version of the given container. @@ -728,7 +714,6 @@ def get_entities_in_container_as_of( publish_log_id: int, ) -> tuple[ContainerVersion | None, list[ContainerEntityListEntry]]: """ - [ 🛑 UNSTABLE ] Get the list of entities and their versions in the published version of the given container as of the given PublishLog version (which is essentially a version for the entire learning package). @@ -762,7 +747,6 @@ def get_entities_in_container_as_of( def contains_unpublished_changes(container_or_pk: Container | Container.ID, /) -> bool: """ - [ 🛑 UNSTABLE ] Check recursively if a container has any unpublished changes. Note: I've preserved the API signature for now, but we probably eventually @@ -815,7 +799,6 @@ def get_containers_with_entity( published=False, ) -> QuerySet[Container]: """ - [ 🛑 UNSTABLE ] Find all draft containers that directly contain the given entity. They will always be from the same learning package; cross-package containers @@ -856,7 +839,6 @@ def get_container_children_count( published: bool, ): """ - [ 🛑 UNSTABLE ] Get the count of entities in the current draft or published version of the given container. Args: @@ -894,7 +876,6 @@ def get_container_children_entity_refs(container_version: ContainerVersion) -> l def get_descendant_component_entity_ids(container: Container) -> list[int]: """ - [ 🛑 UNSTABLE ] Return the entity IDs of all leaf (non-Container) descendants of ``container``. Intermediate containers (e.g. Subsections, Units) are never included in the diff --git a/src/openedx_content/applets/media/api.py b/src/openedx_content/applets/media/api.py index 90d0ff801..bf67d4cfe 100644 --- a/src/openedx_content/applets/media/api.py +++ b/src/openedx_content/applets/media/api.py @@ -1,5 +1,5 @@ """ -Low Level media.api (warning: UNSTABLE, in progress API) +Low Level media.api Please look at the models.py file for more information about the kinds of data are stored in this app. @@ -21,7 +21,7 @@ # is listed in the __all__ entries below. Internal helper functions that are # private to this module should start with an underscore. If a function does not # start with an underscore AND it is not in __all__, that function is considered -# to be callable only by other apps in the authoring package. +# to be callable only by other applets in the openedx_content package. __all__ = [ "get_or_create_media_type", "get_media", diff --git a/src/openedx_content/applets/publishing/api.py b/src/openedx_content/applets/publishing/api.py index 88a715cbf..07d0696b4 100644 --- a/src/openedx_content/applets/publishing/api.py +++ b/src/openedx_content/applets/publishing/api.py @@ -1,5 +1,5 @@ """ -Publishing API (warning: UNSTABLE, in progress API) +Publishing API Please look at the models.py file for more information about the kinds of data are stored in this app. @@ -43,7 +43,7 @@ # is listed in the __all__ entries below. Internal helper functions that are # private to this module should start with an underscore. If a function does not # start with an underscore AND it is not in __all__, that function is considered -# to be callable only by other apps in the authoring package. +# to be callable only by other applets in the openedx_content package. __all__ = [ "get_learning_package", "get_learning_package_by_ref", @@ -621,7 +621,6 @@ def get_entity_draft_history( publishable_entity_or_id: PublishableEntity | int, / ) -> QuerySet[DraftChangeLogRecord]: """ - [ 🛑 UNSTABLE ] Return DraftChangeLogRecords for a PublishableEntity since its last publication, ordered from most recent to oldest. @@ -689,7 +688,6 @@ def get_entity_publish_history( publishable_entity_or_id: PublishableEntity | int, / ) -> QuerySet[PublishLogRecord]: """ - [ 🛑 UNSTABLE ] Return all PublishLogRecords for a PublishableEntity, ordered most recent first. Edge cases: @@ -724,7 +722,6 @@ def get_entity_publish_history_entries( publish_log_uuid: str, ) -> QuerySet[DraftChangeLogRecord]: """ - [ 🛑 UNSTABLE ] Return the DraftChangeLogRecords associated with a specific PublishLog. Finds the PublishLogRecord for the given entity and publish_log_uuid, then @@ -822,7 +819,6 @@ def get_entity_version_contributors( new_version_num: int | None, ) -> QuerySet: """ - [ 🛑 UNSTABLE ] Return distinct User queryset of contributors (changed_by) for DraftChangeLogRecords of a PublishableEntity after old_version_num. diff --git a/src/openedx_content/applets/sections/api.py b/src/openedx_content/applets/sections/api.py index 5449235eb..cdfd36e8b 100644 --- a/src/openedx_content/applets/sections/api.py +++ b/src/openedx_content/applets/sections/api.py @@ -13,8 +13,6 @@ from ..subsections.models import Subsection, SubsectionVersion from .models import Section, SectionVersion -# 🛑 UNSTABLE: All APIs related to containers are unstable until we've figured -# out our approach to dynamic content (randomized, A/B tests, etc.) __all__ = [ "get_section", "create_section_and_version", @@ -93,7 +91,6 @@ def create_next_section_version( @dataclass(frozen=True) class SectionListEntry: """ - [ 🛑 UNSTABLE ] Data about a single subsection in a section. """ @@ -111,7 +108,6 @@ def get_subsections_in_section( published: bool, ) -> list[SectionListEntry]: """ - [ 🛑 UNSTABLE ] Get the list of entities and their versions in the draft or published version of the given Section. diff --git a/src/openedx_content/applets/subsections/api.py b/src/openedx_content/applets/subsections/api.py index 1d9544990..e4c24ca36 100644 --- a/src/openedx_content/applets/subsections/api.py +++ b/src/openedx_content/applets/subsections/api.py @@ -13,8 +13,6 @@ from ..units.models import Unit, UnitVersion from .models import Subsection, SubsectionVersion -# 🛑 UNSTABLE: All APIs related to containers are unstable until we've figured -# out our approach to dynamic content (randomized, A/B tests, etc.) __all__ = [ "get_subsection", "create_subsection_and_version", @@ -93,7 +91,6 @@ def create_next_subsection_version( @dataclass(frozen=True) class SubsectionListEntry: """ - [ 🛑 UNSTABLE ] Data about a single unit in a subsection. """ @@ -111,7 +108,6 @@ def get_units_in_subsection( published: bool, ) -> list[SubsectionListEntry]: """ - [ 🛑 UNSTABLE ] Get the list of entities and their versions in the draft or published version of the given Subsection. diff --git a/src/openedx_content/applets/units/api.py b/src/openedx_content/applets/units/api.py index 415ebf291..0fb55cfe0 100644 --- a/src/openedx_content/applets/units/api.py +++ b/src/openedx_content/applets/units/api.py @@ -13,8 +13,6 @@ from ..publishing.models import LearningPackage from .models import Unit, UnitVersion -# 🛑 UNSTABLE: All APIs related to containers are unstable until we've figured -# out our approach to dynamic content (randomized, A/B tests, etc.) __all__ = [ "get_unit", "create_unit_and_version", @@ -93,7 +91,6 @@ def create_next_unit_version( @dataclass(frozen=True) class UnitListEntry: """ - [ 🛑 UNSTABLE ] Data about a single entity in a container, e.g. a component in a unit. """ @@ -111,7 +108,6 @@ def get_components_in_unit( published: bool, ) -> list[UnitListEntry]: """ - [ 🛑 UNSTABLE ] Get the list of entities and their versions in the draft or published version of the given Unit. diff --git a/src/openedx_content/migrations/0008_rename_collection_key_to_collection_code.py b/src/openedx_content/migrations/0008_rename_collection_key_to_collection_code.py index 9bdab4915..66db2a3bb 100644 --- a/src/openedx_content/migrations/0008_rename_collection_key_to_collection_code.py +++ b/src/openedx_content/migrations/0008_rename_collection_key_to_collection_code.py @@ -15,7 +15,6 @@ class Migration(migrations.Migration): dependencies = [ ('openedx_content', '0007_publishlogrecord_direct'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ diff --git a/src/openedx_content/migrations/0013_unicode_container_component_codes.py b/src/openedx_content/migrations/0013_unicode_container_component_codes.py index e944ce2fd..ad211d909 100644 --- a/src/openedx_content/migrations/0013_unicode_container_component_codes.py +++ b/src/openedx_content/migrations/0013_unicode_container_component_codes.py @@ -14,7 +14,6 @@ class Migration(migrations.Migration): dependencies = [ ('openedx_content', '0012_rename_componentversionmedia_key_to_path'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ diff --git a/src/openedx_core/__init__.py b/src/openedx_core/__init__.py index ef364eec5..e9bef3c71 100644 --- a/src/openedx_core/__init__.py +++ b/src/openedx_core/__init__.py @@ -6,4 +6,4 @@ """ # The version for the entire repository -__version__ = "0.48.1" +__version__ = "1.0.0"