Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 17 additions & 17 deletions .annotation_safe_list.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,39 @@
# See https://code-annotations.readthedocs.io/en/latest/safelist.html for more information.
#
# fake_app_1.FakeModelName:
# ".. no_pii:": "This model has no PII"
# ".. no_pii:": This model has no PII
# fake_app_2.FakeModel2:
# ".. choice_annotation:": foo, bar, baz

admin.LogEntry:
".. no_pii:": "This model has no PII"
".. no_pii:": This model has no PII
auth.Group:
".. no_pii:": "This model has no PII"
".. no_pii:": This model has no PII
auth.Permission:
".. no_pii:": "This model has no PII"
".. no_pii:": This model has no PII
auth.User:
".. pii": "This model minimally contains a username, password, and email"
".. pii_types": "username, email_address, password"
".. pii_retirement": "consumer_api"
".. pii": This model minimally contains a username, password, and email
".. pii_types": username, email_address, password
".. pii_retirement": consumer_api
contenttypes.ContentType:
".. no_pii:": "This model has no PII"
".. no_pii:": This model has no PII
sessions.Session:
".. no_pii:": "This model has no PII"
".. no_pii:": This model has no PII
social_django.Association:
".. no_pii:": "This model has no PII"
".. no_pii:": This model has no PII
social_django.Code:
".. pii:": "Email address"
".. pii:": Email address
".. pii_types:": other
".. pii_retirement:": local_api
social_django.Nonce:
".. no_pii:": "This model has no PII"
".. no_pii:": This model has no PII
social_django.Partial:
".. no_pii:": "This model has no PII"
".. no_pii:": This model has no PII
social_django.UserSocialAuth:
".. no_pii:": "This model has no PII"
".. no_pii:": This model has no PII
waffle.Flag:
".. no_pii:": "This model has no PII"
".. no_pii:": This model has no PII
waffle.Sample:
".. no_pii:": "This model has no PII"
".. no_pii:": This model has no PII
waffle.Switch:
".. no_pii:": "This model has no PII"
".. no_pii:": This model has no PII
54 changes: 27 additions & 27 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
branches: [main]
pull_request:
branches:
- '**'
- '**'


jobs:
Expand All @@ -16,31 +16,31 @@ jobs:
matrix:
os: [ubuntu-latest]
python-version: [3.11, 3.12]
toxenv: [django42, django52, quality, docs, pii_check]
toxenv: [django52, quality, docs, pii_check]

steps:
- uses: actions/checkout@v3
- name: setup python
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}

- name: Install pip
run: pip install -r requirements/pip.txt

- name: Install Dependencies
run: pip install -r requirements/ci.txt

- name: Run Tests
env:
TOXENV: ${{ matrix.toxenv }}
run: tox

- name: Run coverage
if: matrix.python-version == '3.11' && matrix.toxenv == 'django42'
uses: codecov/codecov-action@v3
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
flags: unittests
fail_ci_if_error: true
- uses: actions/checkout@v3
- name: setup python
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}

- name: Install pip
run: pip install -r requirements/pip.txt

- name: Install Dependencies
run: pip install -r requirements/ci.txt

- name: Run Tests
env:
TOXENV: ${{ matrix.toxenv }}
run: tox

- name: Run coverage
if: matrix.python-version == '3.11' && matrix.toxenv == 'django52'
uses: codecov/codecov-action@v3
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
flags: unittests
fail_ci_if_error: true
17 changes: 0 additions & 17 deletions .github/workflows/lint.yml

This file was deleted.

44 changes: 22 additions & 22 deletions .pii_annotations.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,29 @@ annotations:
"pii_group":
- ".. pii:":
- ".. pii_types:":
choices:
- id # Unique identifier for the user which is shared across systems
- name # Used for any part of the user's name
- username
- password
- location # Used for any part of any type address or country stored
- phone_number # Used for phone or fax numbers
- email_address
- birth_date # Used for any part of a stored birth date
- ip # IP address
- external_service # Used for external service ids or links such as social media links or usernames, website links, etc.
- biography # Any type of free-form biography field
- gender
- sex
- image
- video
- other
choices:
- id # Unique identifier for the user which is shared across systems
- name # Used for any part of the user's name
- username
- password
- location # Used for any part of any type address or country stored
- phone_number # Used for phone or fax numbers
- email_address
- birth_date # Used for any part of a stored birth date
- ip # IP address
- external_service # Used for external service ids or links such as social media links or usernames, website links, etc.
- biography # Any type of free-form biography field
- gender
- sex
- image
- video
- other
- ".. pii_retirement:":
choices:
- retained # Intentionally kept for legal reasons
- local_api # An API exists in this repository for retiring this information
- consumer_api # The data's consumer must implement an API for retiring this information
- third_party # A third party API exists to retire this data
choices:
- retained # Intentionally kept for legal reasons
- local_api # An API exists in this repository for retiring this information
- consumer_api # The data's consumer must implement an API for retiring this information
- third_party # A third party API exists to retire this data
extensions:
python:
- py
4 changes: 2 additions & 2 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ sphinx:

