How to define Spawner.args with a dict using new traitlets format?

We’re using z2jh 0.10.6 and jupyterhub 1.2.2. I noticed that we were getting warnings like this in the notebook pod logs:

Mar 5 11:53:49 jupyter-6042701be8aa59a7af9d628b notebook /opt/conda/lib/python3.8/site-packages/traitlets/ FutureWarning: --tornado_settings={“headers”:{‘Access-Control-Allow-Origin’: ‘*’, ‘Content-Security-Policy’: “frame-ancestors * ‘self’”},“cookie_options”: {“SameSite”: “None”, “Secure”: True}} for dict-traits is deprecated in traitlets 5.0. You can pass --tornado_settings <key=value> … multiple times to add items to a dict.

In our hub helm chart values file, in extraConfig, we were setting the c.Spawner.args like this:

c.Spawner.args = [
        "--NotebookApp.tornado_settings={\"headers\":{'Access-Control-Allow-Origin': '*', 'Content-Security-Policy': \"frame-ancestors * 'self'\"},\"cookie_options\": {\"SameSite\": \"None\", \"Secure\": True}}",

Following that warning, and looking at how the dict arg test code works in traitlets [1], we tried this:

      c.Spawner.args = [
        "--ServerApp.tornado_settings headers={'Access-Control-Allow-Origin': '*', 'Content-Security-Policy': \"frame-ancestors * 'self'\"}",
        "--ServerApp.tornado_settings cookie_options={\"SameSite\": \"None\", \"Secure\": True}",

But now the server pod startup fails with this:

Apr 9 15:57:22 jupyter-5e18a4193f4a3f001127f809 notebook [C 2021-04-09 20:57:22.397 SingleUserNotebookApp notebookapp:1620] No such file or directory: /home/jovyan/–ServerApp.tornado_settings headers={‘Access-Control-Allow-Origin’: ‘*’, ‘Content-Security-Policy’: “frame-ancestors * ‘self’”}

I started poking through the notebook->jupyter-server migration guide [2] and created a symlink from to in our singleuser notebook image, and I also followed [3] and set JUPYTERHUB_SINGLEUSER_APP='jupyter_server.serverapp.ServerApp' in the hub pod config but those don’t seem to help.

I’m assuming the way we’ve defined the Spawner.args dict values is somehow breaking the command line parser with traitlets but I’m at a loss as to what we should be using since the dict-arg tests in traitlets are pretty basic and I can’t find anything in the docs.

I’m also wondering if maybe we should just hold off until [4] is complete.

[1] traitlets/ at 9f6276418d85aee49d12ab6495cf8a6acea8b961 · ipython/traitlets · GitHub
[2] Migrating from Notebook Server — Jupyter Server 1.7.0.dev0 documentation
[3] jupyterhub/ at d31af278887e52e8fc42aa822b7624a3ec9ead11 · jupyterhub/jupyterhub · GitHub
[4] JupyterLab - the default? · Issue #776 · jupyterhub/zero-to-jupyterhub-k8s · GitHub

If it helps we have jupyterlab 3.0.5 and jupyter_server 1.4.1 installed in the singleuser notebook image.

Do you still see those warnings/errors if you ignore JupyterHub and run Jupyter notebook/lab directly, passing the *tornado_settings* arguments on the command line?

Sorry for the late reply. Yes I’m still seeing those when trying to pass through to jupyterlab directly locally. To recreate:

cd /tmp
virtualenv .venv
source .venv/bin/activate
pip install jupyterlab
jupyter lab --ServerApp.tornado_settings headers={'Access-Control-Allow-Origin': '*', 'Content-Security-Policy': \"frame-ancestors * 'self'\"}

That results in:

(.venv) osboxes@osboxes:/tmp$ jupyter lab --ServerApp.tornado_settings headers={'Access-Control-Allow-Origin': '*', 'Content-Security-Policy': \"frame-ancestors * 'self'\"}
[C 2021-05-07 10:27:11.813 ServerApp] No such file or directory: /tmp/*,

When running in a shell you’ll have to quote the full arguments to prevent shell expansion (this isn’t needed in the config file since shell expansion shouldn’t happen). With these additional quotes:

jupyter lab --ServerApp.tornado_settings "headers={'Access-Control-Allow-Origin': '*', 'Content-Security-Policy': \"frame-ancestors * 'self'\"}"

starts, though I get some other error when I open it in my browser. This probably needs the help of someone from the jupyter-server team.