Skip to content

Conversation

@kdmccormick
Copy link
Member

@kdmccormick kdmccormick commented Feb 9, 2026

Context

This PR aligns on the new project structure which @ormsbee , @bradenmacdonald and I discussed. It follows on the work which Dave did here:

This involves several breaking changes, which we've deemed OK since the package is still v0.*. The accompanying openedx-platform PR which addresses all those breaking changes is here:

After we merge those PRs, the final step will be to rename the repo and PyPI package to openedx-core.

The new structure

src/  # all packages released under openedx-learning (soon to be "openedx-core")
  openedx_tagging/        # The Tagging djangoapp
  openedx_content/        # The Content djangoapp (formerly "authoring")
  openedx_django_lib/     # Generic Django utils (formely "openedx_learning.lib")
  openedx_core/           # Stub package, just so we have a place to declare `__version__`

New high-level applications will be added as peers of these packages. For example, we expect to have src/openedx_catalog and src/openedx_learning.

New capabilities which fit well into the existing application can be added as "applets" (ADR link). The goal is to have manageable number of well-separated django apps at the top level, internally organized into applets. The top-level apps are hard to refactor (due to migrations) but the internal applets are very easy to refactor.

importlinter is used to enforce boundaries between the djangoapps, as well as between their internal applets -- see .importliner config file.

BREAKING CHANGES

Here are all the changes which a consumer of this package's public APIs would see:

  • openedx_tagging.core.tagging.* --> openedx_tagging.*
  • openedx_learning.api.authoring --> openedx_content.api
  • openedx_learning.api.authoring_models --> openedx_content.models_api
  • openedx_learning.api.django.openedx_learning_apps_to_install --> openedx_content.settings_api.openedx_content_backcompat_apps_to_install
    • Additionally, the function's semantics have changed. Operators will need to explicitly add "openedx_content" to INSTALLED_APPS in addition to splatting the results of this function in.
  • openedx_learning.lib.* -> openedx_django_lib.*
  • openedx_learning.lib.cache --> removed. LRU caching didn't play well with rollbacks.
  • openedx_learning.lib.test_utils --> removed. It was just there to help us clear the LRU cache during tests.
  • openedx_learning.contrib.media_server --> removed
    • from Dave: "The original usage for media_server had to do with the fact that we're intentionally dumping things into a private media storage space that isn't publicly accessible. But in libraries, all the work is being done by get_component_version_asset in the content_libraries REST API. In the Django admin, I switched it to using base64 encoding, since performance isn't really a concern there"

@kdmccormick kdmccormick force-pushed the kdmccormick/root-packages branch 3 times, most recently from ad8d3bc to 03bd6d1 Compare February 11, 2026 16:36
@ormsbee
Copy link
Contributor

ormsbee commented Feb 11, 2026

Maybe openedx_core is just openedx_lib for now?

@bradenmacdonald
Copy link
Contributor

How does this compare to the similar version (like uv workspaces) where each app has its own dir and perhaps even its own pyproject.toml, like openedx_content/src, openedx_content/tests, openedx_content/pyproject.toml, but everything still shares a common virtualenv and dependency lockfile?

That seems cleaner to me, but perhaps it's not achievable without using uv and its sources and workspaces features.

@kdmccormick
Copy link
Member Author

kdmccormick commented Feb 11, 2026

@bradenmacdonald ooh, uv workspaes seems like exactly the pattern we want going forward.

Workspaces are intended to facilitate the development of multiple interconnected packages within a single repository. As a codebase grows in complexity, it can be helpful to split it into smaller, composable packages, each with their own dependencies and version constraints.
...
Workspaces are not suited for cases in which members have conflicting requirements, or desire a separate virtual environment for each member...

I think this new directory structure is compatible with an eventual switch to uv workspaces. I don't want to bite off switching to uv as part of this PR since so much of the Modular delivery work is waiting on it, but I'm supportive of ticketing it up as a future task.

@kdmccormick
Copy link
Member Author

openedx-platform PR (WIP): openedx/openedx-platform#38004

@kdmccormick
Copy link
Member Author

In Slack, Dave and I discussed what to do about openedx_learning.{lib,contrib}. The consensus was:

  • openedx_learning.contrib can be deleted since MediaServer is unused
  • openedx_learning.lib can be moved to openedx_django_lib for now. The testing and caching utils in there are deleted (unused), and the other utils may be moved into edx_django_utils later on.

@ormsbee
Copy link
Contributor

ormsbee commented Feb 11, 2026

I just realized that you haven't gotten around to removing media_server yet, which is fine. I'm just trying to take a first pass through even though it's in draft, to make sure I understand everything and can give a quicker turnaround when it is ready-for-review.

Comment on lines 13 to 17
Version 0.31.0 of openedx-core (nee openedx-learning) reorganized its installation profile
from many Django apps within `openedx_learning.apps.authoring` into a single `openedx_content`
Django app. For backwards compatibility, anything that installed this package prior to 0.31.0
should install the apps returned by this function, in addition to installing `openedx_content`
itself.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Folks will always need to install the backcompat apps, regardless of when they started using it. The first migration in openedx_content does state creation without database operations. Folks who start with a fresh install of openedx-platform release that points to 0.31.0 or later of this repo can skip the weird intermediate state where their platform models have foreign keys to the old apps, and just skip to directly making foreign keys to the openedx_content models from the beginning. But those old authoring models/tables are always created by the old models and transferred to openedx_content, regardless of which version you're starting at.

