Repository navigation
build: add an isolated_apps import-linter contract for openedx_catalog (#860) - #861
Conversation
openedx-platform's own import-linter config already treats openedx_catalog (and openedx_learning) as an isolated app, reachable from outside only through its api/models_api/data/tests modules, which is how a foreign-key import into openedx_catalog.models (instead of models_api) got caught on the platform's CI and not here: this repo's own .importlinter only layers top-level packages, it says nothing about which modules within a package may be reached from outside it. Adds an equivalent "isolated_apps" contract type, scoped to openedx_catalog only for now; extending it to openedx_content, openedx_learning, or openedx_tagging would surface pre-existing violations (confirmed by testing the broader scope and reverting), out of scope for this change. IsolatedAppsContract itself is ported verbatim from openedx-platform's openedx.testing.importlinter.isolated_apps_contract (this library can't depend on openedx-platform), with one change: self.isolated_apps and self.allowed_modules are copied through list() before iterating, working around a pylint false positive (E1133) caused by pylint not understanding that Contract._populate_fields() replaces these class-level Field descriptors with their parsed list values at the instance level. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Thanks for the pull request, @ufedaseyeuconsultant! This repository is currently maintained by Once you've gone through the following steps feel free to tag them in a comment and let them know that your changes are ready for engineering review. 🔘 Get product approvalIf you haven't already, check this list to see if your contribution needs to go through the product review process.
🔘 Provide contextTo help your reviewers and other members of the community understand the purpose and larger context of your changes, feel free to add as much of the following information to the PR description as you can:
🔘 Get a green buildIf one or more checks are failing, continue working on your changes until this is no longer the case and your build turns green. DetailsWhere can I find more information?If you'd like to get more details on all aspects of the review process for open source pull requests (OSPRs), check out the following resources: When can I expect my changes to be merged?Our goal is to get community contributions seen and reviewed as efficiently as possible. However, the amount of time that it takes to review and merge a PR can vary significantly based on factors such as:
💡 As a result it may take up to several weeks or months to complete a review and merge your PR. |
mgwozdz-unicon
left a comment
There was a problem hiding this comment.
This comment is a collaboration between Claude and me.
@ufedaseyeuconsultant Thanks, this does what #860 asks for. I ran lint-imports on this branch and all three contracts are kept, and reverting the criteria.py import to openedx_catalog.models breaks the new contract on that line, as your description shows. A few small changes before I approve, mostly trimming text so the copied file stays close to openedx-platform's original:
1. Module docstring in test_utils/isolated_apps_contract.py. Please drop the commit hash and the last sentence ("Kept dependency-free beyond import-linter itself..."). Nothing copies this file back to openedx-platform, so that sentence describes a process that doesn't exist. Something like:
An import-linter contract that flags imports of an isolated app's private modules.
Ported from openedx-platform's ``openedx.testing.importlinter.isolated_apps_contract``,
since this library can't depend on openedx-platform.
2. Method docstrings on check() and render_broken_contract(). Please remove these two. pylint passes without them, and leaving them out keeps the file closer to openedx-platform's copy.
3. Comment above the new contract in .importlinter. Please drop the clause starting ", which is what let a foreign-key import reach into openedx_catalog.models directly..." The history of how the bad import happened belongs in #853 and #860, not in the config. With that gone, the rest can be shorter too, for example:
# Mirrors openedx-platform's isolated-apps contract (see test_utils/isolated_apps_contract.py):
# code outside an isolated app may only import its public modules (api, models_api, data,
# tests). src_layering above only controls which top-level packages may depend on which.
Nit: the list() workaround in check(). The : list[str] annotations on the two list() lines don't do anything: mypy skips the body of check() because the method has no type hints, and pylint passes without them. I'd drop them and cut the three-line comment above them down to one line, e.g. # pylint can't tell import-linter replaces these Field descriptors with lists.
Nit: PR description. It says the file is ported verbatim with one deliberate deviation. Once 1 and 2 are done that will be accurate apart from the docstring, but it would help to say "verbatim apart from the module docstring and the list() workaround." Please also link #860 in the description so the PR is tied to its ticket.
Drops the commit hash and the "copied back and forth" sentence from the module docstring (nothing copies this file back to openedx-platform, so that process doesn't exist), removes the two method docstrings now that the file is closer to openedx-platform's original, and cuts the list() workaround's annotations and three-line comment down to one line (the annotations did nothing: mypy skips the untyped check() method's body, and pylint passes without them either way). Also shortens the comment above the new contract in .importlinter: drops the clause about how the bad import happened, since that history belongs in openedx#853 and openedx#860, not in the config. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
@mgwozdz-unicon Done |
ormsbee
left a comment
There was a problem hiding this comment.
FYI @kdmccormick, @bradenmacdonald
I'm merging this as a stopgap to keep us from breaking openedx-platform's build, but I realize that this redundancy isn't a long term solution. I'm not entirely sure where we should be putting this to keep consistency across repos.
|
@ormsbee @mgwozdz-unicon This looks good for now, thanks for merging it in. I think the long term solution would be to move the IsolatedAppsContract into edx-lint, and hard-coding it with a default list of |
|
Nice, thanks! I agree it would be nice to have this in edx-lint so it's reusable across repos. We should also fix those existing violations within this repo ASAP. |
Summary
Closes #860.
isolated_appsimport-linter contract, mirroring openedx-platform's own, so a private-module import intoopenedx_catalog(likefrom openedx_catalog.models import CourseRuninstead of.models_api) fails here, not only on the platform's CI. Follow-up to#853's review, deliberately split out as its own PR per your preference there.openedx_catalogonly for now. Extending it toopenedx_content,openedx_learning, oropenedx_taggingsurfaces pre-existing violations (confirmed by testing the broader scope locally and reverting), which is out of scope for this change; happy to open a separate follow-up for that if useful.IsolatedAppsContract(test_utils/isolated_apps_contract.py) is ported verbatim fromopenedx.testing.importlinter.isolated_apps_contractin openedx-platform apart from the module docstring (rewritten; nothing copies this file back to openedx-platform, so the docstring shouldn't imply that it does) and thelist()workaround incheck():self.isolated_apps/self.allowed_modulesare copied throughlist()before iterating, to work around a pylint false positive (E1133 not-an-iterable) caused by pylint not understanding thatContract._populate_fields()replaces these class-levelFielddescriptors with their parsed list values at the instance level. Triedtyping.castand an annotated local first; neither satisfied pylint,list()did, with no suppression directive needed.test_utils/, notsrc/, since it's a dev/CI-only tool and shouldn't ship in the installed package.The contract catches a real violation
Temporarily reverting
criteria.py's import back tofrom openedx_catalog.models import CourseRun(the pre-#853line) and runninglint-importson this branch:Reverted back to
.models_apiafterward; the branch is otherwise unchanged frommain.Test plan
lint-importsonmainplus this change — 3/3 contracts kept, 237 files analyzed (all ofsrc/; the top-leveltests/package isn't inroot_packagesso it's out of scope, same as today)lint-importswithcriteria.py's import reverted to the pre-#853line — 1 contract broken, naming exactly that line (see above)pytest tests/openedx_learning/applets/cbe/— 142 passedpylint/pycodestyle/isort/mypyclean ontest_utils/isolated_apps_contract.py🤖 Generated with Claude Code