Skip to content
16 changes: 7 additions & 9 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
----------
Expand Down Expand Up @@ -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 <https://open-edx-proposals.readthedocs.io/en/latest/architectural-decisions/oep-0049-django-app-patterns.html>`_ 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 <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)

Code Overview
-------------
Expand All @@ -64,11 +67,6 @@ The code in this repository is licensed under the AGPL 3.0 unless otherwise note

Please see `LICENSE.txt <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
-------------------------

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
11 changes: 11 additions & 0 deletions src/openedx_content/applets/backup_restore/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@
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
) -> None:
Expand Down
2 changes: 1 addition & 1 deletion src/openedx_content/applets/collections/api.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
Collections API (warning: UNSTABLE, in progress API)
Collections API
"""
from __future__ import annotations

Expand Down
4 changes: 2 additions & 2 deletions src/openedx_content/applets/components/api.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -31,7 +31,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",
Expand Down
40 changes: 19 additions & 21 deletions src/openedx_content/applets/containers/api.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
Containers API (warning: UNSTABLE, in progress API)
Containers API
"""

from __future__ import annotations
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -76,7 +74,7 @@
@dataclass(frozen=True)
class ContainerEntityListEntry:
"""
[ 🛑 UNSTABLE ]
[ ❓TODO: STABLE or UNSTABLE? ]
Data about a single entity in a container, e.g. a component in a unit.
"""

Expand Down Expand Up @@ -145,7 +143,7 @@ def create_container(
can_stand_alone: bool = True,
) -> ContainerModel:
"""
[ 🛑 UNSTABLE ]
[ ❓TODO: STABLE or UNSTABLE? ]
Create a new container.

Args:
Expand Down Expand Up @@ -185,7 +183,7 @@ def create_container(

def create_entity_list() -> EntityList:
"""
[ 🛑 UNSTABLE ]
[ ❓TODO: STABLE or UNSTABLE? ]
Create a new entity list. This is an structure that holds a list of entities
that will be referenced by the container.

Expand All @@ -201,7 +199,7 @@ def create_entity_list_with_rows(
learning_package_id: LearningPackage.ID | None,
) -> EntityList:
"""
[ 🛑 UNSTABLE ]
[ ❓TODO: STABLE or UNSTABLE? ]
Create new entity list rows for an entity list.

Args:
Expand Down Expand Up @@ -307,7 +305,7 @@ def create_container_version(
created_by: int | None,
) -> ContainerVersion:
"""
[ 🛑 UNSTABLE ]
[ ❓TODO: STABLE or UNSTABLE? ]
Create a new container version.

Args:
Expand Down Expand Up @@ -357,7 +355,7 @@ def create_container_and_version(
can_stand_alone: bool = True,
) -> tuple[ContainerModel, ContainerVersionModel]:
"""
[ 🛑 UNSTABLE ] Create a new container and its initial version.
[ ❓TODO: STABLE or UNSTABLE? ] Create a new container and its initial version.

Args:
learning_package_id: The learning package ID.
Expand Down Expand Up @@ -472,7 +470,7 @@ def create_next_container_version(
force_version_num: int | None = None,
) -> ContainerVersion:
"""
[ 🛑 UNSTABLE ]
[ ❓TODO: STABLE or UNSTABLE? ]
Create the next version of a container. A new version of the container is created
only when its metadata changes:

Expand Down Expand Up @@ -545,7 +543,7 @@ def create_next_container_version(

def get_container(pk: Container.ID) -> Container:
"""
[ 🛑 UNSTABLE ]
[ ❓TODO: STABLE or 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.
Expand All @@ -561,7 +559,7 @@ def get_container(pk: Container.ID) -> Container:

def get_container_version(container_version_pk: int) -> ContainerVersion:
"""
[ 🛑 UNSTABLE ]
[ ❓TODO: STABLE or UNSTABLE? ]
Get a container version by its primary key.

Args:
Expand All @@ -575,7 +573,7 @@ def get_container_version(container_version_pk: int) -> ContainerVersion:

def get_container_by_code(learning_package_id: LearningPackage.ID, /, container_code: str) -> Container:
"""
[ 🛑 UNSTABLE ]
[ ❓TODO: STABLE or UNSTABLE? ]
Get a container by its learning package and container code.

Args:
Expand Down Expand Up @@ -641,7 +639,7 @@ def get_containers(
include_deleted: bool | None = False,
) -> QuerySet[Container]:
"""
[ 🛑 UNSTABLE ]
[ ❓TODO: STABLE or UNSTABLE? ]
Get all containers in the given learning package.

Args:
Expand Down Expand Up @@ -669,7 +667,7 @@ def get_entities_in_container(
select_related_version: str | None = None,
) -> list[ContainerEntityListEntry]:
"""
[ 🛑 UNSTABLE ]
[ ❓TODO: STABLE or UNSTABLE? ]
Get the list of entities and their versions in the current draft or
published version of the given container.

Expand Down Expand Up @@ -728,7 +726,7 @@ def get_entities_in_container_as_of(
publish_log_id: int,
) -> tuple[ContainerVersion | None, list[ContainerEntityListEntry]]:
"""
[ 🛑 UNSTABLE ]
[ ❓TODO: STABLE or 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).
Expand Down Expand Up @@ -762,7 +760,7 @@ def get_entities_in_container_as_of(

def contains_unpublished_changes(container_or_pk: Container | Container.ID, /) -> bool:
"""
[ 🛑 UNSTABLE ]
[ ❓TODO: STABLE or UNSTABLE? ]
Check recursively if a container has any unpublished changes.

Note: I've preserved the API signature for now, but we probably eventually
Expand Down Expand Up @@ -815,7 +813,7 @@ def get_containers_with_entity(
published=False,
) -> QuerySet[Container]:
"""
[ 🛑 UNSTABLE ]
[ ❓TODO: STABLE or UNSTABLE? ]
Find all draft containers that directly contain the given entity.

They will always be from the same learning package; cross-package containers
Expand Down Expand Up @@ -856,7 +854,7 @@ def get_container_children_count(
published: bool,
):
"""
[ 🛑 UNSTABLE ]
[ ❓TODO: STABLE or UNSTABLE? ]
Get the count of entities in the current draft or published version of the given container.

Args:
Expand Down Expand Up @@ -894,7 +892,7 @@ def get_container_children_entity_refs(container_version: ContainerVersion) -> l

def get_descendant_component_entity_ids(container: Container) -> list[int]:
"""
[ 🛑 UNSTABLE ]
[ ❓TODO: STABLE or UNSTABLE? ]
Return the entity IDs of all leaf (non-Container) descendants of ``container``.

Intermediate containers (e.g. Subsections, Units) are never included in the
Expand Down
4 changes: 2 additions & 2 deletions src/openedx_content/applets/media/api.py
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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",
Expand Down
Loading
Loading