diff --git a/CHANGELOG.md b/CHANGELOG.md index f0146df..1101120 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,22 @@ instructions, because git commits are used to generate release notes: + +## v17.0.2 (2024-02-09) + +- [Feature] Several enhancements to the Demo Course (by @kdmccormick): + - The [Open edX Demo Course](https://github.com/openedx/openedx-demo-course) has been re-built from scratch with up-to-date instruction-focused content. Its directory structure has changed. + - In order to support both the old and new structures of the Demo Course's repository, the command `tutor local do importdemocourse` will now auto-determine the course root based on the location of `course.xml`. Use the `--repo-dir` argument to override this behavior. + - The new command `tutor local do importdemolibraries` will import any content libraries defined within the Demo Course repository. At the moment, that is just the "Respiratory System Question Bank", which is an optional but helpful extension to the new Demo Course. + - To try out the new Demo Course now, run: `tutor local do importdemocourse --version master`. + - To try out the demo Respiratory System Question Bank now, run: `tutor local do importdemolibraries --version master`. + - To revert back to an older Demo Course version at any point, run: `tutor local do importdemocourse --version open-release/quince.2`, replacing `quince.2` with your preferred course version. +- [Bugfix] Remove duplicate volume declarations that cause `docker compose` v2.24.1 to fail. +- [Bugfix] Actually update the environment on `tutor plugins enable ...`. (by @regisb) +- [Feature] Introduce a `tutor.hooks.lru_cache` decorator that is automatically cleared whenever a plugin is loaded or unloaded. This is useful, in particular when a plugin implements a costly function that depends on tutor hooks. (by @regisb) +- [Bugfix] Fix compatibility with Python 3.12 by replacing pkg_resources with importlib_metadata and importlib_resources. (by @Danyal-Faheem) +- [Improvement] Upgrade base release to open-release/quince.2. (by @regisb) + ## v17.0.1 (2024-01-25) diff --git a/changelog.d/20240110_101228_kyle_importnewdemocourse.md b/changelog.d/20240110_101228_kyle_importnewdemocourse.md deleted file mode 100644 index 79a7d44..0000000 --- a/changelog.d/20240110_101228_kyle_importnewdemocourse.md +++ /dev/null @@ -1,7 +0,0 @@ -- [Feature] Several enhancements to the Demo Course (by @kdmccormick): - - The [Open edX Demo Course](https://github.com/openedx/openedx-demo-course) has been re-built from scratch with up-to-date instruction-focused content. Its directory structure has changed. - - In order to support both the old and new structures of the Demo Course's repository, the command `tutor local do importdemocourse` will now auto-determine the course root based on the location of `course.xml`. Use the `--repo-dir` argument to override this behavior. - - The new command `tutor local do importdemolibraries` will import any content libraries defined within the Demo Course repository. At the moment, that is just the "Respiratory System Question Bank", which is an optional but helpful extension to the new Demo Course. - - To try out the new Demo Course now, run: `tutor local do importdemocourse --version master`. - - To try out the demo Respiratory System Question Bank now, run: `tutor local do importdemolibraries --version master`. - - To revert back to an older Demo Course version at any point, run: `tutor local do importdemocourse --version open-release/quince.2`, replacing `quince.2` with your preferred course version. diff --git a/changelog.d/20240129_144929_kshitij_fix_tutor_docker_compose.md b/changelog.d/20240129_144929_kshitij_fix_tutor_docker_compose.md deleted file mode 100644 index 4a9625c..0000000 --- a/changelog.d/20240129_144929_kshitij_fix_tutor_docker_compose.md +++ /dev/null @@ -1,2 +0,0 @@ -- [Bugfix] Fixes duplicate volume declarations causing Tutor commands that - invoke Docker to fail. \ No newline at end of file diff --git a/changelog.d/20240130_123351_regis_fix_save_on_plugins.md b/changelog.d/20240130_123351_regis_fix_save_on_plugins.md deleted file mode 100644 index 164dd81..0000000 --- a/changelog.d/20240130_123351_regis_fix_save_on_plugins.md +++ /dev/null @@ -1,2 +0,0 @@ -- [Bugfix] Actually update the environment on `tutor plugins enable ...`. (by @regisb) -- [Feature] Introduce a `tutor.hooks.lru_cache` decorator that is automatically cleared whenever a plugin is loaded or unloaded. This is useful, in particular when a plugin implements a costly function that depends on tutor hooks. (by @regisb) diff --git a/requirements/base.in b/requirements/base.in index eb60ad6..21e5098 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -6,3 +6,5 @@ mypy pycryptodome>=3.17.0 pyyaml>=6.0 typing-extensions>=4.4.0 +importlib-metadata>=7.0.1 +importlib-resources>=6.1.1 diff --git a/requirements/base.txt b/requirements/base.txt index 1526e68..37cdb88 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -20,6 +20,10 @@ google-auth==2.23.3 # via kubernetes idna==3.4 # via requests +importlib-metadata==7.0.1 + # via -r requirements/base.in +importlib-resources==6.1.1 + # via -r requirements/base.in jinja2==3.1.3 # via -r requirements/base.in kubernetes==28.1.0 @@ -72,3 +76,7 @@ urllib3==1.26.18 # requests websocket-client==1.6.4 # via kubernetes +zipp==3.17.0 + # via + # importlib-metadata + # importlib-resources diff --git a/requirements/dev.txt b/requirements/dev.txt index 3515973..5c6aba3 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -58,14 +58,17 @@ idna==3.4 # via # -r requirements/base.txt # requests -importlib-metadata==6.8.0 +importlib-metadata==7.0.1 # via + # -r requirements/base.txt # build # keyring # pyinstaller # twine importlib-resources==6.1.1 - # via keyring + # via + # -r requirements/base.txt + # keyring isort==5.12.0 # via pylint jaraco-classes==3.3.0 @@ -232,6 +235,7 @@ wheel==0.41.2 # via pip-tools zipp==3.17.0 # via + # -r requirements/base.txt # importlib-metadata # importlib-resources diff --git a/requirements/docs.txt b/requirements/docs.txt index 8acbfb5..4ca558d 100644 --- a/requirements/docs.txt +++ b/requirements/docs.txt @@ -42,8 +42,12 @@ idna==3.4 # requests imagesize==1.4.1 # via sphinx -importlib-metadata==6.8.0 - # via sphinx +importlib-metadata==7.0.1 + # via + # -r requirements/base.txt + # sphinx +importlib-resources==6.1.1 + # via -r requirements/base.txt jinja2==3.1.3 # via # -r requirements/base.txt @@ -153,4 +157,7 @@ websocket-client==1.6.4 # -r requirements/base.txt # kubernetes zipp==3.17.0 - # via importlib-metadata + # via + # -r requirements/base.txt + # importlib-metadata + # importlib-resources diff --git a/tutor.spec b/tutor.spec index f68c7c0..1e6f591 100644 --- a/tutor.spec +++ b/tutor.spec @@ -1,7 +1,7 @@ # -*- mode: python -*- import importlib import os -import pkg_resources +from importlib_metadata block_cipher = None @@ -10,10 +10,10 @@ hidden_imports = [] # Auto-discover plugins and include patches & templates folders for entrypoint_version in ["tutor.plugin.v0", "tutor.plugin.v1"]: - for entrypoint in pkg_resources.iter_entry_points(entrypoint_version): + for entrypoint in importlib_metadata.entry_points(group=entrypoint_version): plugin_name = entrypoint.name try: - plugin = entrypoint.load() + plugin = importlib.import_module(entrypoint.value) except Exception as e: print(f"ERROR Failed to load plugin {plugin_name}: {e}") continue diff --git a/tutor/__about__.py b/tutor/__about__.py index de71b79..19e0e9e 100644 --- a/tutor/__about__.py +++ b/tutor/__about__.py @@ -2,7 +2,7 @@ import os # Increment this version number to trigger a new release. See # docs/tutor.html#versioning for information on the versioning scheme. -__version__ = "17.0.1" +__version__ = "17.0.2" # The version suffix will be appended to the actual version, separated by a # dash. Use this suffix to differentiate between the actual released version and diff --git a/tutor/env.py b/tutor/env.py index 5e668b8..470f9dc 100644 --- a/tutor/env.py +++ b/tutor/env.py @@ -7,13 +7,13 @@ import typing as t from copy import deepcopy import jinja2 -import pkg_resources +import importlib_resources from tutor import exceptions, fmt, hooks, plugins, utils from tutor.__about__ import __app__, __version__ from tutor.types import Config, ConfigValue -TEMPLATES_ROOT = pkg_resources.resource_filename("tutor", "templates") +TEMPLATES_ROOT = str(importlib_resources.files("tutor") / "templates") VERSION_FILENAME = "version" BIN_FILE_EXTENSIONS = [ ".ico", diff --git a/tutor/plugins/v0.py b/tutor/plugins/v0.py index 16e6770..b1cf0f7 100644 --- a/tutor/plugins/v0.py +++ b/tutor/plugins/v0.py @@ -5,7 +5,7 @@ import typing as t from glob import glob import click -import pkg_resources +import importlib_metadata from tutor import env, exceptions, fmt, hooks, serialize from tutor.__about__ import __app__ @@ -246,12 +246,12 @@ class EntrypointPlugin(BasePlugin): ENTRYPOINT = "tutor.plugin.v0" - def __init__(self, entrypoint: pkg_resources.EntryPoint) -> None: - self.loader: pkg_resources.EntryPoint + def __init__(self, entrypoint: importlib_metadata.EntryPoint) -> None: + self.loader: importlib_metadata.EntryPoint = entrypoint super().__init__(entrypoint.name, entrypoint) def _load_obj(self) -> None: - self.obj = self.loader.load() + self.obj = importlib.import_module(self.loader.value) def _version(self) -> t.Optional[str]: if not self.loader.dist: @@ -260,12 +260,11 @@ class EntrypointPlugin(BasePlugin): @classmethod def discover_all(cls) -> None: - for entrypoint in pkg_resources.iter_entry_points(cls.ENTRYPOINT): + entrypoints = importlib_metadata.entry_points(group=cls.ENTRYPOINT) + for entrypoint in entrypoints: try: error: t.Optional[str] = None cls(entrypoint) - except pkg_resources.VersionConflict as e: - error = e.report() except Exception as e: # pylint: disable=broad-except error = str(e) if error: diff --git a/tutor/plugins/v1.py b/tutor/plugins/v1.py index cf24bf0..88982b6 100644 --- a/tutor/plugins/v1.py +++ b/tutor/plugins/v1.py @@ -2,7 +2,7 @@ import importlib.util import os from glob import glob -import pkg_resources +import importlib_metadata from tutor import hooks @@ -26,7 +26,7 @@ def _discover_entrypoint_plugins() -> None: """ with hooks.Contexts.PLUGINS.enter(): if "TUTOR_IGNORE_ENTRYPOINT_PLUGINS" not in os.environ: - for entrypoint in pkg_resources.iter_entry_points("tutor.plugin.v1"): + for entrypoint in importlib_metadata.entry_points(group="tutor.plugin.v1"): discover_package(entrypoint) @@ -56,7 +56,7 @@ def discover_module(path: str) -> None: spec.loader.exec_module(module) -def discover_package(entrypoint: pkg_resources.EntryPoint) -> None: +def discover_package(entrypoint: importlib_metadata.EntryPoint) -> None: """ Install a plugin from a python package. """ @@ -68,10 +68,11 @@ def discover_package(entrypoint: pkg_resources.EntryPoint) -> None: # Add plugin information if entrypoint.dist is None: raise ValueError(f"Could not read plugin version: {name}") - hooks.Filters.PLUGINS_INFO.add_item((name, entrypoint.dist.version)) + dist_version = entrypoint.dist.version if entrypoint.dist else "Unknown" + hooks.Filters.PLUGINS_INFO.add_item((name, dist_version)) # Import module on enable @hooks.Actions.PLUGIN_LOADED.add() def load(plugin_name: str) -> None: if name == plugin_name: - entrypoint.load() + importlib.import_module(entrypoint.value) diff --git a/tutor/templates/config/defaults.yml b/tutor/templates/config/defaults.yml index d49ce62..ea68b54 100644 --- a/tutor/templates/config/defaults.yml +++ b/tutor/templates/config/defaults.yml @@ -62,7 +62,7 @@ OPENEDX_LMS_UWSGI_WORKERS: 2 OPENEDX_MYSQL_DATABASE: "openedx" OPENEDX_MYSQL_USERNAME: "openedx" # the common version will be automatically set to "master" in the nightly branch -OPENEDX_COMMON_VERSION: "open-release/quince.1" +OPENEDX_COMMON_VERSION: "open-release/quince.2" OPENEDX_EXTRA_PIP_REQUIREMENTS: [] MYSQL_HOST: "mysql" MYSQL_PORT: 3306