From ab216aeb1dad4502532faf7c109a635bce121aa5 Mon Sep 17 00:00:00 2001 From: Brian Mesick Date: Thu, 29 Feb 2024 15:24:41 -0500 Subject: [PATCH] feat: Initial repository population --- .annotation_safe_list.yml | 41 ++ .coveragerc | 10 + .editorconfig | 100 ++++ .github/PULL_REQUEST_TEMPLATE.md | 10 + .github/workflows/ci.yml | 44 ++ .github/workflows/commitlint.yml | 10 + .github/workflows/pypi-publish.yml | 30 + .../workflows/upgrade-python-requirements.yml | 27 + .gitignore | 195 ++----- .pii_annotations.yml | 35 ++ .readthedocs.yaml | 27 + CHANGELOG.rst | 25 + MANIFEST.in | 6 + Makefile | 124 ++++ README.md | 2 - README.rst | 98 ++++ catalog-info.yaml | 24 + codecov.yml | 12 + docs/Makefile | 230 ++++++++ docs/_static/theme_overrides.css | 10 + docs/changelog.rst | 1 + docs/concepts/index.rst | 2 + docs/conf.py | 547 ++++++++++++++++++ docs/decisions.rst | 12 + docs/decisions/0001-purpose-of-this-repo.rst | 30 + docs/decisions/README.rst | 8 + docs/getting_started.rst | 18 + docs/how-tos/index.rst | 2 + docs/index.rst | 34 ++ docs/internationalization.rst | 51 ++ docs/make.bat | 281 +++++++++ docs/quickstarts/index.rst | 2 + docs/readme.rst | 1 + docs/references/index.rst | 2 + docs/testing.rst | 44 ++ manage.py | 29 + openedx.yaml | 23 + platform_plugin_aspects/__init__.py | 5 + platform_plugin_aspects/apps.py | 13 + .../conf/locale/config.yaml | 85 +++ platform_plugin_aspects/models.py | 3 + .../platform_plugin_aspects/base.html | 26 + platform_plugin_aspects/urls.py | 10 + pylintrc | 390 +++++++++++++ pylintrc_tweaks | 11 + requirements/base.in | 7 + requirements/base.txt | 20 + requirements/ci.in | 5 + requirements/ci.txt | 38 ++ requirements/constraints.txt | 12 + requirements/dev.in | 9 + requirements/dev.txt | 260 +++++++++ requirements/doc.in | 10 + requirements/doc.txt | 219 +++++++ requirements/pip-tools.in | 5 + requirements/pip-tools.txt | 33 ++ requirements/pip.in | 6 + requirements/pip.txt | 14 + requirements/private.readme | 15 + requirements/quality.in | 10 + requirements/quality.txt | 145 +++++ requirements/test.in | 8 + requirements/test.txt | 67 +++ setup.cfg | 10 + setup.py | 160 +++++ test_settings.py | 61 ++ test_utils/__init__.py | 10 + tests/test_models.py | 13 + tox.ini | 89 +++ 69 files changed, 3769 insertions(+), 147 deletions(-) create mode 100644 .annotation_safe_list.yml create mode 100644 .coveragerc create mode 100644 .editorconfig create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/commitlint.yml create mode 100644 .github/workflows/pypi-publish.yml create mode 100644 .github/workflows/upgrade-python-requirements.yml create mode 100644 .pii_annotations.yml create mode 100644 .readthedocs.yaml create mode 100644 CHANGELOG.rst create mode 100644 MANIFEST.in create mode 100644 Makefile delete mode 100644 README.md create mode 100644 README.rst create mode 100644 catalog-info.yaml create mode 100644 codecov.yml create mode 100644 docs/Makefile create mode 100644 docs/_static/theme_overrides.css create mode 100644 docs/changelog.rst create mode 100644 docs/concepts/index.rst create mode 100644 docs/conf.py create mode 100644 docs/decisions.rst create mode 100644 docs/decisions/0001-purpose-of-this-repo.rst create mode 100644 docs/decisions/README.rst create mode 100644 docs/getting_started.rst create mode 100644 docs/how-tos/index.rst create mode 100644 docs/index.rst create mode 100644 docs/internationalization.rst create mode 100644 docs/make.bat create mode 100644 docs/quickstarts/index.rst create mode 100644 docs/readme.rst create mode 100644 docs/references/index.rst create mode 100644 docs/testing.rst create mode 100644 manage.py create mode 100644 openedx.yaml create mode 100644 platform_plugin_aspects/__init__.py create mode 100644 platform_plugin_aspects/apps.py create mode 100644 platform_plugin_aspects/conf/locale/config.yaml create mode 100644 platform_plugin_aspects/models.py create mode 100644 platform_plugin_aspects/templates/platform_plugin_aspects/base.html create mode 100644 platform_plugin_aspects/urls.py create mode 100644 pylintrc create mode 100644 pylintrc_tweaks create mode 100644 requirements/base.in create mode 100644 requirements/base.txt create mode 100644 requirements/ci.in create mode 100644 requirements/ci.txt create mode 100644 requirements/constraints.txt create mode 100644 requirements/dev.in create mode 100644 requirements/dev.txt create mode 100644 requirements/doc.in create mode 100644 requirements/doc.txt create mode 100644 requirements/pip-tools.in create mode 100644 requirements/pip-tools.txt create mode 100644 requirements/pip.in create mode 100644 requirements/pip.txt create mode 100644 requirements/private.readme create mode 100644 requirements/quality.in create mode 100644 requirements/quality.txt create mode 100644 requirements/test.in create mode 100644 requirements/test.txt create mode 100644 setup.cfg create mode 100755 setup.py create mode 100644 test_settings.py create mode 100644 test_utils/__init__.py create mode 100644 tests/test_models.py create mode 100644 tox.ini diff --git a/.annotation_safe_list.yml b/.annotation_safe_list.yml new file mode 100644 index 0000000..62eaaa7 --- /dev/null +++ b/.annotation_safe_list.yml @@ -0,0 +1,41 @@ +# This is a Code Annotations automatically-generated Django model safelist file. +# These models must be annotated as follows in order to be counted in the coverage report. +# See https://code-annotations.readthedocs.io/en/latest/safelist.html for more information. +# +# fake_app_1.FakeModelName: +# ".. 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" +auth.Group: + ".. no_pii:": "This model has no PII" +auth.Permission: + ".. 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" +contenttypes.ContentType: + ".. no_pii:": "This model has no PII" +sessions.Session: + ".. no_pii:": "This model has no PII" +social_django.Association: + ".. no_pii:": "This model has no PII" +social_django.Code: + ".. pii:": "Email address" + ".. pii_types:": other + ".. pii_retirement:": local_api +social_django.Nonce: + ".. no_pii:": "This model has no PII" +social_django.Partial: + ".. no_pii:": "This model has no PII" +social_django.UserSocialAuth: + ".. no_pii:": "This model has no PII" +waffle.Flag: + ".. no_pii:": "This model has no PII" +waffle.Sample: + ".. no_pii:": "This model has no PII" +waffle.Switch: + ".. no_pii:": "This model has no PII" diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..2404b60 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,10 @@ +[run] +branch = True +data_file = .coverage +source=platform_plugin_aspects +omit = + test_settings.py + */migrations/* + *admin.py + */static/* + */templates/* diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..5cf5aed --- /dev/null +++ b/.editorconfig @@ -0,0 +1,100 @@ +# *************************** +# ** DO NOT EDIT THIS FILE ** +# *************************** +# +# This file was generated by edx-lint: https://github.com/openedx/edx-lint +# +# If you want to change this file, you have two choices, depending on whether +# you want to make a local change that applies only to this repo, or whether +# you want to make a central change that applies to all repos using edx-lint. +# +# Note: If your .editorconfig file is simply out-of-date relative to the latest +# .editorconfig in edx-lint, ensure you have the latest edx-lint installed +# and then follow the steps for a "LOCAL CHANGE". +# +# LOCAL CHANGE: +# +# 1. Edit the local .editorconfig_tweaks file to add changes just to this +# repo's file. +# +# 2. Run: +# +# $ edx_lint write .editorconfig +# +# 3. This will modify the local file. Submit a pull request to get it +# checked in so that others will benefit. +# +# +# CENTRAL CHANGE: +# +# 1. Edit the .editorconfig file in the edx-lint repo at +# https://github.com/openedx/edx-lint/blob/master/edx_lint/files/.editorconfig +# +# 2. install the updated version of edx-lint (in edx-lint): +# +# $ pip install . +# +# 3. Run (in edx-lint): +# +# $ edx_lint write .editorconfig +# +# 4. Make a new version of edx_lint, submit and review a pull request with the +# .editorconfig update, and after merging, update the edx-lint version and +# publish the new version. +# +# 5. In your local repo, install the newer version of edx-lint. +# +# 6. Run: +# +# $ edx_lint write .editorconfig +# +# 7. This will modify the local file. Submit a pull request to get it +# checked in so that others will benefit. +# +# +# +# +# +# STAY AWAY FROM THIS FILE! +# +# +# +# +# +# SERIOUSLY. +# +# ------------------------------ +# Generated by edx-lint version: 5.2.5 +# ------------------------------ +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +indent_style = space +indent_size = 4 +max_line_length = 120 +trim_trailing_whitespace = true + +[{Makefile, *.mk}] +indent_style = tab +indent_size = 8 + +[*.{yml,yaml,json}] +indent_size = 2 + +[*.js] +indent_size = 2 + +[*.diff] +trim_trailing_whitespace = false + +[.git/*] +trim_trailing_whitespace = false + +[COMMIT_EDITMSG] +max_line_length = 72 + +[*.rst] +max_line_length = 79 + +# f2f02689fced7a2e0c62c2f9803184114dc2ae4b diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..ed62972 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,10 @@ + +**Merge checklist:** +Check off if complete *or* not applicable: +- [ ] Version bumped +- [ ] Changelog record added +- [ ] Documentation updated (not only docstrings) +- [ ] Fixup commits are squashed away +- [ ] Unit tests added/updated +- [ ] Manual testing instructions provided +- [ ] Noted any: Concerns, dependencies, migration issues, deadlines, tickets diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..80cc1d5 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,44 @@ +name: Python CI + +on: + push: + branches: [main] + pull_request: + branches: + - '**' + + +jobs: + run_tests: + name: tests + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-20.04] + python-version: ['3.8'] + toxenv: [quality, docs, pii_check, django32, django40] + + 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.8' && matrix.toxenv == 'django32' + uses: codecov/codecov-action@v3 + with: + flags: unittests + fail_ci_if_error: true diff --git a/.github/workflows/commitlint.yml b/.github/workflows/commitlint.yml new file mode 100644 index 0000000..fec11d6 --- /dev/null +++ b/.github/workflows/commitlint.yml @@ -0,0 +1,10 @@ +# Run commitlint on the commit messages in a pull request. + +name: Lint Commit Messages + +on: + - pull_request + +jobs: + commitlint: + uses: openedx/.github/.github/workflows/commitlint.yml@master diff --git a/.github/workflows/pypi-publish.yml b/.github/workflows/pypi-publish.yml new file mode 100644 index 0000000..a22e9e6 --- /dev/null +++ b/.github/workflows/pypi-publish.yml @@ -0,0 +1,30 @@ +name: Publish package to PyPi + +on: + release: + types: [published] + +jobs: + + push: + runs-on: ubuntu-20.04 + + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: setup python + uses: actions/setup-python@v2 + with: + python-version: 3.8 + + - name: Install pip + run: pip install -r requirements/pip.txt + + - name: Build package + run: python setup.py sdist bdist_wheel + + - name: Publish to PyPi + uses: pypa/gh-action-pypi-publish@master + with: + user: __token__ + password: ${{ secrets.PYPI_UPLOAD_TOKEN }} diff --git a/.github/workflows/upgrade-python-requirements.yml b/.github/workflows/upgrade-python-requirements.yml new file mode 100644 index 0000000..293fcc9 --- /dev/null +++ b/.github/workflows/upgrade-python-requirements.yml @@ -0,0 +1,27 @@ +name: Upgrade Python Requirements + +on: + schedule: + - cron: "0 0 * * 1" + workflow_dispatch: + inputs: + branch: + description: "Target branch against which to create requirements PR" + required: true + default: 'main' + +jobs: + call-upgrade-python-requirements-workflow: + uses: openedx/.github/.github/workflows/upgrade-python-requirements.yml@master + with: + branch: ${{ github.event.inputs.branch || 'main' }} + # optional parameters below; fill in if you'd like github or email notifications + # user_reviewers: "" + # team_reviewers: "" + # email_address: "" + # send_success_notification: false + secrets: + requirements_bot_github_token: ${{ secrets.REQUIREMENTS_BOT_GITHUB_TOKEN }} + requirements_bot_github_email: ${{ secrets.REQUIREMENTS_BOT_GITHUB_EMAIL }} + edx_smtp_username: ${{ secrets.EDX_SMTP_USERNAME }} + edx_smtp_password: ${{ secrets.EDX_SMTP_PASSWORD }} diff --git a/.gitignore b/.gitignore index 68bc17f..6fb97d1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,160 +1,65 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ *.py[cod] -*$py.class +__pycache__ +.pytest_cache # C extensions *.so -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ -*.egg-info/ -.installed.cfg +# Packages *.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec +*.egg-info +/dist +/build +/eggs +/parts +/bin +/var +/sdist +/develop-eggs +/.installed.cfg +/lib +/lib64 # Installer logs pip-log.txt -pip-delete-this-directory.txt # Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ +.cache/ +.pytest_cache/ .coverage .coverage.* -.cache -nosetests.xml +.tox coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ -cover/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -#pdm.lock -# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it -# in version control. -# https://pdm.fming.dev/#use-with-ide -.pdm.toml - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ - -# Cython debug symbols -cython_debug/ +htmlcov/ -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ +# Virtual environments +/venv/ +/venv-*/ +/.venv/ +/.venv-*/ + +# The Silver Searcher +.agignore + +# OS X artifacts +*.DS_Store + +# Logging +log/ +logs/ +chromedriver.log +ghostdriver.log + +# Complexity +output/*.html +output/*/index.html + +# Sphinx +docs/_build +docs/modules.rst +docs/platform_plugin_aspects.rst +docs/platform_plugin_aspects.*.rst + +# Private requirements +requirements/private.in +requirements/private.txt diff --git a/.pii_annotations.yml b/.pii_annotations.yml new file mode 100644 index 0000000..7da8f3c --- /dev/null +++ b/.pii_annotations.yml @@ -0,0 +1,35 @@ +source_path: ./ +report_path: pii_report +safelist_path: .annotation_safe_list.yml +coverage_target: 100.0 +annotations: + ".. no_pii:": + "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 + - ".. 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 +extensions: + python: + - py diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..ce8bde2 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,27 @@ +# .readthedocs.yml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: docs/conf.py + fail_on_warning: true + +# Set the version of python needed to build these docs. +build: + os: "ubuntu-22.04" + tools: + python: "3.8" + +python: + install: + - requirements: requirements/doc.txt + + # This will pip install this repo into the python environment + # if you are using this in a repo that is not pip installable + # then you should remove the following two lines. + - method: pip + path: . diff --git a/CHANGELOG.rst b/CHANGELOG.rst new file mode 100644 index 0000000..059152e --- /dev/null +++ b/CHANGELOG.rst @@ -0,0 +1,25 @@ +Change Log +########## + +.. + All enhancements and patches to platform_plugin_aspects will be documented + in this file. It adheres to the structure of https://keepachangelog.com/ , + but in reStructuredText instead of Markdown (for ease of incorporation into + Sphinx documentation and the PyPI description). + + This project adheres to Semantic Versioning (https://semver.org/). + +.. There should always be an "Unreleased" section for changes pending release. + +Unreleased +********** + +* + +0.1.0 – 2024-02-29 +********************************************** + +Added +===== + +* First release on PyPI. diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..8b45eee --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,6 @@ +include CHANGELOG.rst +include LICENSE.txt +include README.rst +include requirements/base.in +include requirements/constraints.txt +recursive-include platform_plugin_aspects *.html *.png *.gif *.js *.css *.jpg *.jpeg *.svg diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..08ada5f --- /dev/null +++ b/Makefile @@ -0,0 +1,124 @@ +.PHONY: clean clean_tox compile_translations coverage diff_cover docs dummy_translations \ + extract_translations fake_translations help pii_check pull_translations push_translations \ + quality requirements selfcheck test test-all upgrade validate install_transifex_client + +.DEFAULT_GOAL := help + +# For opening files in a browser. Use like: $(BROWSER)relative/path/to/file.html +BROWSER := python -m webbrowser file://$(CURDIR)/ + +help: ## display this help message + @echo "Please use \`make ' where is one of" + @awk -F ':.*?## ' '/^[a-zA-Z]/ && NF==2 {printf "\033[36m %-25s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) | sort + +clean: ## remove generated byte code, coverage reports, and build artifacts + find . -name '__pycache__' -exec rm -rf {} + + find . -name '*.pyc' -exec rm -f {} + + find . -name '*.pyo' -exec rm -f {} + + find . -name '*~' -exec rm -f {} + + coverage erase + rm -fr build/ + rm -fr dist/ + rm -fr *.egg-info + +clean_tox: ## clear tox requirements cache + rm -fr .tox + +coverage: clean ## generate and view HTML coverage report + pytest --cov-report html + $(BROWSER)htmlcov/index.html + +docs: ## generate Sphinx HTML documentation, including API docs + tox -e docs + $(BROWSER)docs/_build/html/index.html + +# Define PIP_COMPILE_OPTS=-v to get more information during make upgrade. +PIP_COMPILE = pip-compile --upgrade $(PIP_COMPILE_OPTS) + +upgrade: export CUSTOM_COMPILE_COMMAND=make upgrade +upgrade: ## update the requirements/*.txt files with the latest packages satisfying requirements/*.in + pip install -qr requirements/pip-tools.txt + # Make sure to compile files after any other files they include! + $(PIP_COMPILE) --allow-unsafe -o requirements/pip.txt requirements/pip.in + $(PIP_COMPILE) -o requirements/pip-tools.txt requirements/pip-tools.in + pip install -qr requirements/pip.txt + pip install -qr requirements/pip-tools.txt + $(PIP_COMPILE) -o requirements/base.txt requirements/base.in + $(PIP_COMPILE) -o requirements/test.txt requirements/test.in + $(PIP_COMPILE) -o requirements/doc.txt requirements/doc.in + $(PIP_COMPILE) -o requirements/quality.txt requirements/quality.in + $(PIP_COMPILE) -o requirements/ci.txt requirements/ci.in + $(PIP_COMPILE) -o requirements/dev.txt requirements/dev.in + # Let tox control the Django version for tests + 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 + tox -e quality + +pii_check: ## check for PII annotations on all Django models + tox -e pii_check + +piptools: ## install pinned version of pip-compile and pip-sync + pip install -r requirements/pip.txt + pip install -r requirements/pip-tools.txt + +requirements: clean_tox piptools ## install development environment requirements + pip-sync -q requirements/dev.txt requirements/private.* + +test: clean ## run tests in the current virtualenv + pytest + +diff_cover: test ## find diff lines that need test coverage + diff-cover coverage.xml + +test-all: quality pii_check ## run tests on every supported Python/Django combination + tox + tox -e docs + +validate: quality pii_check test ## run tests and quality checks + +selfcheck: ## check that the Makefile is well-formed + @echo "The Makefile is well-formed." + +## Localization targets + +extract_translations: ## extract strings to be translated, outputting .mo files + rm -rf docs/_build + cd platform_plugin_aspects && i18n_tool extract --no-segment + +compile_translations: ## compile translation files, outputting .po files for each supported language + cd platform_plugin_aspects && i18n_tool generate + +detect_changed_source_translations: + cd platform_plugin_aspects && i18n_tool changed + +ifeq ($(OPENEDX_ATLAS_PULL),) +pull_translations: ## Pull translations from Transifex + tx pull -t -a -f --mode reviewed --minimum-perc=1 +else +# Experimental: OEP-58 Pulls translations using atlas +pull_translations: + find platform_plugin_aspects/conf/locale -mindepth 1 -maxdepth 1 -type d -exec rm -r {} \; + atlas pull $(OPENEDX_ATLAS_ARGS) translations/platform-plugin-aspects/platform_plugin_aspects/conf/locale:platform_plugin_aspects/conf/locale + python manage.py compilemessages + + @echo "Translations have been pulled via Atlas and compiled." +endif + +push_translations: ## push source translation files (.po) from Transifex + tx push -s + +dummy_translations: ## generate dummy translation (.po) files + cd platform_plugin_aspects && i18n_tool dummy + +build_dummy_translations: extract_translations dummy_translations compile_translations ## generate and compile dummy translation files + +validate_translations: build_dummy_translations detect_changed_source_translations ## validate translations + +install_transifex_client: ## Install the Transifex client + # Instaling client will skip CHANGELOG and LICENSE files from git changes + # so remind the user to commit the change first before installing client. + git diff -s --exit-code HEAD || { echo "Please commit changes first."; exit 1; } + curl -o- https://raw.githubusercontent.com/transifex/cli/master/install.sh | bash + git checkout -- LICENSE README.md ## overwritten by Transifex installer diff --git a/README.md b/README.md deleted file mode 100644 index 9331fcc..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# platform-plugin-aspects -Aspects plugins for the Open edX LMS and Studio diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..4f9b2f7 --- /dev/null +++ b/README.rst @@ -0,0 +1,98 @@ +Platform Plugin Aspects +####################### + +Purpose +******* + +This repository holds various Aspects related plugins for edx-platform. + + +Getting Started with Development +******************************** + +Please see the Open edX documentation for `guidance on Python development `_ in this repo. + +Deploying +********* + +TODO: How can a new user go about deploying this component? Is it just a few +commands? Is there a larger how-to that should be linked here? + +PLACEHOLDER: For details on how to deploy this component, see the `deployment how-to`_ + +.. _deployment how-to: https://docs.openedx.org/projects/platform-plugin-aspects/how-tos/how-to-deploy-this-component.html + +Getting Help +************ + +Documentation +============= + +PLACEHOLDER: Start by going through `the documentation`_. If you need more help see below. + +.. _the documentation: https://docs.openedx.org/projects/platform-plugin-aspects + +(TODO: `Set up documentation `_) + +More Help +========= + +If you're having trouble, we have discussion forums at +https://discuss.openedx.org where you can connect with others in the +community. + +Our real-time conversations are on Slack. You can request a `Slack +invitation`_, then join our `community Slack workspace`_. + +For anything non-trivial, the best path is to open an issue in this +repository with as many details about the issue you are facing as you +can provide. + +https://github.com/openedx/platform-plugin-aspects/issues + +For more information about these options, see the `Getting Help `__ page. + +.. _Slack invitation: https://openedx.org/slack +.. _community Slack workspace: https://openedx.slack.com/ + +License +******* + +The code in this repository is licensed under the AGPL 3.0 unless +otherwise noted. + +Please see `LICENSE.txt `_ for details. + +Contributing +************ + +Contributions are very welcome. +Please read `How To Contribute `_ for details. + +This project is currently accepting all types of contributions, bug fixes, +security fixes, maintenance work, or new features. However, please make sure +to have a discussion about your new feature idea with the maintainers prior to +beginning development to maximize the chances of your change being accepted. +You can start a conversation by creating a new issue on this repo summarizing +your idea. + +The Open edX Code of Conduct +**************************** + +All community members are expected to follow the `Open edX Code of Conduct`_. + +.. _Open edX Code of Conduct: https://openedx.org/code-of-conduct/ + +People +****** + +The assigned maintainers for this component and other project details may be +found in `Backstage`_. Backstage pulls this data from the ``catalog-info.yaml`` +file in this repo. + +.. _Backstage: https://backstage.openedx.org/catalog/default/component/platform-plugin-aspects + +Reporting Security Issues +************************* + +Please do not report security issues in public. Please email security@openedx.org. diff --git a/catalog-info.yaml b/catalog-info.yaml new file mode 100644 index 0000000..da0ad34 --- /dev/null +++ b/catalog-info.yaml @@ -0,0 +1,24 @@ +# This file records information about this repo. Its use is described in OEP-55: +# https://open-edx-proposals.readthedocs.io/en/latest/processes/oep-0055-proc-project-maintainers.html + +apiVersion: backstage.io/v1alpha1 +kind: "Component" +metadata: + name: 'platform-plugin-aspects' + description: "Aspects plugins for edx-platform" + 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:` or a user(`user:`) + owner: "bmtcril" + + # (Required) Acceptable Type Values: service, website, library + type: 'library' + + # (Required) Acceptable Lifecycle Values: experimental, production, deprecated + lifecycle: 'experimental' diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..4da4768 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,12 @@ +coverage: + status: + project: + default: + enabled: yes + target: auto + patch: + default: + enabled: yes + target: 100% + +comment: false diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..47c409f --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,230 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from https://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " epub3 to make an epub3" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + @echo " dummy to check syntax errors of document sources" + +.PHONY: clean +clean: + rm -rf $(BUILDDIR)/* + +.PHONY: html +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +.PHONY: dirhtml +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +.PHONY: singlehtml +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +.PHONY: pickle +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +.PHONY: json +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +.PHONY: htmlhelp +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +.PHONY: qthelp +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/platform-plugin-aspects.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/platform-plugin-aspects.qhc" + +.PHONY: applehelp +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +.PHONY: devhelp +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/platform-plugin-aspects" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/platform-plugin-aspects" + @echo "# devhelp" + +.PHONY: epub +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +.PHONY: epub3 +epub3: + $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 + @echo + @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." + +.PHONY: latex +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +.PHONY: latexpdf +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: latexpdfja +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: text +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +.PHONY: man +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +.PHONY: texinfo +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +.PHONY: info +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +.PHONY: gettext +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +.PHONY: changes +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +.PHONY: linkcheck +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +.PHONY: doctest +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +.PHONY: coverage +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +.PHONY: xml +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +.PHONY: pseudoxml +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." + +.PHONY: dummy +dummy: + $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy + @echo + @echo "Build finished. Dummy builder generates no files." diff --git a/docs/_static/theme_overrides.css b/docs/_static/theme_overrides.css new file mode 100644 index 0000000..aad8245 --- /dev/null +++ b/docs/_static/theme_overrides.css @@ -0,0 +1,10 @@ +/* override table width restrictions */ +.wy-table-responsive table td, .wy-table-responsive table th { + /* !important prevents the common CSS stylesheets from + overriding this as on RTD they are loaded after this stylesheet */ + white-space: normal !important; +} + +.wy-table-responsive { + overflow: visible !important; +} diff --git a/docs/changelog.rst b/docs/changelog.rst new file mode 100644 index 0000000..565b052 --- /dev/null +++ b/docs/changelog.rst @@ -0,0 +1 @@ +.. include:: ../CHANGELOG.rst diff --git a/docs/concepts/index.rst b/docs/concepts/index.rst new file mode 100644 index 0000000..8a2b4bd --- /dev/null +++ b/docs/concepts/index.rst @@ -0,0 +1,2 @@ +Concepts +######## diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..caf4d87 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,547 @@ +# pylint: disable=invalid-name +""" +platform-plugin-aspects documentation build configuration file. + +This file is execfile()d with the current directory set to its +containing dir. + +Note that not all possible configuration values are present in this +autogenerated file. + +All configuration values have a default; values that are commented out +serve to show the default. +""" +import os +import re +import sys +from datetime import datetime +from subprocess import check_call + +from django import setup as django_setup + + +def get_version(*file_paths): + """ + Extract the version string from the file. + + Input: + - file_paths: relative path fragments to file with + version string + """ + filename = os.path.join(os.path.dirname(__file__), *file_paths) + version_file = open(filename, encoding="utf8").read() + version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", version_file, re.M) + if version_match: + return version_match.group(1) + raise RuntimeError('Unable to find version string.') + + +REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.append(REPO_ROOT) + +VERSION = get_version('../platform_plugin_aspects', '__init__.py') +# Configure Django for autodoc usage +os.environ['DJANGO_SETTINGS_MODULE'] = 'test_settings' +django_setup() + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.doctest', + 'sphinx.ext.intersphinx', + 'sphinx.ext.ifconfig', + 'sphinx.ext.napoleon' +] + +# A list of warning types to suppress arbitrary warning messages. +suppress_warnings = [ + 'image.nonlocal_uri', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +# +# source_encoding = 'utf-8-sig' + +# The top level toctree document. +top_level_doc = 'index' + +# General information about the project. +project = 'platform-plugin-aspects' +copyright = f'{datetime.now().year}, Axim Collaborative, Inc.' # pylint: disable=redefined-builtin +author = 'Axim Collaborative, Inc.' +project_title = 'platform-plugin-aspects' +documentation_title = f"{project_title}" + +# Set display_github to False if you don't want "edit on Github" button +html_context = { + "display_github": True, # Integrate GitHub + "github_user": "edx", # Username + "github_repo": 'platform-plugin-aspects', # Repo name + "github_version": "main", # Version + "conf_py_path": "/docs/", # Path in the checkout to the docs root +} + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = VERSION +# The full version, including alpha/beta/rc tags. +release = VERSION + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = 'en' + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# +# today = '' +# +# Else, today_fmt is used as the format for a strftime call. +# +# today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = [ + '_build', + 'Thumbs.db', + '.DS_Store', + # This file is intended as a guide for developers browsing the source tree, + # not to be rendered into the output docs. + 'decisions/README.rst', +] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +# +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +# +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# +# add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +# keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. + +html_theme = 'sphinx_book_theme' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +html_theme_options = { + "repository_url": "https://github.com/openedx/platform-plugin-aspects", + "repository_branch": 'main', + "path_to_docs": "docs/", + "home_page_in_toc": True, + "use_repository_button": True, + "use_issues_button": True, + "use_edit_page_button": True, + # Please don't change unless you know what you're doing. + "extra_footer": """ + + Creative Commons License + +
+ These works by + Axim Collaborative, Inc + are licensed under a + Creative Commons Attribution-ShareAlike 4.0 International License. + """ +} + +# Add any paths that contain custom themes here, relative to this directory. +# html_theme_path = [] + +# The name for this set of Sphinx documents. +# " v documentation" by default. +# +# html_title = 'platform-plugin-aspects v0.1.0' + +# A shorter title for the navigation bar. Default is the same as html_title. +# +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# +html_logo = "https://logos.openedx.org/open-edx-logo-color.png" + +# The name of an image file (relative to this directory) to use as a favicon +# of the docs. This file should be a Windows icon file (.ico) being 16x16 +# or 32x32 +# pixels large. +# +html_favicon = "https://logos.openedx.org/open-edx-favicon.ico" + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +# +# html_extra_path = [] + +# If not None, a 'Last updated on:' timestamp is inserted at every page +# bottom, using the given strftime format. +# The empty string is equivalent to '%b %d, %Y'. +# +# html_last_updated_fmt = None + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +# +# html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +# +# html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# +# html_additional_pages = {} + +# If false, no module index is generated. +# +# html_domain_indices = True + +# If false, no index is generated. +# +# html_use_index = True + +# If true, the index is split into individual pages for each letter. +# +# html_split_index = False + +# If true, links to the reST sources are added to the pages. +# +# html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +# +# html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# +# html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr', 'zh' +# +# html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# 'ja' uses this config value. +# 'zh' user can custom change `jieba` dictionary path. +# +# html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +# +# html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = f'{project}doc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_target = f'{project}.tex' +latex_documents = [ + (top_level_doc, latex_target, documentation_title, + author, 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# +# latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +# +# latex_use_parts = False + +# If true, show page references after internal links. +# +# latex_show_pagerefs = False + +# If true, show URL addresses after external links. +# +# latex_show_urls = False + +# Documents to append as an appendix to all manuals. +# +# latex_appendices = [] + +# It false, will not define \strong, \code, itleref, \crossref ... but only +# \sphinxstrong, ..., \sphinxtitleref, ... To help avoid clash with user added +# packages. +# +# latex_keep_old_macro_names = True + +# If false, no module index is generated. +# +# latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (top_level_doc, project_title, documentation_title, + [author], 1) +] + +# If true, show URL addresses after external links. +# +# man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (top_level_doc, project_title, documentation_title, + author, project_title, 'Aspects plugins for edx-platform', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +# +# texinfo_appendices = [] + +# If false, no module index is generated. +# +# texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# +# texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +# +# texinfo_no_detailmenu = False + + +# -- Options for Epub output ---------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project +epub_author = author +epub_publisher = author +epub_copyright = copyright + +# The basename for the epub file. It defaults to the project name. +# epub_basename = project + +# The HTML theme for the epub output. Since the default themes are not +# optimized for small screen space, using the same theme for HTML and epub +# output is usually not wise. This defaults to 'epub', a theme designed to save +# visual space. +# +# epub_theme = 'epub' + +# The language of the text. It defaults to the language option +# or 'en' if the language is not set. +# +# epub_language = '' + +# The scheme of the identifier. Typical schemes are ISBN or URL. +# epub_scheme = '' + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +# +# epub_identifier = '' + +# A unique identification for the text. +# +# epub_uid = '' + +# A tuple containing the cover image and cover page html template filenames. +# +# epub_cover = () + +# A sequence of (type, uri, title) tuples for the guide element of content.opf. +# +# epub_guide = () + +# HTML files that should be inserted before the pages created by sphinx. +# The format is a list of tuples containing the path and title. +# +# epub_pre_files = [] + +# HTML files that should be inserted after the pages created by sphinx. +# The format is a list of tuples containing the path and title. +# +# epub_post_files = [] + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] + +# The depth of the table of contents in toc.ncx. +# +# epub_tocdepth = 3 + +# Allow duplicate toc entries. +# +# epub_tocdup = True + +# Choose between 'default' and 'includehidden'. +# +# epub_tocscope = 'default' + +# Fix unsupported image types using the Pillow. +# +# epub_fix_images = False + +# Scale large images. +# +# epub_max_image_width = 0 + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# +# epub_show_urls = 'inline' + +# If false, no index is generated. +# +# epub_use_index = True + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = { + 'python': ('https://docs.python.org/3.8', None), + 'django': ('https://docs.djangoproject.com/en/3.2/', 'https://docs.djangoproject.com/en/3.2/_objects/'), + 'model_utils': ('https://django-model-utils.readthedocs.io/en/latest/', None), +} + + +def on_init(app): # pylint: disable=unused-argument + """ + Run sphinx-apidoc after Sphinx initialization. + + Read the Docs won't run tox or custom shell commands, so we need this to + avoid checking in the generated reStructuredText files. + """ + docs_path = os.path.abspath(os.path.dirname(__file__)) + root_path = os.path.abspath(os.path.join(docs_path, '..')) + apidoc_path = 'sphinx-apidoc' + if hasattr(sys, 'real_prefix'): # Check to see if we are in a virtualenv + # If we are, assemble the path manually + bin_path = os.path.abspath(os.path.join(sys.prefix, 'bin')) + apidoc_path = os.path.join(bin_path, apidoc_path) + check_call([apidoc_path, '-o', docs_path, os.path.join(root_path, 'platform_plugin_aspects'), + os.path.join(root_path, 'platform_plugin_aspects/migrations')]) + + +def setup(app): + """Sphinx extension: run sphinx-apidoc.""" + event = 'builder-inited' + app.connect(event, on_init) diff --git a/docs/decisions.rst b/docs/decisions.rst new file mode 100644 index 0000000..a21903c --- /dev/null +++ b/docs/decisions.rst @@ -0,0 +1,12 @@ +Decisions +######### + +The following `ADRs` are a record of all decisions made as a part of developing this library. + +.. _ADRs: https://open-edx-proposals.readthedocs.io/en/latest/oep-0019-bp-developer-documentation.html#adrs + +.. toctree:: + :maxdepth: 1 + :glob: + + decisions/* diff --git a/docs/decisions/0001-purpose-of-this-repo.rst b/docs/decisions/0001-purpose-of-this-repo.rst new file mode 100644 index 0000000..c03c139 --- /dev/null +++ b/docs/decisions/0001-purpose-of-this-repo.rst @@ -0,0 +1,30 @@ +0001 Purpose of This Repo +######################### + +Status +****** + +**Accepted** + +Context +******* + +This repository holds Aspects-related plugins for the Open edX LMS and Studio. It will likely supersede some other repositories such as openedx-event-sink-clickhouse and gather them into a single repository for maintainability. + +Decision +******** + +We will create a repository to hold all LMS / Studio plugins in one place, with settings or feature flags to enable the different specific features. + +Consequences +************ + +* This repository is created. + +Rejected Alternatives +********************* + +Currently licensing issues prevent us from combining this with openedx-aspects, however we may choose to do that in the future. + +.. _Documenting Architecture Decisions: https://cognitect.com/blog/2011/11/15/documenting-architecture-decisions +.. _OEP-19 on ADRs: https://open-edx-proposals.readthedocs.io/en/latest/best-practices/oep-0019-bp-developer-documentation.html#adrs diff --git a/docs/decisions/README.rst b/docs/decisions/README.rst new file mode 100644 index 0000000..612ad3b --- /dev/null +++ b/docs/decisions/README.rst @@ -0,0 +1,8 @@ +This directory is a historical record on the architectural decisions we make with this repository as it evolves over time. + +It uses Architecture Decision Records, as described by Michael Nygard in `Documenting Architecture Decisions`_. + +For more information, see `OEP-19's section on ADRs`_. + +.. _Documenting Architecture Decisions: https://cognitect.com/blog/2011/11/15/documenting-architecture-decisions +.. _OEP-19's section on ADRs: https://open-edx-proposals.readthedocs.io/en/latest/best-practices/oep-0019-bp-developer-documentation.html#adrs diff --git a/docs/getting_started.rst b/docs/getting_started.rst new file mode 100644 index 0000000..cec5418 --- /dev/null +++ b/docs/getting_started.rst @@ -0,0 +1,18 @@ +Getting Started +############### + +If you have not already done so, create/activate a `virtualenv`_. Unless otherwise stated, assume all terminal code +below is executed within the virtualenv. + +.. _virtualenv: https://virtualenvwrapper.readthedocs.org/en/latest/ + + +Install dependencies +******************** +Dependencies can be installed via the command below. + +.. code-block:: bash + + $ make requirements + + diff --git a/docs/how-tos/index.rst b/docs/how-tos/index.rst new file mode 100644 index 0000000..5147f80 --- /dev/null +++ b/docs/how-tos/index.rst @@ -0,0 +1,2 @@ +How-tos +####### diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..a0d9b42 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,34 @@ +.. platform-plugin-aspects documentation top level file, created by + sphinx-quickstart on Thu Feb 29 15:03:11 2024. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +platform-plugin-aspects +======================= + +Aspects plugins for edx-platform + +Contents: + +.. toctree:: + :maxdepth: 2 + + readme + getting_started + quickstarts/index + concepts/index + how-tos/index + testing + internationalization + modules + changelog + decisions + references/index + + +Indices and tables +################## + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/internationalization.rst b/docs/internationalization.rst new file mode 100644 index 0000000..9b25877 --- /dev/null +++ b/docs/internationalization.rst @@ -0,0 +1,51 @@ +.. _chapter-i18n: + +Internationalization +#################### +All user-facing text content should be marked for translation. Even if this application is only run in English, our +open source users may choose to use another language. Marking content for translation ensures our users have +this choice. + +Follow the `internationalization coding guidelines`_ in the edX Developer's Guide when developing new features. + +.. _internationalization coding guidelines: https://edx.readthedocs.org/projects/edx-developer-guide/en/latest/internationalization/i18n.html + +Updating Translations +********************* +This project uses `Transifex`_ to translate content. After new features are developed the translation source files +should be pushed to Transifex. Our translation community will translate the content, after which we can retrieve the +translations. + +.. _Transifex: https://www.transifex.com/ + +Pushing source translation files to Transifex requires access to the edx-platform. Request access from the Open Source +Team if you will be pushing translation files. You should also `configure the Transifex client`_ if you have not done so +already. + +.. _configure the Transifex client: https://docs.transifex.com/client/config/ + +The `make` targets listed below can be used to push or pull translations. + +.. list-table:: + :widths: 25 75 + :header-rows: 1 + + * - Target + - Description + * - pull_translations + - Pull translations from Transifex + * - push_translations + - Push source translation files to Transifex + +Fake Translations +***************** +As you develop features it may be helpful to know which strings have been marked for translation, and which are not. +Use the `fake_translations` make target for this purpose. This target will extract all strings marked for translation, +generate fake translations in the Esperanto (eo) language directory, and compile the translations. + +You can trigger the display of the translations by setting your browser's language to Esperanto (eo), and navigating to +a page on the site. Instead of plain English strings, you should see specially-accented English strings that look +like this: + + Thé Fütüré øf Ønlïné Édüçätïøn Ⱡσяєм ι# Før änýøné, änýwhéré, änýtïmé Ⱡσяєм # + diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..292b698 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,281 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +set I18NSPHINXOPTS=%SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. epub3 to make an epub3 + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. xml to make Docutils-native XML files + echo. pseudoxml to make pseudoxml-XML files for display purposes + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + echo. coverage to run coverage check of the documentation if enabled + echo. dummy to check syntax errors of document sources + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + + +REM Check if sphinx-build is available and fallback to Python version if any +%SPHINXBUILD% 1>NUL 2>NUL +if errorlevel 9009 goto sphinx_python +goto sphinx_ok + +:sphinx_python + +set SPHINXBUILD=python -m sphinx.__init__ +%SPHINXBUILD% 2> nul +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://sphinx-doc.org/ + exit /b 1 +) + +:sphinx_ok + + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\platform-plugin-aspects.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\platform-plugin-aspects.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "epub3" ( + %SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3 + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub3 file is in %BUILDDIR%/epub3. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdf" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdfja" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf-ja + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +if "%1" == "coverage" ( + %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage + if errorlevel 1 exit /b 1 + echo. + echo.Testing of coverage in the sources finished, look at the ^ +results in %BUILDDIR%/coverage/python.txt. + goto end +) + +if "%1" == "xml" ( + %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The XML files are in %BUILDDIR%/xml. + goto end +) + +if "%1" == "pseudoxml" ( + %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. + goto end +) + +if "%1" == "dummy" ( + %SPHINXBUILD% -b dummy %ALLSPHINXOPTS% %BUILDDIR%/dummy + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. Dummy builder generates no files. + goto end +) + +:end diff --git a/docs/quickstarts/index.rst b/docs/quickstarts/index.rst new file mode 100644 index 0000000..e3f408f --- /dev/null +++ b/docs/quickstarts/index.rst @@ -0,0 +1,2 @@ +Quick Start +########### diff --git a/docs/readme.rst b/docs/readme.rst new file mode 100644 index 0000000..72a3355 --- /dev/null +++ b/docs/readme.rst @@ -0,0 +1 @@ +.. include:: ../README.rst diff --git a/docs/references/index.rst b/docs/references/index.rst new file mode 100644 index 0000000..ba5ea57 --- /dev/null +++ b/docs/references/index.rst @@ -0,0 +1,2 @@ +References +########## diff --git a/docs/testing.rst b/docs/testing.rst new file mode 100644 index 0000000..803c3dc --- /dev/null +++ b/docs/testing.rst @@ -0,0 +1,44 @@ +.. _chapter-testing: + +Testing +####### + +platform-plugin-aspects has an assortment of test cases and code quality +checks to catch potential problems during development. To run them all in the +version of Python you chose for your virtualenv: + +.. code-block:: bash + + $ make validate + +To run just the unit tests: + +.. code-block:: bash + + $ make test + +To run just the unit tests and check diff coverage + +.. code-block:: bash + + $ make diff_cover + +To run just the code quality checks: + +.. code-block:: bash + + $ make quality + +To run the unit tests under every supported Python version and the code +quality checks: + +.. code-block:: bash + + $ make test-all + +To generate and open an HTML report of how much of the code is covered by +test cases: + +.. code-block:: bash + + $ make coverage diff --git a/manage.py b/manage.py new file mode 100644 index 0000000..4afa5aa --- /dev/null +++ b/manage.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python +""" +Django administration utility. +""" + +import os +import sys + +PWD = os.path.abspath(os.path.dirname(__file__)) + +if __name__ == '__main__': + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'test_settings') + sys.path.append(PWD) + try: + from django.core.management import execute_from_command_line + except ImportError: + # The above import may fail for some other reason. Ensure that the + # issue is really that Django is missing to avoid masking other + # exceptions on Python 2. + try: + import django # pylint: disable=unused-import, wrong-import-position + except ImportError as import_error: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from import_error + raise + execute_from_command_line(sys.argv) diff --git a/openedx.yaml b/openedx.yaml new file mode 100644 index 0000000..2785759 --- /dev/null +++ b/openedx.yaml @@ -0,0 +1,23 @@ +# This file describes this Open edX repo, as described in OEP-2: +# https://open-edx-proposals.readthedocs.io/en/latest/oep-0002-bp-repo-metadata.html#specification + +--- +oeps: + oep-2: true + oep-3: + state: false + reason: TODO - Implement for this application if appropriate + oep-5: + state: false + reason: TODO - Implement for this application if appropriate + oep-18: true + oep-30: + state: true +openedx-release: + # The openedx-release key is described in OEP-10: + # https://open-edx-proposals.readthedocs.io/en/latest/oep-0010-proc-openedx-releases.html + # The FAQ might also be helpful: https://openedx.atlassian.net/wiki/spaces/COMM/pages/1331268879/Open+edX+Release+FAQ + # Note: This will only work if the repo is in the `openedx` org in github. Repos in other orgs that have this + # setting will still be treated as if they don't want to be part of the Open edX releases. + maybe: true # Delete this "maybe" line when you have decided about Open edX inclusion. + ref: main diff --git a/platform_plugin_aspects/__init__.py b/platform_plugin_aspects/__init__.py new file mode 100644 index 0000000..8d0a793 --- /dev/null +++ b/platform_plugin_aspects/__init__.py @@ -0,0 +1,5 @@ +""" +Aspects plugins for edx-platform +""" + +__version__ = '0.1.0' diff --git a/platform_plugin_aspects/apps.py b/platform_plugin_aspects/apps.py new file mode 100644 index 0000000..608a632 --- /dev/null +++ b/platform_plugin_aspects/apps.py @@ -0,0 +1,13 @@ +""" +platform_plugin_aspects Django application initialization. +""" + +from django.apps import AppConfig + + +class PlatformPluginAspectsConfig(AppConfig): + """ + Configuration for the platform_plugin_aspects Django application. + """ + + name = 'platform_plugin_aspects' diff --git a/platform_plugin_aspects/conf/locale/config.yaml b/platform_plugin_aspects/conf/locale/config.yaml new file mode 100644 index 0000000..bf2539e --- /dev/null +++ b/platform_plugin_aspects/conf/locale/config.yaml @@ -0,0 +1,85 @@ +# Configuration for i18n workflow. + +locales: + - en # English - Source Language + - am # Amharic + - ar # Arabic + - az # Azerbaijani + - bg_BG # Bulgarian (Bulgaria) + - bn_BD # Bengali (Bangladesh) + - bn_IN # Bengali (India) + - bs # Bosnian + - ca # Catalan + - ca@valencia # Catalan (Valencia) + - cs # Czech + - cy # Welsh + - da # Danish + - de_DE # German (Germany) + - el # Greek + - en # English + - en_GB # English (United Kingdom) + # Don't pull these until we figure out why pages randomly display in these locales, + # when the user's browser is in English and the user is not logged in. + # - en@lolcat # LOLCAT English + # - en@pirate # Pirate English + - es_419 # Spanish (Latin America) + - es_AR # Spanish (Argentina) + - es_EC # Spanish (Ecuador) + - es_ES # Spanish (Spain) + - es_MX # Spanish (Mexico) + - es_PE # Spanish (Peru) + - et_EE # Estonian (Estonia) + - eu_ES # Basque (Spain) + - fa # Persian + - fa_IR # Persian (Iran) + - fi_FI # Finnish (Finland) + - fil # Filipino + - fr # French + - gl # Galician + - gu # Gujarati + - he # Hebrew + - hi # Hindi + - hr # Croatian + - hu # Hungarian + - hy_AM # Armenian (Armenia) + - id # Indonesian + - it_IT # Italian (Italy) + - ja_JP # Japanese (Japan) + - kk_KZ # Kazakh (Kazakhstan) + - km_KH # Khmer (Cambodia) + - kn # Kannada + - ko_KR # Korean (Korea) + - lt_LT # Lithuanian (Lithuania) + - ml # Malayalam + - mn # Mongolian + - mr # Marathi + - ms # Malay + - nb # Norwegian Bokmål + - ne # Nepali + - nl_NL # Dutch (Netherlands) + - or # Oriya + - pl # Polish + - pt_BR # Portuguese (Brazil) + - pt_PT # Portuguese (Portugal) + - ro # Romanian + - ru # Russian + - si # Sinhala + - sk # Slovak + - sl # Slovenian + - sq # Albanian + - sr # Serbian + - ta # Tamil + - te # Telugu + - th # Thai + - tr_TR # Turkish (Turkey) + - uk # Ukrainian + - ur # Urdu + - uz # Uzbek + - vi # Vietnamese + - zh_CN # Chinese (China) + - zh_HK # Chinese (Hong Kong) + - zh_TW # Chinese (Taiwan) + +# The locales used for fake-accented English, for testing. +dummy_locales: + - eo diff --git a/platform_plugin_aspects/models.py b/platform_plugin_aspects/models.py new file mode 100644 index 0000000..0c230db --- /dev/null +++ b/platform_plugin_aspects/models.py @@ -0,0 +1,3 @@ +""" +Database models for platform_plugin_aspects. +""" diff --git a/platform_plugin_aspects/templates/platform_plugin_aspects/base.html b/platform_plugin_aspects/templates/platform_plugin_aspects/base.html new file mode 100644 index 0000000..daf311a --- /dev/null +++ b/platform_plugin_aspects/templates/platform_plugin_aspects/base.html @@ -0,0 +1,26 @@ + + +{% load i18n %} +{% trans "Dummy text to generate a translation (.po) source file. It is safe to delete this line. It is also safe to delete (load i18n) above if there are no other (trans) tags in the file" %} + +{% comment %} +As the developer of this package, don't place anything here if you can help it +since this allows developers to have interoperability between your template +structure and their own. + +Example: Developer melding the 2SoD pattern to fit inside with another pattern:: + + {% extends "base.html" %} + {% load static %} + + + {% block extra_js %} + + + {% block javascript %} + + {% endblock javascript %} + + {% endblock extra_js %} +{% endcomment %} + diff --git a/platform_plugin_aspects/urls.py b/platform_plugin_aspects/urls.py new file mode 100644 index 0000000..cb04c80 --- /dev/null +++ b/platform_plugin_aspects/urls.py @@ -0,0 +1,10 @@ +""" +URLs for platform_plugin_aspects. +""" +from django.urls import re_path # pylint: disable=unused-import +from django.views.generic import TemplateView # pylint: disable=unused-import + +urlpatterns = [ + # TODO: Fill in URL patterns and views here. + # re_path(r'', TemplateView.as_view(template_name="platform_plugin_aspects/base.html")), +] diff --git a/pylintrc b/pylintrc new file mode 100644 index 0000000..7b10d96 --- /dev/null +++ b/pylintrc @@ -0,0 +1,390 @@ +# *************************** +# ** DO NOT EDIT THIS FILE ** +# *************************** +# +# This file was generated by edx-lint: https://github.com/openedx/edx-lint +# +# If you want to change this file, you have two choices, depending on whether +# you want to make a local change that applies only to this repo, or whether +# you want to make a central change that applies to all repos using edx-lint. +# +# Note: If your pylintrc file is simply out-of-date relative to the latest +# pylintrc in edx-lint, ensure you have the latest edx-lint installed +# and then follow the steps for a "LOCAL CHANGE". +# +# LOCAL CHANGE: +# +# 1. Edit the local pylintrc_tweaks file to add changes just to this +# repo's file. +# +# 2. Run: +# +# $ edx_lint write pylintrc +# +# 3. This will modify the local file. Submit a pull request to get it +# checked in so that others will benefit. +# +# +# CENTRAL CHANGE: +# +# 1. Edit the pylintrc file in the edx-lint repo at +# https://github.com/openedx/edx-lint/blob/master/edx_lint/files/pylintrc +# +# 2. install the updated version of edx-lint (in edx-lint): +# +# $ pip install . +# +# 3. Run (in edx-lint): +# +# $ edx_lint write pylintrc +# +# 4. Make a new version of edx_lint, submit and review a pull request with the +# pylintrc update, and after merging, update the edx-lint version and +# publish the new version. +# +# 5. In your local repo, install the newer version of edx-lint. +# +# 6. Run: +# +# $ edx_lint write pylintrc +# +# 7. This will modify the local file. Submit a pull request to get it +# checked in so that others will benefit. +# +# +# +# +# +# STAY AWAY FROM THIS FILE! +# +# +# +# +# +# SERIOUSLY. +# +# ------------------------------ +# Generated by edx-lint version: 5.3.6 +# ------------------------------ +[MASTER] +ignore = migrations +persistent = yes +load-plugins = edx_lint.pylint,pylint_django,pylint_celery + +[MESSAGES CONTROL] +enable = + blacklisted-name, + line-too-long, + + abstract-class-instantiated, + abstract-method, + access-member-before-definition, + anomalous-backslash-in-string, + anomalous-unicode-escape-in-string, + arguments-differ, + assert-on-tuple, + assigning-non-slot, + assignment-from-no-return, + assignment-from-none, + attribute-defined-outside-init, + bad-except-order, + bad-format-character, + bad-format-string-key, + bad-format-string, + bad-open-mode, + bad-reversed-sequence, + bad-staticmethod-argument, + bad-str-strip-call, + bad-super-call, + binary-op-exception, + boolean-datetime, + catching-non-exception, + cell-var-from-loop, + confusing-with-statement, + continue-in-finally, + dangerous-default-value, + duplicate-argument-name, + duplicate-bases, + duplicate-except, + duplicate-key, + expression-not-assigned, + format-combined-specification, + format-needs-mapping, + function-redefined, + global-variable-undefined, + import-error, + import-self, + inconsistent-mro, + inherit-non-class, + init-is-generator, + invalid-all-object, + invalid-format-index, + invalid-length-returned, + invalid-sequence-index, + invalid-slice-index, + invalid-slots-object, + invalid-slots, + invalid-unary-operand-type, + logging-too-few-args, + logging-too-many-args, + logging-unsupported-format, + lost-exception, + method-hidden, + misplaced-bare-raise, + misplaced-future, + missing-format-argument-key, + missing-format-attribute, + missing-format-string-key, + no-member, + no-method-argument, + no-name-in-module, + no-self-argument, + no-value-for-parameter, + non-iterator-returned, + non-parent-method-called, + nonexistent-operator, + not-a-mapping, + not-an-iterable, + not-callable, + not-context-manager, + not-in-loop, + pointless-statement, + pointless-string-statement, + raising-bad-type, + raising-non-exception, + redefined-builtin, + redefined-outer-name, + redundant-keyword-arg, + repeated-keyword, + return-arg-in-generator, + return-in-init, + return-outside-function, + signature-differs, + super-init-not-called, + super-method-not-called, + syntax-error, + test-inherits-tests, + too-few-format-args, + too-many-format-args, + too-many-function-args, + translation-of-non-string, + truncated-format-string, + undefined-all-variable, + undefined-loop-variable, + undefined-variable, + unexpected-keyword-arg, + unexpected-special-method-signature, + unpacking-non-sequence, + unreachable, + unsubscriptable-object, + unsupported-binary-operation, + unsupported-membership-test, + unused-format-string-argument, + unused-format-string-key, + used-before-assignment, + using-constant-test, + yield-outside-function, + + astroid-error, + fatal, + method-check-failed, + parse-error, + raw-checker-failed, + + empty-docstring, + invalid-characters-in-docstring, + missing-docstring, + wrong-spelling-in-comment, + wrong-spelling-in-docstring, + + unused-argument, + unused-import, + unused-variable, + + eval-used, + exec-used, + + bad-classmethod-argument, + bad-mcs-classmethod-argument, + bad-mcs-method-argument, + bare-except, + broad-except, + consider-iterating-dictionary, + consider-using-enumerate, + global-at-module-level, + global-variable-not-assigned, + literal-used-as-attribute, + logging-format-interpolation, + logging-not-lazy, + multiple-imports, + multiple-statements, + no-classmethod-decorator, + no-staticmethod-decorator, + protected-access, + redundant-unittest-assert, + reimported, + simplifiable-if-statement, + simplifiable-range, + singleton-comparison, + superfluous-parens, + unidiomatic-typecheck, + unnecessary-lambda, + unnecessary-pass, + unnecessary-semicolon, + unneeded-not, + useless-else-on-loop, + wrong-assert-type, + + deprecated-method, + deprecated-module, + + too-many-boolean-expressions, + too-many-nested-blocks, + too-many-statements, + + wildcard-import, + wrong-import-order, + wrong-import-position, + + missing-final-newline, + mixed-line-endings, + trailing-newlines, + trailing-whitespace, + unexpected-line-ending-format, + + bad-inline-option, + bad-option-value, + deprecated-pragma, + unrecognized-inline-option, + useless-suppression, +disable = + bad-indentation, + broad-exception-raised, + consider-using-f-string, + duplicate-code, + file-ignored, + fixme, + global-statement, + invalid-name, + locally-disabled, + no-else-return, + suppressed-message, + too-few-public-methods, + too-many-ancestors, + too-many-arguments, + too-many-branches, + too-many-instance-attributes, + too-many-lines, + too-many-locals, + too-many-public-methods, + too-many-return-statements, + ungrouped-imports, + unspecified-encoding, + unused-wildcard-import, + use-maxsplit-arg, + + feature-toggle-needs-doc, + illegal-waffle-usage, + + logging-fstring-interpolation, + invalid-name, + django-not-configured, + consider-using-with, + bad-option-value, + +[REPORTS] +output-format = text +reports = no +score = no + +[BASIC] +module-rgx = (([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ +const-rgx = (([A-Z_][A-Z0-9_]*)|(__.*__)|log|urlpatterns)$ +class-rgx = [A-Z_][a-zA-Z0-9]+$ +function-rgx = ([a-z_][a-z0-9_]{2,40}|test_[a-z0-9_]+)$ +method-rgx = ([a-z_][a-z0-9_]{2,40}|setUp|set[Uu]pClass|tearDown|tear[Dd]ownClass|assert[A-Z]\w*|maxDiff|test_[a-z0-9_]+)$ +attr-rgx = [a-z_][a-z0-9_]{2,30}$ +argument-rgx = [a-z_][a-z0-9_]{2,30}$ +variable-rgx = [a-z_][a-z0-9_]{2,30}$ +class-attribute-rgx = ([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ +inlinevar-rgx = [A-Za-z_][A-Za-z0-9_]*$ +good-names = f,i,j,k,db,ex,Run,_,__ +bad-names = foo,bar,baz,toto,tutu,tata +no-docstring-rgx = __.*__$|test_.+|setUp$|setUpClass$|tearDown$|tearDownClass$|Meta$ +docstring-min-length = 5 + +[FORMAT] +max-line-length = 120 +ignore-long-lines = ^\s*(# )?((?)|(\.\. \w+: .*))$ +single-line-if-stmt = no +max-module-lines = 1000 +indent-string = ' ' + +[MISCELLANEOUS] +notes = FIXME,XXX,TODO + +[SIMILARITIES] +min-similarity-lines = 4 +ignore-comments = yes +ignore-docstrings = yes +ignore-imports = no + +[TYPECHECK] +ignore-mixin-members = yes +ignored-classes = SQLObject +unsafe-load-any-extension = yes +generated-members = + REQUEST, + acl_users, + aq_parent, + objects, + DoesNotExist, + can_read, + can_write, + get_url, + size, + content, + status_code, + create, + build, + fields, + tag, + org, + course, + category, + name, + revision, + _meta, + +[VARIABLES] +init-import = no +dummy-variables-rgx = _|dummy|unused|.*_unused +additional-builtins = + +[CLASSES] +defining-attr-methods = __init__,__new__,setUp +valid-classmethod-first-arg = cls +valid-metaclass-classmethod-first-arg = mcs + +[DESIGN] +max-args = 5 +ignored-argument-names = _.* +max-locals = 15 +max-returns = 6 +max-branches = 12 +max-statements = 50 +max-parents = 7 +max-attributes = 7 +min-public-methods = 2 +max-public-methods = 20 + +[IMPORTS] +deprecated-modules = regsub,TERMIOS,Bastion,rexec +import-graph = +ext-import-graph = +int-import-graph = + +[EXCEPTIONS] +overgeneral-exceptions = builtins.Exception + +# 22aad72373290794ac5bd89746f80d5c1bd95e25 diff --git a/pylintrc_tweaks b/pylintrc_tweaks new file mode 100644 index 0000000..7b6eb35 --- /dev/null +++ b/pylintrc_tweaks @@ -0,0 +1,11 @@ +# pylintrc tweaks for use with edx_lint. +[MASTER] +ignore = migrations +load-plugins = edx_lint.pylint,pylint_django,pylint_celery + +[MESSAGES CONTROL] +disable+= + invalid-name, + django-not-configured, + consider-using-with, + bad-option-value, diff --git a/requirements/base.in b/requirements/base.in new file mode 100644 index 0000000..9f4002e --- /dev/null +++ b/requirements/base.in @@ -0,0 +1,7 @@ +# Core requirements for using this application +-c constraints.txt + +Django # Web application framework + + +openedx-atlas diff --git a/requirements/base.txt b/requirements/base.txt new file mode 100644 index 0000000..451961d --- /dev/null +++ b/requirements/base.txt @@ -0,0 +1,20 @@ +# +# This file is autogenerated by pip-compile with Python 3.8 +# by the following command: +# +# make upgrade +# +asgiref==3.7.2 + # via django +backports-zoneinfo==0.2.1 + # via django +django==4.2.10 + # via + # -c https://raw.githubusercontent.com/edx/edx-lint/master/edx_lint/files/common_constraints.txt + # -r requirements/base.in +openedx-atlas==0.6.0 + # via -r requirements/base.in +sqlparse==0.4.4 + # via django +typing-extensions==4.10.0 + # via asgiref diff --git a/requirements/ci.in b/requirements/ci.in new file mode 100644 index 0000000..3586cbe --- /dev/null +++ b/requirements/ci.in @@ -0,0 +1,5 @@ +# Requirements for running tests in CI + +-c constraints.txt + +tox # Virtualenv management for tests diff --git a/requirements/ci.txt b/requirements/ci.txt new file mode 100644 index 0000000..88a39ff --- /dev/null +++ b/requirements/ci.txt @@ -0,0 +1,38 @@ +# +# This file is autogenerated by pip-compile with Python 3.8 +# by the following command: +# +# make upgrade +# +cachetools==5.3.3 + # via tox +chardet==5.2.0 + # via tox +colorama==0.4.6 + # via tox +distlib==0.3.8 + # via virtualenv +filelock==3.13.1 + # via + # tox + # virtualenv +packaging==23.2 + # via + # pyproject-api + # tox +platformdirs==4.2.0 + # via + # tox + # virtualenv +pluggy==1.4.0 + # via tox +pyproject-api==1.6.1 + # via tox +tomli==2.0.1 + # via + # pyproject-api + # tox +tox==4.13.0 + # via -r requirements/ci.in +virtualenv==20.25.1 + # via tox diff --git a/requirements/constraints.txt b/requirements/constraints.txt new file mode 100644 index 0000000..d91704b --- /dev/null +++ b/requirements/constraints.txt @@ -0,0 +1,12 @@ +# Version constraints for pip-installation. +# +# This file doesn't install any packages. It specifies version constraints +# that will be applied if a package is needed. +# +# When pinning something here, please provide an explanation of why. Ideally, +# link to other information that will help people in the future to remove the +# pin when possible. Writing an issue against the offending project and +# linking to it here is good. + +# Common constraints for edx repos +-c https://raw.githubusercontent.com/edx/edx-lint/master/edx_lint/files/common_constraints.txt diff --git a/requirements/dev.in b/requirements/dev.in new file mode 100644 index 0000000..eb8c92c --- /dev/null +++ b/requirements/dev.in @@ -0,0 +1,9 @@ +# Additional requirements for development of this application +-c constraints.txt + +-r pip-tools.txt # pip-tools and its dependencies, for managing requirements files +-r quality.txt # Core and quality check dependencies +-r ci.txt # dependencies for setting up testing in CI + +diff-cover # Changeset diff test coverage +edx-i18n-tools # For i18n_tool dummy diff --git a/requirements/dev.txt b/requirements/dev.txt new file mode 100644 index 0000000..ec59a68 --- /dev/null +++ b/requirements/dev.txt @@ -0,0 +1,260 @@ +# +# This file is autogenerated by pip-compile with Python 3.8 +# by the following command: +# +# make upgrade +# +asgiref==3.7.2 + # via + # -r requirements/quality.txt + # django +astroid==3.1.0 + # via + # -r requirements/quality.txt + # pylint + # pylint-celery +backports-zoneinfo==0.2.1 + # via + # -r requirements/quality.txt + # django +build==1.0.3 + # via + # -r requirements/pip-tools.txt + # pip-tools +cachetools==5.3.3 + # via + # -r requirements/ci.txt + # tox +chardet==5.2.0 + # via + # -r requirements/ci.txt + # diff-cover + # tox +click==8.1.7 + # via + # -r requirements/pip-tools.txt + # -r requirements/quality.txt + # click-log + # code-annotations + # edx-lint + # pip-tools +click-log==0.4.0 + # via + # -r requirements/quality.txt + # edx-lint +code-annotations==1.6.0 + # via + # -r requirements/quality.txt + # edx-lint +colorama==0.4.6 + # via + # -r requirements/ci.txt + # tox +coverage[toml]==7.4.3 + # via + # -r requirements/quality.txt + # pytest-cov +diff-cover==8.0.3 + # via -r requirements/dev.in +dill==0.3.8 + # via + # -r requirements/quality.txt + # pylint +distlib==0.3.8 + # via + # -r requirements/ci.txt + # virtualenv +django==4.2.10 + # via + # -c https://raw.githubusercontent.com/edx/edx-lint/master/edx_lint/files/common_constraints.txt + # -r requirements/quality.txt + # edx-i18n-tools +edx-i18n-tools==1.3.0 + # via -r requirements/dev.in +edx-lint==5.3.6 + # via -r requirements/quality.txt +exceptiongroup==1.2.0 + # via + # -r requirements/quality.txt + # pytest +filelock==3.13.1 + # via + # -r requirements/ci.txt + # tox + # virtualenv +importlib-metadata==7.0.1 + # via + # -r requirements/pip-tools.txt + # build +iniconfig==2.0.0 + # via + # -r requirements/quality.txt + # pytest +isort==5.13.2 + # via + # -r requirements/quality.txt + # pylint +jinja2==3.1.3 + # via + # -r requirements/quality.txt + # code-annotations + # diff-cover +lxml==5.1.0 + # via edx-i18n-tools +markupsafe==2.1.5 + # via + # -r requirements/quality.txt + # jinja2 +mccabe==0.7.0 + # via + # -r requirements/quality.txt + # pylint +openedx-atlas==0.6.0 + # via -r requirements/quality.txt +packaging==23.2 + # via + # -r requirements/ci.txt + # -r requirements/pip-tools.txt + # -r requirements/quality.txt + # build + # pyproject-api + # pytest + # tox +path==16.10.0 + # via edx-i18n-tools +pbr==6.0.0 + # via + # -r requirements/quality.txt + # stevedore +pip-tools==7.4.0 + # via -r requirements/pip-tools.txt +platformdirs==4.2.0 + # via + # -r requirements/ci.txt + # -r requirements/quality.txt + # pylint + # tox + # virtualenv +pluggy==1.4.0 + # via + # -r requirements/ci.txt + # -r requirements/quality.txt + # diff-cover + # pytest + # tox +polib==1.2.0 + # via edx-i18n-tools +pycodestyle==2.11.1 + # via -r requirements/quality.txt +pydocstyle==6.3.0 + # via -r requirements/quality.txt +pygments==2.17.2 + # via diff-cover +pylint==3.1.0 + # via + # -r requirements/quality.txt + # edx-lint + # pylint-celery + # pylint-django + # pylint-plugin-utils +pylint-celery==0.3 + # via + # -r requirements/quality.txt + # edx-lint +pylint-django==2.5.5 + # via + # -r requirements/quality.txt + # edx-lint +pylint-plugin-utils==0.8.2 + # via + # -r requirements/quality.txt + # pylint-celery + # pylint-django +pyproject-api==1.6.1 + # via + # -r requirements/ci.txt + # tox +pyproject-hooks==1.0.0 + # via + # -r requirements/pip-tools.txt + # build + # pip-tools +pytest==8.0.2 + # via + # -r requirements/quality.txt + # pytest-cov + # pytest-django +pytest-cov==4.1.0 + # via -r requirements/quality.txt +pytest-django==4.8.0 + # via -r requirements/quality.txt +python-slugify==8.0.4 + # via + # -r requirements/quality.txt + # code-annotations +pyyaml==6.0.1 + # via + # -r requirements/quality.txt + # code-annotations + # edx-i18n-tools +six==1.16.0 + # via + # -r requirements/quality.txt + # edx-lint +snowballstemmer==2.2.0 + # via + # -r requirements/quality.txt + # pydocstyle +sqlparse==0.4.4 + # via + # -r requirements/quality.txt + # django +stevedore==5.2.0 + # via + # -r requirements/quality.txt + # code-annotations +text-unidecode==1.3 + # via + # -r requirements/quality.txt + # python-slugify +tomli==2.0.1 + # via + # -r requirements/ci.txt + # -r requirements/pip-tools.txt + # -r requirements/quality.txt + # build + # coverage + # pip-tools + # pylint + # pyproject-api + # pyproject-hooks + # pytest + # tox +tomlkit==0.12.4 + # via + # -r requirements/quality.txt + # pylint +tox==4.13.0 + # via -r requirements/ci.txt +typing-extensions==4.10.0 + # via + # -r requirements/quality.txt + # asgiref + # astroid + # pylint +virtualenv==20.25.1 + # via + # -r requirements/ci.txt + # tox +wheel==0.42.0 + # via + # -r requirements/pip-tools.txt + # pip-tools +zipp==3.17.0 + # via + # -r requirements/pip-tools.txt + # importlib-metadata + +# The following packages are considered to be unsafe in a requirements file: +# pip +# setuptools diff --git a/requirements/doc.in b/requirements/doc.in new file mode 100644 index 0000000..a8b0290 --- /dev/null +++ b/requirements/doc.in @@ -0,0 +1,10 @@ +# Requirements for documentation validation +-c constraints.txt + +-r test.txt # Core and testing dependencies for this package + +doc8 # reStructuredText style checker +sphinx-book-theme # Common theme for all Open edX projects +twine # Validates README.rst for usage on PyPI +build # Needed to build the wheel for twine check +Sphinx # Documentation builder diff --git a/requirements/doc.txt b/requirements/doc.txt new file mode 100644 index 0000000..925948a --- /dev/null +++ b/requirements/doc.txt @@ -0,0 +1,219 @@ +# +# This file is autogenerated by pip-compile with Python 3.8 +# by the following command: +# +# make upgrade +# +accessible-pygments==0.0.4 + # via pydata-sphinx-theme +alabaster==0.7.13 + # via sphinx +asgiref==3.7.2 + # via + # -r requirements/test.txt + # django +babel==2.14.0 + # via + # pydata-sphinx-theme + # sphinx +backports-zoneinfo==0.2.1 + # via + # -r requirements/test.txt + # django +beautifulsoup4==4.12.3 + # via pydata-sphinx-theme +build==1.0.3 + # via -r requirements/doc.in +certifi==2024.2.2 + # via requests +charset-normalizer==3.3.2 + # via requests +click==8.1.7 + # via + # -r requirements/test.txt + # code-annotations +code-annotations==1.6.0 + # via -r requirements/test.txt +coverage[toml]==7.4.3 + # via + # -r requirements/test.txt + # pytest-cov +django==4.2.10 + # via + # -c https://raw.githubusercontent.com/edx/edx-lint/master/edx_lint/files/common_constraints.txt + # -r requirements/test.txt +doc8==1.1.1 + # via -r requirements/doc.in +docutils==0.19 + # via + # doc8 + # pydata-sphinx-theme + # readme-renderer + # restructuredtext-lint + # sphinx +exceptiongroup==1.2.0 + # via + # -r requirements/test.txt + # pytest +idna==3.6 + # via requests +imagesize==1.4.1 + # via sphinx +importlib-metadata==7.0.1 + # via + # build + # keyring + # sphinx + # twine +importlib-resources==6.1.2 + # via keyring +iniconfig==2.0.0 + # via + # -r requirements/test.txt + # pytest +jaraco-classes==3.3.1 + # via keyring +jinja2==3.1.3 + # via + # -r requirements/test.txt + # code-annotations + # sphinx +keyring==24.3.1 + # via twine +markdown-it-py==3.0.0 + # via rich +markupsafe==2.1.5 + # via + # -r requirements/test.txt + # jinja2 +mdurl==0.1.2 + # via markdown-it-py +more-itertools==10.2.0 + # via jaraco-classes +nh3==0.2.15 + # via readme-renderer +openedx-atlas==0.6.0 + # via -r requirements/test.txt +packaging==23.2 + # via + # -r requirements/test.txt + # build + # pydata-sphinx-theme + # pytest + # sphinx +pbr==6.0.0 + # via + # -r requirements/test.txt + # stevedore +pkginfo==1.9.6 + # via twine +pluggy==1.4.0 + # via + # -r requirements/test.txt + # pytest +pydata-sphinx-theme==0.14.4 + # via sphinx-book-theme +pygments==2.17.2 + # via + # accessible-pygments + # doc8 + # pydata-sphinx-theme + # readme-renderer + # rich + # sphinx +pyproject-hooks==1.0.0 + # via build +pytest==8.0.2 + # via + # -r requirements/test.txt + # pytest-cov + # pytest-django +pytest-cov==4.1.0 + # via -r requirements/test.txt +pytest-django==4.8.0 + # via -r requirements/test.txt +python-slugify==8.0.4 + # via + # -r requirements/test.txt + # code-annotations +pytz==2024.1 + # via babel +pyyaml==6.0.1 + # via + # -r requirements/test.txt + # code-annotations +readme-renderer==43.0 + # via twine +requests==2.31.0 + # via + # requests-toolbelt + # sphinx + # twine +requests-toolbelt==1.0.0 + # via twine +restructuredtext-lint==1.4.0 + # via doc8 +rfc3986==2.0.0 + # via twine +rich==13.7.1 + # via twine +snowballstemmer==2.2.0 + # via sphinx +soupsieve==2.5 + # via beautifulsoup4 +sphinx==6.2.1 + # via + # -r requirements/doc.in + # pydata-sphinx-theme + # sphinx-book-theme +sphinx-book-theme==1.0.1 + # via -r requirements/doc.in +sphinxcontrib-applehelp==1.0.4 + # via sphinx +sphinxcontrib-devhelp==1.0.2 + # via sphinx +sphinxcontrib-htmlhelp==2.0.1 + # via sphinx +sphinxcontrib-jsmath==1.0.1 + # via sphinx +sphinxcontrib-qthelp==1.0.3 + # via sphinx +sphinxcontrib-serializinghtml==1.1.5 + # via sphinx +sqlparse==0.4.4 + # via + # -r requirements/test.txt + # django +stevedore==5.2.0 + # via + # -r requirements/test.txt + # code-annotations + # doc8 +text-unidecode==1.3 + # via + # -r requirements/test.txt + # python-slugify +tomli==2.0.1 + # via + # -r requirements/test.txt + # build + # coverage + # doc8 + # pyproject-hooks + # pytest +twine==5.0.0 + # via -r requirements/doc.in +typing-extensions==4.10.0 + # via + # -r requirements/test.txt + # asgiref + # pydata-sphinx-theme + # rich +urllib3==2.2.1 + # via + # requests + # twine +zipp==3.17.0 + # via + # importlib-metadata + # importlib-resources diff --git a/requirements/pip-tools.in b/requirements/pip-tools.in new file mode 100644 index 0000000..0295d2c --- /dev/null +++ b/requirements/pip-tools.in @@ -0,0 +1,5 @@ +# Just the dependencies to run pip-tools, mainly for the "upgrade" make target + +-c constraints.txt + +pip-tools # Contains pip-compile, used to generate pip requirements files diff --git a/requirements/pip-tools.txt b/requirements/pip-tools.txt new file mode 100644 index 0000000..44c48d9 --- /dev/null +++ b/requirements/pip-tools.txt @@ -0,0 +1,33 @@ +# +# This file is autogenerated by pip-compile with Python 3.8 +# by the following command: +# +# make upgrade +# +build==1.0.3 + # via pip-tools +click==8.1.7 + # via pip-tools +importlib-metadata==7.0.1 + # via build +packaging==23.2 + # via build +pip-tools==7.4.0 + # via -r requirements/pip-tools.in +pyproject-hooks==1.0.0 + # via + # build + # pip-tools +tomli==2.0.1 + # via + # build + # pip-tools + # pyproject-hooks +wheel==0.42.0 + # via pip-tools +zipp==3.17.0 + # via importlib-metadata + +# The following packages are considered to be unsafe in a requirements file: +# pip +# setuptools diff --git a/requirements/pip.in b/requirements/pip.in new file mode 100644 index 0000000..716c6f2 --- /dev/null +++ b/requirements/pip.in @@ -0,0 +1,6 @@ +# Core dependencies for installing other packages +-c constraints.txt + +pip +setuptools +wheel diff --git a/requirements/pip.txt b/requirements/pip.txt new file mode 100644 index 0000000..6665603 --- /dev/null +++ b/requirements/pip.txt @@ -0,0 +1,14 @@ +# +# This file is autogenerated by pip-compile with Python 3.8 +# by the following command: +# +# make upgrade +# +wheel==0.42.0 + # via -r requirements/pip.in + +# The following packages are considered to be unsafe in a requirements file: +pip==24.0 + # via -r requirements/pip.in +setuptools==69.1.1 + # via -r requirements/pip.in diff --git a/requirements/private.readme b/requirements/private.readme new file mode 100644 index 0000000..5600a10 --- /dev/null +++ b/requirements/private.readme @@ -0,0 +1,15 @@ +# If there are any Python packages you want to keep in your virtualenv beyond +# those listed in the official requirements files, create a "private.in" file +# and list them there. Generate the corresponding "private.txt" file pinning +# all of their indirect dependencies to specific versions as follows: + +# pip-compile private.in + +# This allows you to use "pip-sync" without removing these packages: + +# pip-sync requirements/*.txt + +# "private.in" and "private.txt" aren't checked into git to avoid merge +# conflicts, and the presence of this file allows "private.*" to be +# included in scripted pip-sync usage without requiring that those files be +# created first. diff --git a/requirements/quality.in b/requirements/quality.in new file mode 100644 index 0000000..93661d9 --- /dev/null +++ b/requirements/quality.in @@ -0,0 +1,10 @@ +# Requirements for code quality checks + +-c constraints.txt + +-r test.txt # Core and testing dependencies for this package + +edx-lint # edX pylint rules and plugins +isort # to standardize order of imports +pycodestyle # PEP 8 compliance validation +pydocstyle # PEP 257 compliance validation diff --git a/requirements/quality.txt b/requirements/quality.txt new file mode 100644 index 0000000..59f6e0c --- /dev/null +++ b/requirements/quality.txt @@ -0,0 +1,145 @@ +# +# This file is autogenerated by pip-compile with Python 3.8 +# by the following command: +# +# make upgrade +# +asgiref==3.7.2 + # via + # -r requirements/test.txt + # django +astroid==3.1.0 + # via + # pylint + # pylint-celery +backports-zoneinfo==0.2.1 + # via + # -r requirements/test.txt + # django +click==8.1.7 + # via + # -r requirements/test.txt + # click-log + # code-annotations + # edx-lint +click-log==0.4.0 + # via edx-lint +code-annotations==1.6.0 + # via + # -r requirements/test.txt + # edx-lint +coverage[toml]==7.4.3 + # via + # -r requirements/test.txt + # pytest-cov +dill==0.3.8 + # via pylint +django==4.2.10 + # via + # -c https://raw.githubusercontent.com/edx/edx-lint/master/edx_lint/files/common_constraints.txt + # -r requirements/test.txt +edx-lint==5.3.6 + # via -r requirements/quality.in +exceptiongroup==1.2.0 + # via + # -r requirements/test.txt + # pytest +iniconfig==2.0.0 + # via + # -r requirements/test.txt + # pytest +isort==5.13.2 + # via + # -r requirements/quality.in + # pylint +jinja2==3.1.3 + # via + # -r requirements/test.txt + # code-annotations +markupsafe==2.1.5 + # via + # -r requirements/test.txt + # jinja2 +mccabe==0.7.0 + # via pylint +openedx-atlas==0.6.0 + # via -r requirements/test.txt +packaging==23.2 + # via + # -r requirements/test.txt + # pytest +pbr==6.0.0 + # via + # -r requirements/test.txt + # stevedore +platformdirs==4.2.0 + # via pylint +pluggy==1.4.0 + # via + # -r requirements/test.txt + # pytest +pycodestyle==2.11.1 + # via -r requirements/quality.in +pydocstyle==6.3.0 + # via -r requirements/quality.in +pylint==3.1.0 + # via + # edx-lint + # pylint-celery + # pylint-django + # pylint-plugin-utils +pylint-celery==0.3 + # via edx-lint +pylint-django==2.5.5 + # via edx-lint +pylint-plugin-utils==0.8.2 + # via + # pylint-celery + # pylint-django +pytest==8.0.2 + # via + # -r requirements/test.txt + # pytest-cov + # pytest-django +pytest-cov==4.1.0 + # via -r requirements/test.txt +pytest-django==4.8.0 + # via -r requirements/test.txt +python-slugify==8.0.4 + # via + # -r requirements/test.txt + # code-annotations +pyyaml==6.0.1 + # via + # -r requirements/test.txt + # code-annotations +six==1.16.0 + # via edx-lint +snowballstemmer==2.2.0 + # via pydocstyle +sqlparse==0.4.4 + # via + # -r requirements/test.txt + # django +stevedore==5.2.0 + # via + # -r requirements/test.txt + # code-annotations +text-unidecode==1.3 + # via + # -r requirements/test.txt + # python-slugify +tomli==2.0.1 + # via + # -r requirements/test.txt + # coverage + # pylint + # pytest +tomlkit==0.12.4 + # via pylint +typing-extensions==4.10.0 + # via + # -r requirements/test.txt + # asgiref + # astroid + # pylint diff --git a/requirements/test.in b/requirements/test.in new file mode 100644 index 0000000..6797160 --- /dev/null +++ b/requirements/test.in @@ -0,0 +1,8 @@ +# Requirements for test runs. +-c constraints.txt + +-r base.txt # Core dependencies for this package + +pytest-cov # pytest extension for code coverage statistics +pytest-django # pytest extension for better Django support +code-annotations # provides commands used by the pii_check make target. diff --git a/requirements/test.txt b/requirements/test.txt new file mode 100644 index 0000000..d3406f9 --- /dev/null +++ b/requirements/test.txt @@ -0,0 +1,67 @@ +# +# This file is autogenerated by pip-compile with Python 3.8 +# by the following command: +# +# make upgrade +# +asgiref==3.7.2 + # via + # -r requirements/base.txt + # django +backports-zoneinfo==0.2.1 + # via + # -r requirements/base.txt + # django +click==8.1.7 + # via code-annotations +code-annotations==1.6.0 + # via -r requirements/test.in +coverage[toml]==7.4.3 + # via pytest-cov + # via + # -c https://raw.githubusercontent.com/edx/edx-lint/master/edx_lint/files/common_constraints.txt + # -r requirements/base.txt +exceptiongroup==1.2.0 + # via pytest +iniconfig==2.0.0 + # via pytest +jinja2==3.1.3 + # via code-annotations +markupsafe==2.1.5 + # via jinja2 +openedx-atlas==0.6.0 + # via -r requirements/base.txt +packaging==23.2 + # via pytest +pbr==6.0.0 + # via stevedore +pluggy==1.4.0 + # via pytest +pytest==8.0.2 + # via + # pytest-cov + # pytest-django +pytest-cov==4.1.0 + # via -r requirements/test.in +pytest-django==4.8.0 + # via -r requirements/test.in +python-slugify==8.0.4 + # via code-annotations +pyyaml==6.0.1 + # via code-annotations +sqlparse==0.4.4 + # via + # -r requirements/base.txt + # django +stevedore==5.2.0 + # via code-annotations +text-unidecode==1.3 + # via python-slugify +tomli==2.0.1 + # via + # coverage + # pytest +typing-extensions==4.10.0 + # via + # -r requirements/base.txt + # asgiref diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..d782599 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,10 @@ +[isort] +include_trailing_comma = True +indent = ' ' +line_length = 120 +multi_line_output = 3 +skip= + migrations + +[wheel] +universal = 1 diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..34448a6 --- /dev/null +++ b/setup.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python +""" +Package metadata for platform_plugin_aspects. +""" +import os +import re +import sys + +from setuptools import find_packages, setup + + +def get_version(*file_paths): + """ + Extract the version string from the file. + + Input: + - file_paths: relative path fragments to file with + version string + """ + filename = os.path.join(os.path.dirname(__file__), *file_paths) + version_file = open(filename, encoding="utf8").read() + version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", + version_file, re.M) + if version_match: + return version_match.group(1) + raise RuntimeError('Unable to find version string.') + + +def load_requirements(*requirements_paths): + """ + Load all requirements from the specified requirements files. + + Requirements will include any constraints from files specified + with -c in the requirements files. + Returns a list of requirement strings. + """ + # e.g. {"django": "Django", "confluent-kafka": "confluent_kafka[avro]"} + by_canonical_name = {} + + def check_name_consistent(package): + """ + Raise exception if package is named different ways. + + This ensures that packages are named consistently so we can match + constraints to packages. It also ensures that if we require a package + with extras we don't constrain it without mentioning the extras (since + that too would interfere with matching constraints.) + """ + canonical = package.lower().replace('_', '-').split('[')[0] + seen_spelling = by_canonical_name.get(canonical) + if seen_spelling is None: + by_canonical_name[canonical] = package + elif seen_spelling != package: + raise Exception( + f'Encountered both "{seen_spelling}" and "{package}" in requirements ' + 'and constraints files; please use just one or the other.' + ) + + requirements = {} + constraint_files = set() + + # groups "pkg<=x.y.z,..." into ("pkg", "<=x.y.z,...") + re_package_name_base_chars = r"a-zA-Z0-9\-_." # chars allowed in base package name + # Two groups: name[maybe,extras], and optionally a constraint + requirement_line_regex = re.compile( + r"([%s]+(?:\[[%s,\s]+\])?)([<>=][^#\s]+)?" + % (re_package_name_base_chars, re_package_name_base_chars) + ) + + def add_version_constraint_or_raise(current_line, current_requirements, add_if_not_present): + regex_match = requirement_line_regex.match(current_line) + if regex_match: + package = regex_match.group(1) + version_constraints = regex_match.group(2) + check_name_consistent(package) + existing_version_constraints = current_requirements.get(package, None) + # It's fine to add constraints to an unconstrained package, + # but raise an error if there are already constraints in place. + if existing_version_constraints and existing_version_constraints != version_constraints: + raise BaseException(f'Multiple constraint definitions found for {package}:' + f' "{existing_version_constraints}" and "{version_constraints}".' + f'Combine constraints into one location with {package}' + f'{existing_version_constraints},{version_constraints}.') + if add_if_not_present or package in current_requirements: + current_requirements[package] = version_constraints + + # Read requirements from .in files and store the path to any + # constraint files that are pulled in. + for path in requirements_paths: + with open(path) as reqs: + for line in reqs: + if is_requirement(line): + add_version_constraint_or_raise(line, requirements, True) + if line and line.startswith('-c') and not line.startswith('-c http'): + constraint_files.add(os.path.dirname(path) + '/' + line.split('#')[0].replace('-c', '').strip()) + + # process constraint files: add constraints to existing requirements + for constraint_file in constraint_files: + with open(constraint_file) as reader: + for line in reader: + if is_requirement(line): + add_version_constraint_or_raise(line, requirements, False) + + # process back into list of pkg><=constraints strings + constrained_requirements = [f'{pkg}{version or ""}' for (pkg, version) in sorted(requirements.items())] + return constrained_requirements + + +def is_requirement(line): + """ + Return True if the requirement line is a package requirement. + + Returns: + bool: True if the line is not blank, a comment, + a URL, or an included file + """ + return line and line.strip() and not line.startswith(("-r", "#", "-e", "git+", "-c")) + + +VERSION = get_version('platform_plugin_aspects', '__init__.py') + +if sys.argv[-1] == 'tag': + print("Tagging the version on github:") + os.system("git tag -a %s -m 'version %s'" % (VERSION, VERSION)) + os.system("git push --tags") + sys.exit() + +README = open(os.path.join(os.path.dirname(__file__), 'README.rst'), encoding="utf8").read() +CHANGELOG = open(os.path.join(os.path.dirname(__file__), 'CHANGELOG.rst'), encoding="utf8").read() + +setup( + name='platform-plugin-aspects', + version=VERSION, + description="""Aspects plugins for edx-platform""", + long_description=README + '\n\n' + CHANGELOG, + author='Open edX Project', + author_email='oscm@openedx.org', + url='https://github.com/openedx/platform-plugin-aspects', + packages=find_packages( + include=['platform_plugin_aspects', 'platform_plugin_aspects.*'], + exclude=["*tests"], + ), + + include_package_data=True, + install_requires=load_requirements('requirements/base.in'), + python_requires=">=3.8", + license="AGPL 3.0", + zip_safe=False, + keywords='Python edx', + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Framework :: Django', + 'Framework :: Django :: 3.2', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)', + 'Natural Language :: English', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.8', + ], +) diff --git a/test_settings.py b/test_settings.py new file mode 100644 index 0000000..43b7b78 --- /dev/null +++ b/test_settings.py @@ -0,0 +1,61 @@ +""" +These settings are here to use during tests, because django requires them. + +In a real-world use case, apps in this project are installed into other +Django applications, so these settings will not be used. +""" + +from os.path import abspath, dirname, join + + +def root(*args): + """ + Get the absolute path of the given path relative to the project root. + """ + return join(abspath(dirname(__file__)), *args) + + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': 'default.db', + 'USER': '', + 'PASSWORD': '', + 'HOST': '', + 'PORT': '', + } +} + +INSTALLED_APPS = ( + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.messages', + 'django.contrib.sessions', + 'platform_plugin_aspects', +) + +LOCALE_PATHS = [ + root('platform_plugin_aspects', 'conf', 'locale'), +] + +ROOT_URLCONF = 'platform_plugin_aspects.urls' + +SECRET_KEY = 'insecure-secret-key' + +MIDDLEWARE = ( + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', +) + +TEMPLATES = [{ + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'APP_DIRS': False, + 'OPTIONS': { + 'context_processors': [ + 'django.contrib.auth.context_processors.auth', # this is required for admin + 'django.contrib.messages.context_processors.messages', # this is required for admin + ], + }, +}] diff --git a/test_utils/__init__.py b/test_utils/__init__.py new file mode 100644 index 0000000..7961e47 --- /dev/null +++ b/test_utils/__init__.py @@ -0,0 +1,10 @@ +""" +Test utilities. + +Since pytest discourages putting __init__.py into testdirectory +(i.e. making tests a package) one cannot import from anywhere +under tests folder. However, some utility classes/methods might be useful +in multiple test modules (i.e. factoryboy factories, base test classes). + +So this package is the place to put them. +""" diff --git a/tests/test_models.py b/tests/test_models.py new file mode 100644 index 0000000..446a740 --- /dev/null +++ b/tests/test_models.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python +""" +Tests for the `platform-plugin-aspects` models module. +""" + +import pytest + + +@pytest.mark.skip(reason="Placeholder to allow pytest to succeed before real tests are in place.") +def test_placeholder(): + """ + TODO: Delete this test once there are real tests. + """ diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..c182f60 --- /dev/null +++ b/tox.ini @@ -0,0 +1,89 @@ +[tox] +envlist = py38-django{32,40} + +[doc8] +; D001 = Line too long +ignore = D001 + +[pycodestyle] +exclude = .git,.tox,migrations +max-line-length = 120 + +[pydocstyle] +; D101 = Missing docstring in public class +; D200 = One-line docstring should fit on one line with quotes +; D203 = 1 blank line required before class docstring +; D212 = Multi-line docstring summary should start at the first line +; D215 = Section underline is over-indented (numpy style) +; D404 = First word of the docstring should not be This (numpy style) +; D405 = Section name should be properly capitalized (numpy style) +; D406 = Section name should end with a newline (numpy style) +; D407 = Missing dashed underline after section (numpy style) +; D408 = Section underline should be in the line following the section's name (numpy style) +; D409 = Section underline should match the length of its name (numpy style) +; D410 = Missing blank line after section (numpy style) +; D411 = Missing blank line before section (numpy style) +; D412 = No blank lines allowed between a section header and its content (numpy style) +; D413 = Missing blank line after last section (numpy style) +; D414 = Section has no content (numpy style) +ignore = D101,D200,D203,D212,D215,D404,D405,D406,D407,D408,D409,D410,D411,D412,D413,D414 +match-dir = (?!migrations) + +[pytest] +DJANGO_SETTINGS_MODULE = test_settings +addopts = --cov platform_plugin_aspects --cov tests --cov-report term-missing --cov-report xml +norecursedirs = .* docs requirements site-packages + +[testenv] +deps = + django32: Django>=3.2,<4.0 + django40: Django>=4.0,<4.1 + -r{toxinidir}/requirements/test.txt +commands = + python manage.py check + pytest {posargs} + +[testenv:docs] +setenv = + DJANGO_SETTINGS_MODULE = test_settings + PYTHONPATH = {toxinidir} + # Adding the option here instead of as a default in the docs Makefile because that Makefile is generated by shpinx. + SPHINXOPTS = -W +allowlist_externals = + make + rm +deps = + -r{toxinidir}/requirements/doc.txt +commands = + doc8 --ignore-path docs/_build README.rst docs + rm -f docs/platform_plugin_aspects.rst + rm -f docs/modules.rst + make -e -C docs clean + make -e -C docs html + python -m build --wheel + twine check dist/* + +[testenv:quality] +allowlist_externals = + make + rm + touch +deps = + -r{toxinidir}/requirements/quality.txt +commands = + touch tests/__init__.py + pylint platform_plugin_aspects tests test_utils manage.py setup.py + rm tests/__init__.py + pycodestyle platform_plugin_aspects tests manage.py setup.py + pydocstyle platform_plugin_aspects tests manage.py setup.py + isort --check-only --diff tests test_utils platform_plugin_aspects manage.py setup.py test_settings.py + make selfcheck + +[testenv:pii_check] +setenv = + DJANGO_SETTINGS_MODULE = test_settings +deps = + -r{toxinidir}/requirements/test.txt +commands = + code_annotations django_find_annotations --config_file .pii_annotations.yml --lint --report --coverage +