diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 8963213..0000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,73 +0,0 @@ -version: 2.1 - -workflows: - run_tests: - jobs: - - test: - filters: - tags: - only: /v?[0-9]+(\.[0-9]+)*/ - matrix: - parameters: - python_version: ["3.5","3.8"] - - pypi: - requires: - - test - filters: - tags: - only: /v?[0-9]+(\.[0-9]+)*/ - branches: - ignore: /.*/ - -jobs: - test: - parameters: - python_version: - type: string - docker: - - image: python:<< parameters.python_version >> - working_directory: ~/flow-control-xblock - steps: - - checkout - - run : - name: Install requirements - command: | - pip install -r requirements/tox.txt - apt install git - - run: - name: Run tox tests - command: tox -e ${python_version//./} - environment: - - python_version: py<< parameters.python_version >> - - pypi: - docker: - - image: circleci/python:3.5 - steps: - - checkout - - run: - name: Init .pypirc - command: | - echo $'[distutils]\nindex-servers = pypi\n[pypi]' > ~/.pypirc - echo -e "username = $PYPI_USERNAME" >> ~/.pypirc - echo -e "password = $PYPI_PASSWORD" >> ~/.pypirc - - run: - name: Prepare venv for distribution - command: | - virtualenv venv - source venv/bin/activate - pip install twine - - run: - name: Create package - command: | - python setup.py sdist bdist_wheel - - run: - name: Check package - command: | - source venv/bin/activate - twine check dist/* - - run: - name: Upload to pypi - command: | - source venv/bin/activate - twine upload dist/* diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..1141973 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,37 @@ +name: Test suite workflow + +on: + push: + branches: [master] + pull_request: + branches: + - '**' + + +jobs: + run_tests: + name: tests + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-20.04] + python-version: ['3.11'] + toxenv: [django42] + + steps: + - uses: actions/checkout@v4 + - name: setup python + uses: actions/setup-python@v5 + 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 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/CHANGELOG.rst b/CHANGELOG.rst index d344731..5fd6947 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,6 +14,36 @@ Unreleased * +[2.0.0] - 2025-01-23 +********************************************** + +Added +===== + +* Support for Python 3.11 and Django 4.2 +* Add github workflow + +Removed +_______ + +* **BREAKING CHANGE**: Dropped support for Python 3.5 +* Drop CircleCI support +* Remove support to "redirect to another unit in the same subsection" action + +Changed +======= + +* Fix UI issues + +[1.0.1] - 2020-10-14 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Fixed +_____ + +* Python3 and Juniper issues +* Fix applyFlowControl in injection to applied correctly the actions of flow-control + [1.0.0] - 2020-06-18 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/Makefile b/Makefile index 37c41c3..4483079 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,33 @@ +.DEFAULT_GOAL := help + +ifdef TOXENV +TOX := tox -- #to isolate each tox environment if TOXENV is defined +endif + .PHONY: help test install upgrade requirements help: ## display this help message @echo "Please use \`make ' where is one of" @perl -nle'print $& if m{^[a-zA-Z_-]+:.*?## .*$$}' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m %-25s\033[0m %s\n", $$1, $$2}' +install-dev-dependencies: ## install tox + pip install -r requirements/tox.txt + +clean: ## delete most git-ignored files + find . -name '__pycache__' -exec rm -rf {} + + find . -name '*.pyc' -exec rm -f {} + + find . -name '*.pyo' -exec rm -f {} + + find . -name '*~' -exec rm -f {} + + +# Define PIP_COMPILE_OPTS=-v to get more information during make upgrade. +PIP_COMPILE = pip-compile --upgrade $(PIP_COMPILE_OPTS) + install: ## install the flow-control xblock pip install . requirements: ## fetch development requirements pip install -r requirements/base.txt + pip install -qr requirements/pip-tools.txt test: ## test using tox pip install -r requirements/tox.txt @@ -17,8 +36,18 @@ test: ## test using tox upgrade: export CUSTOM_COMPILE_COMMAND=make upgrade upgrade: ## update the pip requirements files to use the latest releases satisfying our constraints pip install -r requirements/pip-tools.txt + pip-compile --rebuild --upgrade --allow-unsafe -o requirements/pip.txt requirements/pip.in pip-compile --rebuild --upgrade -o requirements/pip-tools.txt requirements/pip-tools.in + pip install -qr requirements/pip.txt pip-compile --rebuild --upgrade -o requirements/base.txt requirements/base.in pip-compile --rebuild --upgrade -o requirements/test.txt requirements/test.in pip-compile --rebuild --upgrade -o requirements/tox.txt requirements/tox.in pip-compile --rebuild --upgrade -o requirements/quality.txt requirements/quality.in + pip-compile --rebuild --upgrade -o requirements/ci.txt requirements/ci.in + pip-compile --rebuild --upgrade -o requirements/dev.txt requirements/dev.in + +test-python: clean ## Run test suite. + $(TOX) pip install -r requirements/base.txt --exists-action w + $(TOX) coverage run --source="." -m pytest ./flow_control_xblock + +run-tests: test-python quality diff --git a/README.rst b/README.rst index f176c59..3016ddb 100644 --- a/README.rst +++ b/README.rst @@ -7,19 +7,16 @@ XBlock Flow Control The Flow Control XBlock provides a way to display the content of a unit or to redirect the user elsewhere based on compliance with a condition that evaluates the submission or the score of a problem or a set of problems. -Installing on Open edX Devstack -------------------------------- - -Inside both LMS and Studio shells, using `make lms-shell` and `make studio-shell` in your devstack directory do:: - - pip install flow-control-xblock - -However, if you want to further develop this XBlock, you might want to instead clone this repository and do:: - - pip install -e path/to/flow-control - -⚠️ Since the Open edX Olive release, some features could fail because of the integration of [Learning MFE](https://github.com/eduNEXT/frontend-app-learning). +Compatibility Notes +=================== ++------------------+--------------+ +| Open edX Release | Version | ++==================+==============+ +| Redwood | >= 2.0.0 | ++------------------+--------------+ +| Sumac | >= 2.0.0 | ++------------------+--------------+ Enabling in Studio ------------------ @@ -83,7 +80,7 @@ Features include **Actions:** This actions can be applied when a condition is met: * Display a message -* Redirect to another unit in the same subsection (without reloading the page) +* Redirect to another unit in the same subsection (without reloading the page) :warning:[DEPRECATED: Since version 2.0.0 and not working with the Learning MFE] * Redirect to another unit using jump_to_id (reloading the page) * Redirect to a given url diff --git a/flow_control/__init__.py b/flow_control/__init__.py index 9541349..84119fa 100644 --- a/flow_control/__init__.py +++ b/flow_control/__init__.py @@ -2,4 +2,4 @@ Init for main Flow-Control XBlock """ from .flow import FlowCheckPointXblock -__version__ = '1.0.1' +__version__ = '2.0.0' diff --git a/flow_control/apps.py b/flow_control/apps.py new file mode 100644 index 0000000..3c4870c --- /dev/null +++ b/flow_control/apps.py @@ -0,0 +1,27 @@ +""" +Flow Control Django application initialization. +""" + +from django.apps import AppConfig + + +class FlowControlConfig(AppConfig): + """ + Configuration for the Flow Control Django application. + """ + name = "flow_control" + + plugin_app = { + "settings_config": { + "lms.djangoapp": { + "common": {"relative_path": "settings.common"}, + "test": {"relative_path": "settings.test"}, + "production": {"relative_path": "settings.production"}, + }, + "cms.djangoapp": { + "common": {"relative_path": "settings.common"}, + "test": {"relative_path": "settings.test"}, + "production": {"relative_path": "settings.production"}, + }, + } + } diff --git a/flow_control/edxapp_wrapper/__init__.py b/flow_control/edxapp_wrapper/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/flow_control/edxapp_wrapper/backends/__init__.py b/flow_control/edxapp_wrapper/backends/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/flow_control/edxapp_wrapper/backends/score_s_v1.py b/flow_control/edxapp_wrapper/backends/score_s_v1.py new file mode 100644 index 0000000..b2863bc --- /dev/null +++ b/flow_control/edxapp_wrapper/backends/score_s_v1.py @@ -0,0 +1,15 @@ +""" +Score module definitions for Open edX Sumac release. +""" +# pylint: disable=import-error +from lms.djangoapps.courseware.model_data import ScoresClient + + +def get_score_module(*args, **kwargs): + """ + Get ScoresClient model. + + Returns: + ScoresClient: ScoresClient object. + """ + return ScoresClient(*args, **kwargs) diff --git a/flow_control/edxapp_wrapper/score.py b/flow_control/edxapp_wrapper/score.py new file mode 100644 index 0000000..93fac50 --- /dev/null +++ b/flow_control/edxapp_wrapper/score.py @@ -0,0 +1,18 @@ +""" +Score module generalized definitions. +""" + +from importlib import import_module +from django.conf import settings + + +def get_score_module_function(*args, **kwargs): + """Get ScoreModule model.""" + + backend_function = settings.FLOW_CONTROL_SCORE_MODULE_BACKEND + backend = import_module(backend_function) + + return backend.get_score_module(*args, **kwargs) + + +score_module = get_score_module_function diff --git a/flow_control/flow.py b/flow_control/flow.py index a831826..4162f46 100644 --- a/flow_control/flow.py +++ b/flow_control/flow.py @@ -12,10 +12,9 @@ from xblockutils.studio_editable import StudioEditableXBlockMixin from xblock.validation import ValidationMessage -try: - from lms.djangoapps.courseware.model_data import ScoresClient -except ImportError: - from courseware.model_data import ScoresClient +from flow_control.edxapp_wrapper.score import ( + score_module as ScoresClient, +) from opaque_keys.edx.keys import UsageKey from opaque_keys import InvalidKeyError @@ -38,8 +37,6 @@ def _actions_generator(block): # pylint: disable=unused-argument "value": "display_message"}, {"display_name": "Redirect using jump_to_id", "value": "to_jump"}, - {"display_name": "Redirect to a given unit in the same subsection", - "value": "to_unit"}, {"display_name": "Redirect to a given URL", "value": "to_url"} ] @@ -129,17 +126,13 @@ class FlowCheckPointXblock(StudioEditableXBlockMixin, XBlock): scope=Scope.content, display_name="Score percentage") - tab_to = Integer(help="Number of unit tab to redirect to. (1, 2, 3...)", - default=1, - scope=Scope.content, - display_name="Tab to redirect to") - target_url = String(help="URL to redirect to, supports relative " "or absolute urls", scope=Scope.content, display_name="URL to redirect to") - target_id = String(help="Unit identifier to redirect to (Location id)", + target_id = String(help="Unit identifier to redirect to (Location id). " + "Use this action to redirect to any course unit.", scope=Scope.content, display_name="Unit identifier to redirect to") @@ -175,27 +168,10 @@ class FlowCheckPointXblock(StudioEditableXBlockMixin, XBlock): 'operator', 'ref_value', 'action', - 'tab_to', 'target_url', 'target_id', 'message') - def validate_field_data(self, validation, data): - """ - Validate this block's field data - """ - - if data.tab_to <= 0: - validation.add(ValidationMessage( - ValidationMessage.ERROR, - u"Tab to redirect to must be greater than zero")) - - if data.ref_value < 0 or data.ref_value > 100: - validation.add(ValidationMessage( - ValidationMessage.ERROR, - u"Score percentage field must " - u"be an integer number between 0 and 100")) - def get_location_string(self, locator, is_draft=False): """ Returns the location string for one problem, given its id """ # pylint: disable=no-member @@ -253,13 +229,10 @@ def student_view(self, context=None): # pylint: disable=unused-argument # pylint: disable=no-member in_studio_runtime = hasattr(self.xmodule_runtime, 'is_author_mode') index_base = 1 - default_tab = 'tab_{}'.format(self.tab_to - index_base) fragment.initialize_js( 'FlowControlGoto', json_args={"display_name": self.display_name, - "default": default_tab, - "default_tab_id": self.tab_to, "action": self.action, "target_url": self.target_url, "target_id": self.target_id, diff --git a/flow_control/settings/__init__.py b/flow_control/settings/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/flow_control/settings/common.py b/flow_control/settings/common.py new file mode 100644 index 0000000..c637f16 --- /dev/null +++ b/flow_control/settings/common.py @@ -0,0 +1,10 @@ +""" +Settings for the Flow Control plugin. +""" + + +def plugin_settings(settings): + """ + Read / Update necessary common project settings. + """ + settings.FLOW_CONTROL_SCORE_MODULE_BACKEND = 'flow_control.edxapp_wrapper.backends.score_s_v1' diff --git a/flow_control/settings/production.py b/flow_control/settings/production.py new file mode 100644 index 0000000..5cdbbc7 --- /dev/null +++ b/flow_control/settings/production.py @@ -0,0 +1,13 @@ +""" +Settings for the Flow Control plugin. +""" + + +def plugin_settings(settings): + """ + Read / Update necessary project settings for production envs. + """ + settings.FLOW_CONTROL_SCORE_MODULE_BACKEND = getattr(settings, "ENV_TOKENS", {}).get( + "FLOW_CONTROL_SCORE_MODULE_BACKEND", + settings.FLOW_CONTROL_SCORE_MODULE_BACKEND + ) diff --git a/flow_control/settings/test.py b/flow_control/settings/test.py new file mode 100644 index 0000000..7930287 --- /dev/null +++ b/flow_control/settings/test.py @@ -0,0 +1,56 @@ +""" +Django settings for flow_control project. +For more information on this file, see +https://docs.djangoproject.com/en/2.2/topics/settings/ +For the full list of settings and their values, see +https://docs.djangoproject.com/en/2.2/ref/settings/ +""" + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": "default.db", + "USER": "", + "PASSWORD": "", + "HOST": "", + "PORT": "", + }, + "read_replica": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": "read_replica.db", + "USER": "", + "PASSWORD": "", + "HOST": "", + "PORT": "", + }, +} + +SECRET_KEY = "not-so-secret-key" + +# Application definition + +INSTALLED_APPS = ( + 'flow_control', +) + +# Internationalization +# https://docs.djangoproject.com/en/2.2/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/2.2/howto/static-files/ + +STATIC_URL = '/static/' + +# Plugin settings +FLOW_CONTROL_SCORE_MODULE_BACKEND = 'flow_control.edxapp_wrapper.backends.score_s_v1' diff --git a/flow_control/static/js/injection.js b/flow_control/static/js/injection.js index e031f7f..386ec99 100644 --- a/flow_control/static/js/injection.js +++ b/flow_control/static/js/injection.js @@ -1,12 +1,8 @@ var settings = { - timeToCheck: 1, - tabTogo: null, - defaulTabId: null, defaultAction: 1, targetUrl: null, targetId: null, - lmsBaseJumpUrl: '../../../jump_to_id/', message: null, conditionReached: null, inStudioRuntime: false @@ -14,7 +10,6 @@ var settings = { var actions = { noAct: 'No action', - redirectTab: 'to_unit', redirectUrl: 'to_url', redirectJump: 'to_jump', show_message: 'display_message' @@ -44,7 +39,8 @@ var uiSelectors = { }; var viewblocks = { - seqContent: $('#seq_content'), + seqContent: $('#course-content'), + loadingMessageHtml: "

Loading, please wait...

", hideNotAllowedOption: function hideNotAllowedOption() { $(uiSelectors.settingsFields).hide(); $(uiSelectors.settingsFields).filter('[data-field-name="condition"]').show(); @@ -52,9 +48,6 @@ var viewblocks = { $(uiSelectors.settingsFields).filter('[data-field-name="operator"]').show(); switch ($(uiSelectors.action).val()) { - case actions.redirectTab: - $(uiSelectors.settingsFields).filter('[data-field-name="tab_to"]').show(); - break; case actions.redirectUrl: $(uiSelectors.settingsFields).filter('[data-field-name="target_url"]').show(); break; @@ -89,19 +82,13 @@ var viewblocks = { switch (settings.defaultAction) { case actions.noAct: break; - case actions.redirectTab: - viewblocks.seqContent.empty(); - window.flowControlTimeoutID = window.setTimeout(redirectToTab, - settings.timeToCheck, - settings.tabTogo); - break; case actions.redirectUrl: - viewblocks.seqContent.empty(); - location.href = settings.targetUrl; + viewblocks.seqContent.html(viewblocks.loadingMessageHtml); + window.parent.location.href = settings.targetUrl; break; case actions.redirectJump: - viewblocks.seqContent.empty(); - location.href = settings.targetId; + viewblocks.seqContent.html(viewblocks.loadingMessageHtml); + window.parent.location.href = getJumpToIdUrl(settings.targetId); break; case actions.show_message: viewblocks.seqContent.html(settings.message); @@ -111,59 +98,11 @@ var viewblocks = { } }; -var getActiveTab = function getActiveTab() { - // return the active sequential button - $tab = $('#course-content #sequence-list button.active')[0]; - - return $tab; -}; - -var execControl = function execControl(arg) { - // Find the target tab - var $target = $('#sequence-list button').filter(function filterFunc() { - return $(this).attr('id') === arg; - }); - - // Do the action - $target.click(); - // TODO: can we make this silent. E.g. that it does not post to /handler/xmodule_handler/goto_position -}; - -var redirectToTab = function redirectToTab(arg) { - var $activeTab = getActiveTab(); - var currentID = $activeTab.id; - var allTabs = $('#sequence-list button'); - var firstTabIndex = 0; - var firstTab = 'tab_' + firstTabIndex; - var lastTabIndex = allTabs.length - 1; - var lastTab = 'tab_' + lastTabIndex; - - if (currentID === arg) { - window.clearTimeout(window.flowControlTimeoutID); - } else { - var whereTo = null; - if (settings.defaulTabId > lastTabIndex) { - whereTo = lastTab; - } - if (settings.defaulTabId < firstTabIndex) { - whereTo = firstTab; - } - if (firstTabIndex <= settings.defaulTabId && settings.defaulTabId <= lastTabIndex) { - whereTo = arg; - } - - execControl(whereTo); - window.flowControlTimeoutID = window.setTimeout(redirectToTab, settings.timeToCheck, whereTo); - } -}; - function FlowControlGoto(runtime, element, options) { // Getting settings varibales to apply flow control - settings.tabTogo = options.default; settings.defaultAction = options.action; settings.targetUrl = options.target_url; - settings.targetId = settings.lmsBaseJumpUrl + options.target_id; - settings.defaulTabId = options.default_tab_id; + settings.targetId = options.target_id; settings.message = options.message; settings.inStudioRuntime = options.in_studio_runtime; @@ -202,3 +141,16 @@ function StudioFlowControl(runtime, element) { $(uiSelectors.visibility).hide(); $(uiSelectors.duplicate).hide(); } + +function getCourseIdByUrl() { + const regex = /(?:block-v1:)(.+)(?:\+type)/; + const result = window.location.href.match(regex); + if (result) { + return result[1]; + } + return null; +} + +function getJumpToIdUrl(id) { + return `${window.location.origin}/courses/course-v1:${getCourseIdByUrl()}/jump_to_id/${id}`; +} diff --git a/flow_control/tests/test_flowcontrol.py b/flow_control/tests/test_flowcontrol.py index 3e1d5a7..74cc773 100644 --- a/flow_control/tests/test_flowcontrol.py +++ b/flow_control/tests/test_flowcontrol.py @@ -39,8 +39,6 @@ def test_actions_generator(self): "value": "display_message"}, {"display_name": "Redirect using jump_to_id", "value": "to_jump"}, - {"display_name": "Redirect to a given unit in the same subsection", - "value": "to_unit"}, {"display_name": "Redirect to a given URL", "value": "to_url"} ] diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..598f7cb --- /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", "flow_control.settings.test") + 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 + 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/requirements/base.txt b/requirements/base.txt index 5cace40..ec45102 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -1,28 +1,97 @@ # -# This file is autogenerated by pip-compile -# To update, run: +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: # # make upgrade # -appdirs==1.4.4 # via fs -django==2.2.13 # via -c requirements/constraints.txt, edx-opaque-keys -edx-opaque-keys[django]==2.0.2 # via -c requirements/constraints.txt, -r requirements/base.in -fs==2.4.11 # via xblock -lxml==4.5.1 # via xblock -mako==1.1.3 # via xblock-utils -markupsafe==1.1.1 # via mako, xblock -pbr==5.4.5 # via stevedore -pymongo==3.10.1 # via edx-opaque-keys -python-dateutil==2.8.1 # via xblock -pytz==2020.1 # via django, fs, xblock -pyyaml==5.3.1 # via xblock -six==1.15.0 # via edx-opaque-keys, fs, python-dateutil, stevedore, xblock -sqlparse==0.3.1 # via django -stevedore==1.32.0 # via -c requirements/constraints.txt, edx-opaque-keys -web-fragments==0.3.2 # via xblock -webob==1.8.6 # via xblock -xblock-utils==1.2.0 # via -c requirements/constraints.txt, -r requirements/base.in -xblock==1.2.2 # via -c requirements/constraints.txt, -r requirements/base.in, xblock-utils +appdirs==1.4.4 + # via fs +asgiref==3.8.1 + # via django +boto3==1.36.4 + # via fs-s3fs +botocore==1.36.4 + # via + # boto3 + # s3transfer +django==4.2.18 + # via + # -c https://raw.githubusercontent.com/edx/edx-lint/master/edx_lint/files/common_constraints.txt + # openedx-django-pyfs +dnspython==2.7.0 + # via pymongo +edx-opaque-keys[django]==2.11.0 + # via -r requirements/base.in +fs==2.4.16 + # via + # fs-s3fs + # openedx-django-pyfs + # xblock +fs-s3fs==1.1.1 + # via openedx-django-pyfs +jmespath==1.0.1 + # via + # boto3 + # botocore +lazy==1.6 + # via xblock +lxml==5.3.0 + # via xblock +mako==1.3.8 + # via + # xblock + # xblock-utils +markupsafe==3.0.2 + # via + # mako + # xblock +openedx-django-pyfs==3.7.0 + # via xblock +pbr==6.1.0 + # via stevedore +pymongo==4.10.1 + # via edx-opaque-keys +python-dateutil==2.9.0.post0 + # via + # botocore + # xblock +pytz==2024.2 + # via xblock +pyyaml==6.0.2 + # via xblock +s3transfer==0.11.1 + # via boto3 +simplejson==3.19.3 + # via + # xblock + # xblock-utils +six==1.17.0 + # via + # fs + # fs-s3fs + # python-dateutil +sqlparse==0.5.3 + # via django +stevedore==5.4.0 + # via edx-opaque-keys +typing-extensions==4.12.2 + # via edx-opaque-keys +urllib3==2.2.3 + # via + # -c https://raw.githubusercontent.com/edx/edx-lint/master/edx_lint/files/common_constraints.txt + # botocore +web-fragments==2.2.0 + # via + # xblock + # xblock-utils +webob==1.8.9 + # via xblock +xblock[django]==5.1.1 + # via + # -r requirements/base.in + # xblock-utils +xblock-utils==4.0.0 + # via -r requirements/base.in # The following packages are considered to be unsafe in a requirements file: # setuptools diff --git a/requirements/ci.in b/requirements/ci.in new file mode 100644 index 0000000..38983d4 --- /dev/null +++ b/requirements/ci.in @@ -0,0 +1,7 @@ +# Requirements for running tests in CI + +-c constraints.txt + +tox # Virtualenv management for tests +tox-battery # Makes tox aware of requirements file changes +twine # Uploads to PyPI diff --git a/requirements/ci.txt b/requirements/ci.txt new file mode 100644 index 0000000..1eeb651 --- /dev/null +++ b/requirements/ci.txt @@ -0,0 +1,105 @@ +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# make upgrade +# +backports-tarfile==1.2.0 + # via jaraco-context +certifi==2024.12.14 + # via requests +cffi==1.17.1 + # via cryptography +charset-normalizer==3.4.1 + # via requests +cryptography==44.0.0 + # via secretstorage +distlib==0.3.9 + # via virtualenv +docutils==0.21.2 + # via readme-renderer +filelock==3.17.0 + # via + # tox + # virtualenv +id==1.5.0 + # via twine +idna==3.10 + # via requests +importlib-metadata==8.6.1 + # via keyring +jaraco-classes==3.4.0 + # via keyring +jaraco-context==6.0.1 + # via keyring +jaraco-functools==4.1.0 + # via keyring +jeepney==0.8.0 + # via + # keyring + # secretstorage +keyring==25.6.0 + # via twine +markdown-it-py==3.0.0 + # via rich +mdurl==0.1.2 + # via markdown-it-py +more-itertools==10.6.0 + # via + # jaraco-classes + # jaraco-functools +nh3==0.2.20 + # via readme-renderer +packaging==24.2 + # via + # pyproject-api + # tox + # twine +platformdirs==4.3.6 + # via + # tox + # virtualenv +pluggy==1.5.0 + # via tox +py==1.11.0 + # via tox +pycparser==2.22 + # via cffi +pygments==2.19.1 + # via + # readme-renderer + # rich +readme-renderer==44.0 + # via twine +requests==2.32.3 + # via + # id + # requests-toolbelt + # twine +requests-toolbelt==1.0.0 + # via twine +rfc3986==2.0.0 + # via twine +rich==13.9.4 + # via twine +secretstorage==3.3.3 + # via keyring +six==1.17.0 + # via tox +tox==3.28.0 + # via + # -r requirements/ci.in + # tox-battery +tox-battery==0.6.2 + # via -r requirements/ci.in +twine==6.1.0 + # via -r requirements/ci.in +urllib3==2.2.3 + # via + # -c https://raw.githubusercontent.com/edx/edx-lint/master/edx_lint/files/common_constraints.txt + # requests + # twine +virtualenv==20.29.1 + # via tox +zipp==3.21.0 + # via importlib-metadata diff --git a/requirements/constraints.txt b/requirements/constraints.txt index 6394bac..a569aac 100644 --- a/requirements/constraints.txt +++ b/requirements/constraints.txt @@ -8,21 +8,6 @@ # pin when possible. Writing an issue against the offending project and # linking to it here is good. -# Last Djagno version compatible with Juniper -django<2.3 - -# Fetches last opaque-keys version compatible with django 1.11 -edx-opaque-keys<2.1.0 - -# Testing mock tool compatible with Juniper -mock==1.0.1 - -# stevedore 2.0.0 requires python >= 3.6 -stevedore<2.0.0 - -# XBlock version compatible with Juniper -xblock==1.2.2 - -# Utilities compatible with Juniper -xblock-utils==1.2.0 +# Common constraints for edx repos +-c https://raw.githubusercontent.com/edx/edx-lint/master/edx_lint/files/common_constraints.txt \ No newline at end of file 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..62016f7 --- /dev/null +++ b/requirements/dev.txt @@ -0,0 +1,252 @@ +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# make upgrade +# +asgiref==3.8.1 + # via django +astroid==3.3.8 + # via + # -r requirements/quality.txt + # pylint +backports-tarfile==1.2.0 + # via + # -r requirements/ci.txt + # jaraco-context +build==1.2.2.post1 + # via + # -r requirements/pip-tools.txt + # pip-tools +certifi==2024.12.14 + # via + # -r requirements/ci.txt + # requests +cffi==1.17.1 + # via + # -r requirements/ci.txt + # cryptography +chardet==5.2.0 + # via diff-cover +charset-normalizer==3.4.1 + # via + # -r requirements/ci.txt + # requests +click==8.1.8 + # via + # -r requirements/pip-tools.txt + # pip-tools +coverage==7.6.10 + # via -r requirements/quality.txt +cryptography==44.0.0 + # via + # -r requirements/ci.txt + # secretstorage +diff-cover==9.2.1 + # via -r requirements/dev.in +dill==0.3.9 + # via + # -r requirements/quality.txt + # pylint +distlib==0.3.9 + # via + # -r requirements/ci.txt + # virtualenv +django==4.2.18 + # via + # -c https://raw.githubusercontent.com/edx/edx-lint/master/edx_lint/files/common_constraints.txt + # edx-i18n-tools +docutils==0.21.2 + # via + # -r requirements/ci.txt + # readme-renderer +edx-i18n-tools==1.6.3 + # via -r requirements/dev.in +filelock==3.17.0 + # via + # -r requirements/ci.txt + # tox + # virtualenv +id==1.5.0 + # via + # -r requirements/ci.txt + # twine +idna==3.10 + # via + # -r requirements/ci.txt + # requests +importlib-metadata==8.6.1 + # via + # -r requirements/ci.txt + # keyring +isort==5.13.2 + # via + # -r requirements/quality.txt + # pylint +jaraco-classes==3.4.0 + # via + # -r requirements/ci.txt + # keyring +jaraco-context==6.0.1 + # via + # -r requirements/ci.txt + # keyring +jaraco-functools==4.1.0 + # via + # -r requirements/ci.txt + # keyring +jeepney==0.8.0 + # via + # -r requirements/ci.txt + # keyring + # secretstorage +jinja2==3.1.5 + # via diff-cover +keyring==25.6.0 + # via + # -r requirements/ci.txt + # twine +lxml[html-clean,html_clean]==5.3.0 + # via + # edx-i18n-tools + # lxml-html-clean +lxml-html-clean==0.4.1 + # via lxml +markdown-it-py==3.0.0 + # via + # -r requirements/ci.txt + # rich +markupsafe==3.0.2 + # via jinja2 +mccabe==0.7.0 + # via + # -r requirements/quality.txt + # pylint +mdurl==0.1.2 + # via + # -r requirements/ci.txt + # markdown-it-py +more-itertools==10.6.0 + # via + # -r requirements/ci.txt + # jaraco-classes + # jaraco-functools +nh3==0.2.20 + # via + # -r requirements/ci.txt + # readme-renderer +packaging==24.2 + # via + # -r requirements/ci.txt + # -r requirements/pip-tools.txt + # build + # tox + # twine +path==16.16.0 + # via edx-i18n-tools +pep8==1.7.1 + # via -r requirements/quality.txt +pip-tools==7.4.1 + # via -r requirements/pip-tools.txt +platformdirs==4.3.6 + # via + # -r requirements/ci.txt + # -r requirements/quality.txt + # pylint + # virtualenv +pluggy==1.5.0 + # via + # -r requirements/ci.txt + # diff-cover + # tox +polib==1.2.0 + # via edx-i18n-tools +py==1.11.0 + # via + # -r requirements/ci.txt + # tox +pycparser==2.22 + # via + # -r requirements/ci.txt + # cffi +pygments==2.19.1 + # via + # -r requirements/ci.txt + # diff-cover + # readme-renderer + # rich +pylint==3.3.3 + # via -r requirements/quality.txt +pyproject-hooks==1.2.0 + # via + # -r requirements/pip-tools.txt + # build + # pip-tools +pyyaml==6.0.2 + # via edx-i18n-tools +readme-renderer==44.0 + # via + # -r requirements/ci.txt + # twine +requests==2.32.3 + # via + # -r requirements/ci.txt + # id + # requests-toolbelt + # twine +requests-toolbelt==1.0.0 + # via + # -r requirements/ci.txt + # twine +rfc3986==2.0.0 + # via + # -r requirements/ci.txt + # twine +rich==13.9.4 + # via + # -r requirements/ci.txt + # twine +secretstorage==3.3.3 + # via + # -r requirements/ci.txt + # keyring +six==1.17.0 + # via + # -r requirements/ci.txt + # tox +sqlparse==0.5.3 + # via django +tomlkit==0.13.2 + # via + # -r requirements/quality.txt + # pylint +tox==3.28.0 + # via + # -r requirements/ci.txt + # tox-battery +tox-battery==0.6.2 + # via -r requirements/ci.txt +twine==6.1.0 + # via -r requirements/ci.txt +urllib3==2.2.3 + # via + # -c https://raw.githubusercontent.com/edx/edx-lint/master/edx_lint/files/common_constraints.txt + # -r requirements/ci.txt + # requests + # twine +virtualenv==20.29.1 + # via + # -r requirements/ci.txt + # tox +wheel==0.45.1 + # via + # -r requirements/pip-tools.txt + # pip-tools +zipp==3.21.0 + # via + # -r requirements/ci.txt + # importlib-metadata + +# The following packages are considered to be unsafe in a requirements file: +# pip +# setuptools diff --git a/requirements/pip-tools.txt b/requirements/pip-tools.txt index 1ae2c19..5461e43 100644 --- a/requirements/pip-tools.txt +++ b/requirements/pip-tools.txt @@ -1,12 +1,24 @@ # -# This file is autogenerated by pip-compile -# To update, run: +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: # # make upgrade # -click==7.1.2 # via pip-tools -pip-tools==5.2.1 # via -r requirements/pip-tools.in -six==1.15.0 # via pip-tools +build==1.2.2.post1 + # via pip-tools +click==8.1.8 + # via pip-tools +packaging==24.2 + # via build +pip-tools==7.4.1 + # via -r requirements/pip-tools.in +pyproject-hooks==1.2.0 + # via + # build + # pip-tools +wheel==0.45.1 + # via pip-tools # 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..e6c3348 --- /dev/null +++ b/requirements/pip.txt @@ -0,0 +1,16 @@ +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# make upgrade +# +wheel==0.45.1 + # via -r requirements/pip.in + +# The following packages are considered to be unsafe in a requirements file: +pip==24.2 + # via + # -c https://raw.githubusercontent.com/edx/edx-lint/master/edx_lint/files/common_constraints.txt + # -r requirements/pip.in +setuptools==75.8.0 + # via -r requirements/pip.in diff --git a/requirements/quality.txt b/requirements/quality.txt index c78c147..c5b79b0 100644 --- a/requirements/quality.txt +++ b/requirements/quality.txt @@ -1,16 +1,24 @@ # -# This file is autogenerated by pip-compile -# To update, run: +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: # # make upgrade # -astroid==2.4.2 # via pylint -coverage==5.1 # via -r requirements/quality.in -isort==4.3.21 # via pylint -lazy-object-proxy==1.4.3 # via astroid -mccabe==0.6.1 # via pylint -pep8==1.7.1 # via -r requirements/quality.in -pylint==2.5.3 # via -r requirements/quality.in -six==1.15.0 # via astroid -toml==0.10.1 # via pylint -wrapt==1.12.1 # via astroid +astroid==3.3.8 + # via pylint +coverage==7.6.10 + # via -r requirements/quality.in +dill==0.3.9 + # via pylint +isort==5.13.2 + # via pylint +mccabe==0.7.0 + # via pylint +pep8==1.7.1 + # via -r requirements/quality.in +platformdirs==4.3.6 + # via pylint +pylint==3.3.3 + # via -r requirements/quality.in +tomlkit==0.13.2 + # via pylint diff --git a/requirements/test.in b/requirements/test.in index 1aa1f9e..0e0d31c 100644 --- a/requirements/test.in +++ b/requirements/test.in @@ -10,7 +10,7 @@ pytest # mako==1.0.2 # Language for server-side page rendering. More tests should be added # eduNEXT mock project for couserware.model_data --e git+https://github.com/edunext/mock-courseware-model_data.git@30409f54e2d51b3dbdd028597e0a28bdeb9d0455#egg=dev +# -e git+https://github.com/edunext/mock-courseware-model_data.git@30409f54e2d51b3dbdd028597e0a28bdeb9d0455#egg=dev # XBlock SDK to access Django Workbench Settings # -e git+https://github.com/edx/xblock-sdk.git@21dac6a88fad2cf6d5588b0ee5a1e7c7d3b591fc#egg=xblock-sdk==0.1.6 diff --git a/requirements/test.txt b/requirements/test.txt index 9ef6cf3..caba2ca 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -1,39 +1,109 @@ # -# This file is autogenerated by pip-compile -# To update, run: +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: # # make upgrade # --e git+https://github.com/edunext/mock-courseware-model_data.git@30409f54e2d51b3dbdd028597e0a28bdeb9d0455#egg=dev # via -r requirements/test.in -appdirs==1.4.4 # via fs -attrs==19.3.0 # via pytest -ddt==1.4.1 # via -r requirements/test.in -django==2.2.13 # via -c requirements/constraints.txt, edx-opaque-keys -edx-opaque-keys[django]==2.0.2 # via -c requirements/constraints.txt, -r requirements/base.in -fs==2.4.11 # via xblock -lxml==4.5.1 # via xblock -mako==1.1.3 # via xblock-utils -markupsafe==1.1.1 # via mako, xblock -mock==1.0.1 # via -c requirements/constraints.txt, -r requirements/test.in -more-itertools==8.4.0 # via pytest -packaging==20.4 # via pytest -pbr==5.4.5 # via stevedore -pluggy==0.13.1 # via pytest -py==1.8.2 # via pytest -pymongo==3.10.1 # via edx-opaque-keys -pyparsing==2.4.7 # via packaging -pytest==5.4.3 # via -r requirements/test.in -python-dateutil==2.8.1 # via xblock -pytz==2020.1 # via django, fs, xblock -pyyaml==5.3.1 # via xblock -six==1.15.0 # via edx-opaque-keys, fs, packaging, python-dateutil, stevedore, xblock -sqlparse==0.3.1 # via django -stevedore==1.32.0 # via -c requirements/constraints.txt, edx-opaque-keys -wcwidth==0.2.4 # via pytest -web-fragments==0.3.2 # via xblock -webob==1.8.6 # via xblock -xblock-utils==1.2.0 # via -c requirements/constraints.txt, -r requirements/base.in -xblock==1.2.2 # via -c requirements/constraints.txt, -r requirements/base.in, xblock-utils +appdirs==1.4.4 + # via fs +asgiref==3.8.1 + # via django +boto3==1.36.4 + # via fs-s3fs +botocore==1.36.4 + # via + # boto3 + # s3transfer +ddt==1.7.2 + # via -r requirements/test.in +django==4.2.18 + # via + # -c https://raw.githubusercontent.com/edx/edx-lint/master/edx_lint/files/common_constraints.txt + # openedx-django-pyfs +dnspython==2.7.0 + # via pymongo +edx-opaque-keys[django]==2.11.0 + # via -r requirements/base.in +fs==2.4.16 + # via + # fs-s3fs + # openedx-django-pyfs + # xblock +fs-s3fs==1.1.1 + # via openedx-django-pyfs +iniconfig==2.0.0 + # via pytest +jmespath==1.0.1 + # via + # boto3 + # botocore +lazy==1.6 + # via xblock +lxml==5.3.0 + # via xblock +mako==1.3.8 + # via + # xblock + # xblock-utils +markupsafe==3.0.2 + # via + # mako + # xblock +mock==5.1.0 + # via -r requirements/test.in +openedx-django-pyfs==3.7.0 + # via xblock +packaging==24.2 + # via pytest +pbr==6.1.0 + # via stevedore +pluggy==1.5.0 + # via pytest +pymongo==4.10.1 + # via edx-opaque-keys +pytest==8.3.4 + # via -r requirements/test.in +python-dateutil==2.9.0.post0 + # via + # botocore + # xblock +pytz==2024.2 + # via xblock +pyyaml==6.0.2 + # via xblock +s3transfer==0.11.1 + # via boto3 +simplejson==3.19.3 + # via + # xblock + # xblock-utils +six==1.17.0 + # via + # fs + # fs-s3fs + # python-dateutil +sqlparse==0.5.3 + # via django +stevedore==5.4.0 + # via edx-opaque-keys +typing-extensions==4.12.2 + # via edx-opaque-keys +urllib3==2.2.3 + # via + # -c https://raw.githubusercontent.com/edx/edx-lint/master/edx_lint/files/common_constraints.txt + # botocore +web-fragments==2.2.0 + # via + # xblock + # xblock-utils +webob==1.8.9 + # via xblock +xblock[django]==5.1.1 + # via + # -r requirements/base.in + # xblock-utils +xblock-utils==4.0.0 + # via -r requirements/base.in # The following packages are considered to be unsafe in a requirements file: # setuptools diff --git a/requirements/tox.txt b/requirements/tox.txt index a071464..aebf440 100644 --- a/requirements/tox.txt +++ b/requirements/tox.txt @@ -1,17 +1,34 @@ # -# This file is autogenerated by pip-compile -# To update, run: +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: # # make upgrade # -appdirs==1.4.4 # via virtualenv -distlib==0.3.0 # via virtualenv -filelock==3.0.12 # via tox, virtualenv -packaging==20.4 # via tox -pluggy==0.13.1 # via tox -py==1.8.2 # via tox -pyparsing==2.4.7 # via packaging -six==1.15.0 # via packaging, tox, virtualenv -toml==0.10.1 # via tox -tox==3.15.2 # via -r requirements/tox.in -virtualenv==20.0.23 # via tox +cachetools==5.5.1 + # via tox +chardet==5.2.0 + # via tox +colorama==0.4.6 + # via tox +distlib==0.3.9 + # via virtualenv +filelock==3.17.0 + # via + # tox + # virtualenv +packaging==24.2 + # via + # pyproject-api + # tox +platformdirs==4.3.6 + # via + # tox + # virtualenv +pluggy==1.5.0 + # via tox +pyproject-api==1.9.0 + # via tox +tox==4.24.1 + # via -r requirements/tox.in +virtualenv==20.29.1 + # via tox diff --git a/setup.cfg b/setup.cfg index e0b755c..592dcb8 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 1.0.1 +current_version = 2.0.0 commit = True tag = True diff --git a/setup.py b/setup.py index 122f4e1..91c0904 100644 --- a/setup.py +++ b/setup.py @@ -93,18 +93,17 @@ def load_requirements(*requirements_paths): long_description=long_description, long_description_content_type='text/x-rst', url='https://github.com/eduNEXT/flow-control-xblock', - python_requires=">=3.5.*", + python_requires=">=3.11", packages=find_packages(), classifiers=[ - 'Framework :: Django :: 2.2', + 'Framework :: Django :: 4.2', 'Intended Audience :: Developers', 'Intended Audience :: Education', 'License :: OSI Approved :: GNU Affero General Public License v3', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.11', 'Topic :: Internet', 'Topic :: Internet :: WWW/HTTP', ], @@ -114,6 +113,12 @@ def load_requirements(*requirements_paths): 'xblock.v1': [ 'flow-control = flow_control:FlowCheckPointXblock', ], + 'lms.djangoapp': [ + "flow-control = flow_control.apps:FlowControlConfig", + ], + 'cms.djangoapp': [ + "flow-control = flow_control.apps:FlowControlConfig", + ], }, keywords='edunext xblock flowcontrol flow-control', include_package_data=True, diff --git a/tox.ini b/tox.ini index cc838e3..32d73ff 100644 --- a/tox.ini +++ b/tox.ini @@ -1,15 +1,17 @@ # testing with tox [tox] -envlist = py35, py38 +envlist = py311-django{42} +skipsdist = true [testenv] -deps = +DJANGO_SETTINGS_MODULE = flow_control.settings.test +deps = + django42: Django>=4.2,<5.0 -r {toxinidir}/requirements/test.txt -setenv = - DJANGO_SETTINGS_MODULE = workbench.settings commands = pytest [pytest] +DJANGO_SETTINGS_MODULE = flow_control.settings.test python_files = test_*.py commands = pytest