Tutor "dev launch" not compatible with latest click v8.3.0
Bug description
Click 8.3.0 introduced a breaking change where optional parameters without defaults now receive a Sentinel object instead of None: https://github.com/pallets/click/commit/b64ea07128a6368b5f6f93035c75d5693c7ba572
This causes tutor dev launch to fail with a TypeError when building dev Docker images because the Sentinel object is passed to shlex.join(), which expects only string arguments.
/home/pupkin/tutor-19.0.5/. $ TUTOR_ROOT=$(pwd) tutor dev launch
⚠️ Failed to enable plugin 'indigo': plugin 'indigo' is not installed.
⚠️ Failed to enable plugin 'mfe': plugin 'mfe' is not installed.
==================================================
Interactive platform configuration
==================================================
As you are not running this platform in production, we automatically set the following configuration values:
LMS_HOST = local.openedx.io
CMS_HOST = studio.local.openedx.io
ENABLE_HTTPS = False
Your platform name/title [My Open edX]
Your public contact email address [[email protected]]
The default language code for the platform [en]
Configuration saved to /home/pupkin/tutor-19.0.5/config.yml
Environment generated in /home/pupkin/tutor-19.0.5/env
======================================
Building Docker images
======================================
Building image openedx-dev:19.0.5
Traceback (most recent call last):
File "/home/pupkin/tutor-19.0.5/.venv/bin/tutor", line 7, in <module>
sys.exit(main())
^^^^^^
File "/home/pupkin/tutor-19.0.5/.venv/lib/python3.11/site-packages/tutor/commands/cli.py", line 27, in main
cli() # pylint: disable=no-value-for-parameter
^^^^^
File "/home/pupkin/tutor-19.0.5/.venv/lib/python3.11/site-packages/click/core.py", line 1462, in __call__
return self.main(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/pupkin/tutor-19.0.5/.venv/lib/python3.11/site-packages/click/core.py", line 1383, in main
rv = self.invoke(ctx)
^^^^^^^^^^^^^^^^
File "/home/pupkin/tutor-19.0.5/.venv/lib/python3.11/site-packages/click/core.py", line 1850, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/pupkin/tutor-19.0.5/.venv/lib/python3.11/site-packages/click/core.py", line 1850, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/pupkin/tutor-19.0.5/.venv/lib/python3.11/site-packages/click/core.py", line 1246, in invoke
return ctx.invoke(self.callback, **ctx.params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/pupkin/tutor-19.0.5/.venv/lib/python3.11/site-packages/click/core.py", line 814, in invoke
return callback(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/pupkin/tutor-19.0.5/.venv/lib/python3.11/site-packages/click/decorators.py", line 34, in new_func
return f(get_current_context(), *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/pupkin/tutor-19.0.5/.venv/lib/python3.11/site-packages/tutor/commands/compose.py", line 138, in launch
context.invoke(images.build, image_names=images_to_build)
File "/home/pupkin/tutor-19.0.5/.venv/lib/python3.11/site-packages/click/core.py", line 814, in invoke
return callback(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/pupkin/tutor-19.0.5/.venv/lib/python3.11/site-packages/click/decorators.py", line 46, in new_func
return f(get_current_context().obj, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/pupkin/tutor-19.0.5/.venv/lib/python3.11/site-packages/tutor/commands/images.py", line 241, in build
images.build(
File "/home/pupkin/tutor-19.0.5/.venv/lib/python3.11/site-packages/tutor/images.py", line 11, in build
utils.docker(*command)
File "/home/pupkin/tutor-19.0.5/.venv/lib/python3.11/site-packages/tutor/utils.py", line 193, in docker
return execute("docker", *command)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/pupkin/tutor-19.0.5/.venv/lib/python3.11/site-packages/tutor/utils.py", line 217, in execute
click.echo(fmt.command(shlex.join(command)))
^^^^^^^^^^^^^^^^^^^
File "/home/pupkin/.pyenv/versions/3.11.8/lib/python3.11/shlex.py", line 320, in join
return ' '.join(quote(arg) for arg in split_command)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/pupkin/.pyenv/versions/3.11.8/lib/python3.11/shlex.py", line 320, in <genexpr>
return ' '.join(quote(arg) for arg in split_command)
^^^^^^^^^^
File "/home/pupkin/.pyenv/versions/3.11.8/lib/python3.11/shlex.py", line 329, in quote
if _find_unsafe(s) is None:
^^^^^^^^^^^^^^^
TypeError: expected string or bytes-like object, got 'Sentinel'
How to reproduce
- Set up Python environment:
echo 3.11.8 > .python-version uv venv --python 3.11.8 .venv source .venv/bin/activate - Install tutor:
uv pip install "tutor==19.0.5" - Run the failing command
tutor dev launch
Environment
- OS: MacOS Sequoia (also reproduced on Ubuntu)
- Python: 3.11.8
- Tutor: 19.0.5 and 20.0.1
- Click: 8.3.0 (works fine with click <8.3.0)
Temporary fix
Install older version of click: uv pip install "click<8.3"
Tutor is currently on click 8.1.8 version. Unless explicitly installed, the latest version of click won't install. That said, this will require changes if it is causing the launch to break.
@DawoudSheraz note however that the most recent version of click will be installed when we run pip install tutor because click is not pinned in base.in:
https://github.com/overhangio/tutor/blob/c031d2473a65b5413784bbcc7dcbcc50865a57e4/pyproject.toml#L52 https://github.com/overhangio/tutor/blob/release/requirements/base.in
Created a PR to temporarily pin click https://github.com/overhangio/tutor/pull/1277
In case anyone is facing this issue pip install click==8.1.8 did the job for me
I had a similar issue where tutor local launch was not always out of sync and was not available for the LMS and CMS workers to connect to. This was on a completely fresh install of Python 3.15 and running on an M3 if it helps.
The pip install click==8.1.8 fix of @junedkhatri31 resolved this issue.