# Set the version of python needed to build these docs.
build:
os: "ubuntu-22.04"
os: ubuntu-lts-latest
tools:
python: "3.8"
python: "3.11"

python:
install:
Expand Down
23 changes: 23 additions & 0 deletions .yamllint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
extends: default

ignore: |
.pytest_cache/
.ruff_cache/
.tox/
pii_report/
venv/
.venv/
rules:
indentation:
spaces: consistent
check-multi-line-strings: true
line-length: disable
document-start: disable
quoted-strings:
quote-type: any
required: only-when-needed
braces:
forbid: non-empty
level: warning
truthy:
check-keys: false
14 changes: 14 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,20 @@ Unreleased

*

0.4.0 - 2026-06-12
******************

Fixed
=====

* Mark course key admin widget as safe (Django 5.2 automatically escapes this code).
* Do not evaluate DB queries when building the docs.

Removed
=======

* Django 4.2 support.

0.3.5 - 2025-09-01
******************

Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ upgrade: ## update the requirements/*.txt files with the latest packages satisfy
sed '/^[dD]jango==/d' requirements/test.txt > requirements/test.tmp
mv requirements/test.tmp requirements/test.txt

quality: ## check coding style with pycodestyle and pylint
quality: ## check coding style with pycodestyle, pylint, ruff and yamllint
tox -e quality

pii_check: ## check for PII annotations on all Django models
Expand Down
16 changes: 10 additions & 6 deletions catalog-info.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@
apiVersion: backstage.io/v1alpha1
kind: ""
metadata:
name: 'learning-paths-plugin'
description: "Learning Paths plugin"
name: learning-paths-plugin
description: Learning Paths plugin
annotations:
# (Optional) Annotation keys and values can be whatever you want.
# We use it in Open edX repos to have a comma-separated list of GitHub user
# names that might be interested in changes to the architecture of this
# component.
openedx.org/arch-interest-groups: ""
spec:

# (Required) This can be a group(`group:<group_name>` or a user(`user:<github_username>`)
Expand All @@ -17,12 +21,12 @@ spec:
type: ''

# (Required) Acceptable Lifecycle Values: experimental, production, deprecated
lifecycle: 'experimental'
lifecycle: experimental

# (Optional) The value can be the name of any known component.
subcomponentOf: '<name_of_a_component>'
subcomponentOf: <name_of_a_component>

# (Optional) An array of different components or resources.
dependsOn:
- '<component_or_resource>'
- '<another_component_or_resource>'
- <component_or_resource>
- <another_component_or_resource>
4 changes: 2 additions & 2 deletions codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ coverage:
status:
project:
default:
enabled: yes
enabled: true
target: 85%
patch:
default:
enabled: yes
enabled: true
target: 90%

comment: false
20 changes: 18 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -518,8 +518,8 @@ def get_version(*file_paths):
intersphinx_mapping = {
"python": ("https://docs.python.org/3.11", None),
"django": (
"https://docs.djangoproject.com/en/4.2/",
"https://docs.djangoproject.com/en/4.2/_objects/",
"https://docs.djangoproject.com/en/5.2/",
"https://docs.djangoproject.com/en/5.2/_objects/",
),
"model_utils": ("https://django-model-utils.readthedocs.io/en/latest/", None),
}
Expand Down Expand Up @@ -550,7 +550,23 @@ def on_init(app): # pylint: disable=unused-argument
)


def skip_lazy_db_attributes(app, what, name, obj, skip, options): # pylint: disable=unused-argument
"""
Skip documenting attributes backed by a lazy database query.

Sphinx autodoc calls ``repr()`` on every documented attribute. For class attributes, such as a DRF
view's ``queryset = Model.objects.all()``, this forces the lazy QuerySet to hit the database, which fails
during the docs build because no tables exist. Their runtime value is not useful documentation anyway.
"""
from django.db.models import Manager, QuerySet # pylint: disable=import-outside-toplevel

if isinstance(obj, (QuerySet, Manager)):
return True
return skip


def setup(app):
"""Sphinx extension: run sphinx-apidoc."""
event = "builder-inited"
app.connect(event, on_init)
app.connect("autodoc-skip-member", skip_lazy_db_attributes)
2 changes: 1 addition & 1 deletion learning_paths/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
Learning Paths plugin.
"""

__version__ = "0.3.5"
__version__ = "0.4.0"
3 changes: 2 additions & 1 deletion learning_paths/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from django.db import transaction
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
from django_object_actions import DjangoObjectActions, action

Expand Down Expand Up @@ -62,7 +63,7 @@ def render(self, name, value, attrs=None, renderer=None):
data_list_id = f"datalist_{name}"
options = "\n".join(f'<option value="{choice}" />' for choice in self.choices)
datalist_html = f'<datalist id="{data_list_id}">\n{options}\n</datalist>'
return f"{text_input_html}\n{datalist_html}"
return mark_safe(f"{text_input_html}\n{datalist_html}")


class LearningPathStepForm(forms.ModelForm):
Expand Down
Loading
Loading