diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a95bf47..52ebe05 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -38,7 +38,7 @@ jobs: # https://github.com/actions/setup-python uses: actions/setup-python@v3 with: - python-version: 3.7 + python-version: 3.8 cache: 'pip' cache-dependency-path: requirements/dev.txt - name: Upgrade pip and setuptools diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bb85882..b7940a4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,11 +14,11 @@ jobs: - name: Set up Python uses: actions/setup-python@v3 with: - python-version: 3.9 + python-version: 3.8 cache: 'pip' cache-dependency-path: requirements/dev.txt - name: Upgrade pip - run: python -m pip install --upgrade pip setuptools==44.0.0 + run: python -m pip install --upgrade pip setuptools - name: Install dependencies run: pip install -r requirements/dev.txt - name: Static code analysis diff --git a/Dockerfile b/Dockerfile index a77d35e..ce3b105 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,7 @@ # Because this image is still experimental, and we are not quite sure if it's going to # be very useful, we do not provide any usage documentation. -FROM docker.io/python:3.7-slim-stretch +FROM docker.io/python:3.8-slim-stretch # As per https://github.com/docker/compose/issues/3918 COPY --from=library/docker:19.03 /usr/local/bin/docker /usr/bin/docker diff --git a/Makefile b/Makefile index 9dbdeb7..b1755a5 100644 --- a/Makefile +++ b/Makefile @@ -91,7 +91,6 @@ bootstrap-dev-plugins: bootstrap-dev ## Install dev requirements and all support pull-base-images: # Manually pull base images docker image pull docker.io/ubuntu:20.04 - docker image pull docker.io/python:3.7-alpine ci-info: ## Print info about environment python --version diff --git a/changelog.d/20230412_100608_regis_palm.md b/changelog.d/20230412_100608_regis_palm.md index 63fb682..6af204d 100644 --- a/changelog.d/20230412_100608_regis_palm.md +++ b/changelog.d/20230412_100608_regis_palm.md @@ -1,3 +1,4 @@ - 💥[Feature] Upgrade to Palm. (by @regisb) - [Bugfix] Rename ORA2 file upload folder from "SET-ME-PLEASE (ex. bucket-name)" to "openedxuploads". This has the effect of moving the corresponding folder from the `/data/lms/ora2` directory. MinIO users were not affected by this bug. - 💥[Improvement] During registration, the honor code and terms of service links are no longer visible by default. For most platforms, these links did not work anyway. (by @regisb) + - 💥[Deprecation] Halt support for Python 3.7. The binary release of Tutor is also no longer compatible with macOS 10. (by @regisb) diff --git a/docs/conf.py b/docs/conf.py index 92f9a54..38fb307 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -35,7 +35,7 @@ autodoc_typehints = "description" # For the life of me I can't get the docs to compile in nitpicky mode without these # ignore statements. You are most welcome to try and remove them. # To make matters worse, some ignores are only required for some versions of Python, -# from 3.7 to 3.10... +# from 3.8 to 3.10... nitpick_ignore = [ # Sphinx does not handle ParamSpec arguments ("py:class", "T.args"), @@ -48,8 +48,6 @@ nitpick_ignore = [ ("py:class", "t.Callable"), ("py:class", "t.Iterator"), ("py:class", "t.Optional"), - # python 3.7 - ("py:class", "Concatenate"), # python 3.10 ("py:class", "NoneType"), ("py:class", "click.core.Command"), @@ -57,8 +55,6 @@ nitpick_ignore = [ # Resolve type aliases here # https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#confval-autodoc_type_aliases autodoc_type_aliases: dict[str, str] = { - "T1": "tutor.core.hooks.filters.T1", - "L": "tutor.core.hooks.filters.L", # python 3.10 "T": "tutor.core.hooks.actions.T", "T2": "tutor.core.hooks.filters.T2", @@ -132,14 +128,12 @@ def youtube( return [ docutils.nodes.raw( "", - """ + f""" """.format( - video_id=video_id - ), +""", format="html", ) ] diff --git a/requirements/base.txt b/requirements/base.txt index b4947ed..fa90477 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.7 +# This file is autogenerated by pip-compile with Python 3.10 # by the following command: # # pip-compile requirements/base.in @@ -20,8 +20,6 @@ google-auth==2.19.1 # via kubernetes idna==3.4 # via requests -importlib-metadata==6.6.0 - # via click jinja2==3.1.2 # via -r requirements/base.in kubernetes==26.1.0 @@ -63,12 +61,9 @@ six==1.16.0 # python-dateutil tomli==2.0.1 # via mypy -typed-ast==1.5.4 - # via mypy typing-extensions==4.6.3 # via # -r requirements/base.in - # importlib-metadata # mypy urllib3==1.26.16 # via @@ -77,8 +72,6 @@ urllib3==1.26.16 # requests websocket-client==1.5.2 # via kubernetes -zipp==3.15.0 - # via importlib-metadata # The following packages are considered to be unsafe in a requirements file: # setuptools diff --git a/requirements/dev.in b/requirements/dev.in index 4c1100d..8dc0c3d 100644 --- a/requirements/dev.in +++ b/requirements/dev.in @@ -9,7 +9,7 @@ twine # doc requirement is lagging behind # https://github.com/readthedocs/sphinx_rtd_theme/issues/1323 -docutils<0.18 +docutils<0.19 # Types packages types-docutils diff --git a/requirements/dev.txt b/requirements/dev.txt index ce33e73..6e1addc 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.7 +# This file is autogenerated by pip-compile with Python 3.10 # by the following command: # # pip-compile requirements/dev.in @@ -48,7 +48,7 @@ cryptography==41.0.1 # via secretstorage dill==0.3.6 # via pylint -docutils==0.17.1 +docutils==0.18.1 # via # -r requirements/dev.in # readme-renderer @@ -62,16 +62,9 @@ idna==3.4 # requests importlib-metadata==6.6.0 # via - # -r requirements/base.txt - # attrs - # build - # click # keyring - # pyinstaller # twine -importlib-resources==5.12.0 - # via keyring -isort==5.11.5 +isort==5.12.0 # via pylint jaraco-classes==3.2.3 # via keyring @@ -206,12 +199,6 @@ tomlkit==0.11.8 # via pylint twine==4.0.2 # via -r requirements/dev.in -typed-ast==1.5.4 - # via - # -r requirements/base.txt - # astroid - # black - # mypy types-docutils==0.20.0.1 # via -r requirements/dev.in types-pyyaml==6.0.12.10 @@ -222,13 +209,7 @@ typing-extensions==4.6.3 # via # -r requirements/base.txt # astroid - # black - # importlib-metadata - # markdown-it-py # mypy - # platformdirs - # pylint - # rich urllib3==1.26.16 # via # -r requirements/base.txt @@ -247,10 +228,7 @@ wheel==0.40.0 wrapt==1.15.0 # via astroid zipp==3.15.0 - # via - # -r requirements/base.txt - # importlib-metadata - # importlib-resources + # via importlib-metadata # The following packages are considered to be unsafe in a requirements file: # pip diff --git a/requirements/docs.txt b/requirements/docs.txt index 5fcdbc1..016cb3d 100644 --- a/requirements/docs.txt +++ b/requirements/docs.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.7 +# This file is autogenerated by pip-compile with Python 3.10 # by the following command: # # pip-compile requirements/docs.in @@ -42,11 +42,6 @@ idna==3.4 # requests imagesize==1.4.1 # via sphinx -importlib-metadata==6.6.0 - # via - # -r requirements/base.txt - # click - # sphinx jinja2==3.1.2 # via # -r requirements/base.txt @@ -86,8 +81,6 @@ python-dateutil==2.8.2 # via # -r requirements/base.txt # kubernetes -pytz==2023.3 - # via babel pyyaml==6.0 # via # -r requirements/base.txt @@ -114,7 +107,7 @@ six==1.16.0 # python-dateutil snowballstemmer==2.2.0 # via sphinx -sphinx==5.3.0 +sphinx==6.2.1 # via # -r requirements/docs.in # sphinx-click @@ -124,11 +117,11 @@ sphinx-click==4.4.0 # via -r requirements/docs.in sphinx-rtd-theme==1.2.1 # via -r requirements/docs.in -sphinxcontrib-applehelp==1.0.2 +sphinxcontrib-applehelp==1.0.4 # via sphinx sphinxcontrib-devhelp==1.0.2 # via sphinx -sphinxcontrib-htmlhelp==2.0.0 +sphinxcontrib-htmlhelp==2.0.1 # via sphinx sphinxcontrib-jquery==4.1 # via sphinx-rtd-theme @@ -142,14 +135,9 @@ tomli==2.0.1 # via # -r requirements/base.txt # mypy -typed-ast==1.5.4 - # via - # -r requirements/base.txt - # mypy typing-extensions==4.6.3 # via # -r requirements/base.txt - # importlib-metadata # mypy urllib3==1.26.16 # via @@ -161,10 +149,6 @@ websocket-client==1.5.2 # via # -r requirements/base.txt # kubernetes -zipp==3.15.0 - # via - # -r requirements/base.txt - # importlib-metadata # The following packages are considered to be unsafe in a requirements file: # setuptools diff --git a/setup.py b/setup.py index ff7ee31..8a5c470 100644 --- a/setup.py +++ b/setup.py @@ -56,7 +56,7 @@ setup( long_description_content_type="text/x-rst", packages=find_packages(exclude=["tests*"]), include_package_data=True, - python_requires=">=3.7", + python_requires=">=3.8", install_requires=load_requirements("base.in"), extras_require={ "full": load_requirements("plugins.txt"), @@ -68,10 +68,10 @@ setup( "License :: OSI Approved :: GNU Affero General Public License v3", "Operating System :: OS Independent", "Programming Language :: Python", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", ], test_suite="tests", ) diff --git a/tutor/commands/jobs.py b/tutor/commands/jobs.py index 8e694fc..a6648c7 100644 --- a/tutor/commands/jobs.py +++ b/tutor/commands/jobs.py @@ -4,13 +4,14 @@ Common jobs that must be added both to local, dev and k8s commands. from __future__ import annotations import functools +import shlex import typing as t import click from typing_extensions import ParamSpec from tutor import config as tutor_config -from tutor import env, fmt, hooks, utils +from tutor import env, fmt, hooks from tutor.hooks import priorities @@ -260,7 +261,7 @@ def sqlshell(args: list[str]) -> t.Iterable[tuple[str, str]]: """ command = "mysql --user={{ MYSQL_ROOT_USERNAME }} --password={{ MYSQL_ROOT_PASSWORD }} --host={{ MYSQL_HOST }} --port={{ MYSQL_PORT }}" if args: - command += " " + utils._shlex_join(*args) # pylint: disable=protected-access + command += " " + shlex.join(args) # pylint: disable=protected-access yield ("lms", command) diff --git a/tutor/core/hooks/filters.py b/tutor/core/hooks/filters.py index c513bae..9e9b70e 100644 --- a/tutor/core/hooks/filters.py +++ b/tutor/core/hooks/filters.py @@ -225,15 +225,10 @@ class Filter(t.Generic[T1, T2]): my_filter.add_item("item2") """ - # Unfortunately we have to type-ignore this line. If not, mypy complains with: - # - # Argument 1 has incompatible type "Callable[[Arg(List[E], 'values'), **T2], List[E]]"; expected "Callable[[List[E], **T2], List[E]]" - # This is likely because "callback" has named arguments: "values". Consider marking them positional-only - # - # But we are unable to mark arguments positional-only (by adding / after values arg) in Python 3.7. - # Get rid of this statement after Python 3.7 EOL. - @self.add(priority=priority) # type: ignore - def callback(values: list[L], *_args: T2.args, **_kwargs: T2.kwargs) -> list[L]: + @self.add(priority=priority) + def callback( + values: list[L], /, *_args: T2.args, **_kwargs: T2.kwargs + ) -> list[L]: return values + items def iterate( diff --git a/tutor/utils.py b/tutor/utils.py index 6492958..6d62777 100644 --- a/tutor/utils.py +++ b/tutor/utils.py @@ -216,7 +216,7 @@ def is_a_tty() -> bool: def execute(*command: str) -> int: - click.echo(fmt.command(_shlex_join(*command))) + click.echo(fmt.command(shlex.join(command))) return execute_silent(*command) @@ -239,21 +239,8 @@ def execute_silent(*command: str) -> int: return result -def _shlex_join(*split_command: str) -> str: - """ - Return a shell-escaped string from *split_command. - - TODO: REMOVE THIS FUNCTION AFTER 2023-06-27. - This function is a shim for the ``shlex.join`` standard library function, - which becomes available in Python 3.8 The end-of-life date for Python 3.7 - is in Jan 2023 (https://endoflife.date/python). After that point, it - would be good to delete this function and just use Py3.8's ``shlex.join``. - """ - return " ".join(shlex.quote(arg) for arg in split_command) - - def check_output(*command: str) -> bytes: - literal_command = _shlex_join(*command) + literal_command = shlex.join(command) click.echo(fmt.command(literal_command)) try: return subprocess.check_output(command)