Copy link
Contributor

@ormsbee ormsbee Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, maybe not always. We can probably make a future squashed migration in openedx_content that skips the state transfer magic and just makes tables the normal way, and make more squashed migrations on the openedx-platform side to bridge into it. But as it stands right now, if you have a plugin, you'd need to include the backcompat apps in process when testing so those migrations would run, or openedx_content is going to complain that its dependency migrations aren't found.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But that transition would probably have to wait at least one release cycle, since putting that in Verawood would mess up people upgrading from Ulmo.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense -- I just linked to your ADR, which describes this all better than I can

Copy link
Contributor

@ormsbee ormsbee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did my first pass. Minor request around comment wording for openedx_content_backcompat_apps_to_install, and media_server removal comments. The tagging stuff looks fine to me, but I don't know if there are any weird search-related issues around moving the app around—it seems unlikely, but I mention it in case it rings any bells for @bradenmacdonald.

@kdmccormick kdmccormick force-pushed the kdmccormick/root-packages branch from 5bd3bf0 to 015bcd1 Compare February 12, 2026 20:03
@kdmccormick kdmccormick marked this pull request as ready for review February 12, 2026 22:02
Copy link
Member Author

@kdmccormick kdmccormick left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bradenmacdonald -- this is ready for review.

I haven't manually tested yet, but I'll do that in tandem with finishing the openedx-platform PR, which I just got a green build on.

Some miscellaneous notes ⬇️

uses: actions/setup-python@v6
with:
python-version: '3.11'
python-version: '3.12'
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not critical to this PR, but this brings import-linter's python version up to date with unit tests.


- name: Install Dependencies
run: pip install -r requirements/ci.txt
run: pip install -e . -r requirements/quality.txt
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor requirements rejigger:

  • ci.in / ci.txt now just installs tox, not import-linter. No need to install tox to run import-linter.
  • by adding quality.txt, we gain the ability to lint imports into openedx-learning's dependencies, if we ever want to do that. quality.txt also installs import-linter for us already.
  • with the new package structure, we need to add -e ., otherwise import-linter doesn't see our root source packages.

from openedx_learning.apps.openedx_content.applets.components import api as components_api
from openedx_learning.apps.openedx_content.applets.contents import api as contents_api
from openedx_learning.apps.openedx_content.applets.publishing import api as publishing_api
from openedx_content import api as content_api
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure where olx_importer belongs with this new packages structure, but I've opted not to worry about it for this PR.

Comment on lines +38 to +40
"openedx_tagging",
"openedx_content",
*openedx_content_backcompat_apps_to_install(),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than having a single openedx_core_apps_to_install function, I've opted to allow clients to choose which of our top-level apps (openedx_tagging, openedx_content, etc.) they'd like to install, letting them list those explicitly, and then just having the a helper function for the content backcompat apps.

My reasoning here is basically "explicit is better than implicit". If a dev is wondering how openedx_content is installed, they're gonna grep for "openedx_content", not for "openedx_core".

Comment on lines +86 to +87
./manage.py makemessages -l en -v1 -d django
./manage.py makemessages -l en -v1 -d djangojs
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NOTE: I need to confirm that this works. Will do before merging, or will make a follow-up ticket if it isn't critical to this PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was actually broken because manage.py wasn't marked executable.

I pushed a commit to fix that, but also pushed a commit to generally enable translations on this repo, which they currently aren't. #483

Comment on lines 13 to 17
Version 0.31.0 of openedx-core (nee openedx-learning) reorganized its installation profile
from many Django apps within `openedx_learning.apps.authoring` into a single `openedx_content`
Django app. For backwards compatibility, anything that installed this package prior to 0.31.0
should install the apps returned by this function, in addition to installing `openedx_content`
itself.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense -- I just linked to your ADR, which describes this all better than I can

@bradenmacdonald
Copy link
Contributor

The tagging stuff looks fine to me, but I don't know if there are any weird search-related issues around moving the app around—it seems unlikely, but I mention it in case it rings any bells for @bradenmacdonald.

Yeah, I don't think it should cause any problems.

@bradenmacdonald
Copy link
Contributor

The code looks great, @kdmccormick. I'm going to rebuild my devstack and see if it works.

@kdmccormick
Copy link
Member Author

kdmccormick commented Feb 13, 2026

Thanks @bradenmacdonald

I smoke tested with the sandbox on openedx/openedx-platform#38004, and the only issue I hit is that when I try to back up the library, instead of downloading a ZIP, my browser gets redirected to /media/user_tasks/2026/02/13/lib-kyle-1-2026-02-13-152329.zip (for lib:kyle:1) which 404s. Not sure if that's a bug in this PR, or an issue with the sandboxes. I'll dig in later today, but let me know whether you observe that too Braden.

@kdmccormick
Copy link
Member Author

Ah, it's an issue with all PR sandboxes right now, I Iet Kaustav know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants