diff --git a/.github/workflows/tox.yml b/.github/workflows/tox.yml index f29bd4c..cb1f046 100644 --- a/.github/workflows/tox.yml +++ b/.github/workflows/tox.yml @@ -11,8 +11,6 @@ jobs: matrix: python-version: - '3.8' - - '3.9' - - '3.10' - '3.11' pip-version: - 22.0.4 diff --git a/Changelog.md b/Changelog.md index ff0e51d..8f6bf01 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,7 @@ +Unreleasead +------------------------- +* [Enhancement] Add support for the Open edX Redwood release. + Version 7.11.0 (2024-05-06) ------------------------- * [Enhancement] Update to a newer Twisted version. diff --git a/README.md b/README.md index aed490b..ffa2395 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ repository, you must select the appropriate one: | Olive | `>=15.0, <16` | `>=7.5` | `master` | | Palm | `>=16.0, <17` | `>=7.5` | `master` | | Quince | `>=17.0, <18` | `>=7.9` | `master` | +| Redwood | `>=18.0, <19` | `>=7.10` | `master` | Instructions for deploying this XBlock with Tutor can be found below, in the [Deployment with Tutor](#deployment-with-tutor) diff --git a/hastexo/hastexo.py b/hastexo/hastexo.py index 0d7bf51..0b7cff4 100644 --- a/hastexo/hastexo.py +++ b/hastexo/hastexo.py @@ -8,15 +8,27 @@ from xblock.core import XBlock, XML_NAMESPACES from xblock.fields import Scope, Float, String, Dict, List, Integer, Boolean -from xblock.fragment import Fragment +try: # XBlock 2+ + from web_fragments.fragment import Fragment + from xblock.utils.resources import ResourceLoader + from xblock.utils.settings import XBlockWithSettingsMixin + from xblock.utils.studio_editable import ( + NestedXBlockSpec, + StudioContainerWithNestedXBlocksMixin, + StudioEditableXBlockMixin + ) +except ImportError: # Compatibility with XBlock<2 + from xblock.fragment import Fragment + from xblockutils.resources import ResourceLoader + from xblockutils.settings import XBlockWithSettingsMixin + from xblockutils.studio_editable import ( + NestedXBlockSpec, + StudioContainerWithNestedXBlocksMixin, + StudioEditableXBlockMixin, + ) + from xblock.scorable import ScorableXBlockMixin, Score -from xblockutils.resources import ResourceLoader -from xblockutils.studio_editable import ( - NestedXBlockSpec, - StudioContainerWithNestedXBlocksMixin, - StudioEditableXBlockMixin, -) -from xblockutils.settings import XBlockWithSettingsMixin + from distutils.util import strtobool from django.db import transaction @@ -305,12 +317,22 @@ def parse_attributes(tag, node, block): block.providers.append(provider) @classmethod - def parse_xml(cls, node, runtime, keys, id_generator): + def parse_xml(cls, node, runtime, keys, id_generator=None): """ Use `node` to construct a new block. """ block = runtime.construct_xblock_from_class(cls, keys) + # Prior to XBlock 2.0, id_generator is passed in. + # Since XBlock 2.0, we grab it from the runtime. + # + # TODO: Once we decide to drop support for versions prior to + # XBlock 2 (i.e. Open edX releases before Redwood), we can + # drop id_generator from the method signature, and always rely + # on runtime.id_generator. + if not id_generator: + id_generator = runtime.id_generator + if 'filename' in node.attrib: # Read xml content from file. url_name = node.get('url_name', node.get('slug')) @@ -351,7 +373,16 @@ def parse_xml(cls, node, runtime, keys, id_generator): child.tag)) # Import nested blocks for child in node: - block.runtime.add_node_as_child(block, child, id_generator) + # Prior to XBlock 2.0, id_generator needs to be passed here. + # + # TODO: Once we decide to drop support for versions prior to + # XBlock 2 (i.e. Open edX releases before Redwood), we can + # drop the try/except block and passing the id_generator here. + try: + block.runtime.add_node_as_child(block, child) + except TypeError: + block.runtime.add_node_as_child(block, child, id_generator) + else: for child in node: if child.tag is etree.Comment: @@ -368,7 +399,18 @@ def parse_xml(cls, node, runtime, keys, id_generator): cls.parse_attributes(child.tag, child, block) else: # Import nested blocks - block.runtime.add_node_as_child(block, child, id_generator) + + # Prior to XBlock 2.0, id_generator needs to be passed. + # + # TODO: Once we decide to drop support for versions prior + # to XBlock 2 (i.e. Open edX releases before Redwood), + # we can drop the try/except block here and stop passing + # the id_generator. + try: + block.runtime.add_node_as_child(block, child) + except TypeError: + block.runtime.add_node_as_child( + block, child, id_generator) # Attributes become fields. for name, value in list(node.items()): # lxml has no iteritems @@ -700,7 +742,19 @@ def student_view(self, context=None): for child_id in self.children: child = self.runtime.get_block(child_id) child_fragment = child.render("student_view", context) - frag.add_frag_resources(child_fragment) + + # Prior to XBlock 2.0, Fragment is imported from XBlock + # and we the `add_frag_resources` method. + # + # TODO: Once we decide to drop support for versions prior + # to XBlock 2 (i.e. Open edX releases before Redwood), + # we can drop the try/except block here and use + # `add_fragment_resources` from `web_fragments.Fragment` + try: + frag.add_fragment_resources(child_fragment) + except AttributeError: + frag.add_frag_resources(child_fragment) + child_content += child_fragment.content # Render the main template diff --git a/requirements/base.txt b/requirements/base.txt index 94a47cc..86f2dd4 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -17,10 +17,10 @@ python-novaclient>=7.1.2,<16 tenacity>=6.2,<8 # for hastexo_guacamole_client -django<=4.2.8 +django<=4.2.14 channels<=4.0.0 daphne<=4.0.0 twisted<24 # drop this restriction once we drop Python 3.8 and 3.9 support -mysqlclient<=2.2.1 # keep in sync with edx-platform +mysqlclient<=2.2.4 # keep in sync with edx-platform jsonfield>=3.1.0,<4 # keep in sync with edx-platform pyguacamole>=0.11 diff --git a/requirements/test.txt b/requirements/test.txt index 7d83dc4..100b35c 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -1,7 +1,8 @@ -r base.txt # These package versions must be kept in sync with edx-platform as much as possible. -xblock-utils<=3.0.0 +xblock-sdk<0.9.0;python_version<"3.9" +xblock-sdk;python_version>="3.9" six==1.16.0 lazy<=1.5 django-pyfs==3.1.0 diff --git a/tox.ini b/tox.ini index 9a79071..814fc52 100644 --- a/tox.ini +++ b/tox.ini @@ -1,11 +1,9 @@ [tox] -envlist = flake8,pipdeptree{,-requirements},py{38,39,310,311,312}-xblock{17,18,19}-celery5 +envlist = flake8,pipdeptree{,-requirements},py38-xblock18-celery5,py{311,312}-xblock{40}-celery5 [gh-actions] python = 3.8: flake8,pipdeptree,pipdeptree-requirements,py38 - 3.9: flake8,pipdeptree,pipdeptree-requirements,py39 - 3.10: flake8,pipdeptree,pipdeptree-requirements,py310 3.11: flake8,pipdeptree,pipdeptree-requirements,py311 3.12: flake8,pipdeptree,pipdeptree-requirements,py312 @@ -29,10 +27,8 @@ exclude_lines = deps = -rrequirements/setup.txt -rrequirements/test.txt - xblock-sdk<0.9.0 - xblock17: XBlock>=1.7,<1.8 xblock18: XBlock>=1.8,<1.9 - xblock19: XBlock>=1.9,<2 + xblock40: XBlock>=4.0,<5 celery5: celery>=5,<6 commands = python run_tests.py []