jupyterhub / kubespawner

Kubernetes spawner for JupyterHub
https://jupyterhub-kubespawner.readthedocs.io
BSD 3-Clause "New" or "Revised" License
536 stars 301 forks source link

static_url() is undefined in Jinja inside form.html #760

Open luanabeckerdaluz opened 12 months ago

luanabeckerdaluz commented 12 months ago

Bug description

I am customizing jupyterhub templates by using images and css files stored in the jupyterhub static folder. When I need these images in the templates (page.html, login.html, spawner.html, etc.), I am accessing using the static_url() function with jinja. Nonetheless, I am not able to use this function or the functions url_for() and static() when calling it from inside kubespawner form.html. I also tried to access the STATIC_URL variable but the value was none.

Expected behaviour

The form.html file is used inside spawn.html in the object "{{spawner_options_form | safe}}". It is expected that some functions available by jinja when building jupyterhub templates also be available when building kubespawner form.html.

Actual behaviour

I think that Jinja is building the form html before insert this html in the spawner_options_form object of spawner.html. When building before, the function static_url() is undefined, while in the jupyterhub templates this function is defined. Below is shown the traceback when I tried to use this function in the html <img src="{{ static_url('images/cpu-ram.svg') }}>"

HTTPServerRequest(protocol='http', host='127.0.0.1:8081', method='GET', uri='/hub/spawn', version='HTTP/1.1', remote_ip='127.0.0.1')
Traceback (most recent call last):
File "/home/harmonize/.local/lib/python3.10/site-packages/tornado/web.py", line 1713, in _execute
  result = await result
File "/home/harmonize/.local/lib/python3.10/site-packages/jupyterhub/handlers/pages.py", line 207, in _get
  spawner_options_form = await spawner.get_options_form()
File "/home/harmonize/.local/lib/python3.10/site-packages/jupyterhub/spawner.py", line 542, in get_options_form
  options_form = await maybe_future(self.options_form(self))
File "/home/harmonize/git/jupyter-k8s/hub/config.py", line 216, in custom_options_form
  return self._options_form_default()
File "/home/harmonize/.local/lib/python3.10/site-packages/kubespawner/spawner.py", line 2974, in _options_form_default
  return self._render_options_form(self.profile_list)
File "/home/harmonize/.local/lib/python3.10/site-packages/kubespawner/spawner.py", line 2951, in _render_options_form
  return profile_form_template.render(profile_list=profile_list)
File "/home/harmonize/.local/lib/python3.10/site-packages/jinja2/environment.py", line 1301, in render
  self.environment.handle_exception()
File "/home/harmonize/.local/lib/python3.10/site-packages/jinja2/environment.py", line 936, in handle_exception
  raise rewrite_traceback_stack(source=source)
File "templates/form.html", line 72, in top-level template code
  <img  src="{{ static_url('images/cpu-ram.svg') }}">
File "/home/harmonize/.local/lib/python3.10/site-packages/jinja2/utils.py", line 83, in from_obj
  if hasattr(obj, "jinja_pass_arg"):
jinja2.exceptions.UndefinedError: 'static_url' is undefined

Your personal set up

welcome[bot] commented 12 months ago

Thank you for opening your first issue in this project! Engagement like this is essential for open source projects! :hugs:
If you haven't done so already, check out Jupyter's Code of Conduct. Also, please try to follow the issue template as it helps other other community members to contribute more effectively. welcome You can meet the other Jovyans by joining our Discourse forum. There is also an intro thread there where you can stop by and say Hi! :wave:
Welcome to the Jupyter community! :tada:

yuvipanda commented 9 months ago

We create our own jinja2 environment here: https://github.com/jupyterhub/kubespawner/blob/6d9d9a36df3077b6ba22e4a94107ffe96fc2b18c/kubespawner/spawner.py#L2943. static_url and other helpers come from this jinja_env that is setup by JupyterHub (not kubespawner).

I'm not sure what exactly is the best way to move forward here.

consideRatio commented 9 months ago

Kubespawner renders a jinja2 template into another jinja2 template, is fix fix to ensure that static_url is parsed by the second jinja2 template rendering done by jupyterhub?

yuvipanda commented 9 months ago

Kubespawner renders a jinja2 template into a string, that is then passed onto JupyterHub via options_form which expects a string. That is then rendered onto a jinja2 template.

I think the cleanest way perhaps is to add templating support into upstream JupyterHub for options forms, and move https://github.com/jupyterhub/kubespawner/pull/724 there.