pallets / jinja

A very fast and expressive template engine.
https://jinja.palletsprojects.com
BSD 3-Clause "New" or "Revised" License
10.23k stars 1.6k forks source link

Property Template::is_up_to_date breaks type hint contract #1902

Closed rwielk closed 10 months ago

rwielk commented 10 months ago

environment.py::Template::is_up_to_date (https://github.com/pallets/jinja/blob/main/src/jinja2/environment.py#L1496) tries to call self._uptodate even if this correctly is a boolean and not callable, disallowing to correctly implement BaseLoader::get_source with an alway up_to_date get_source like here: https://github.com/peering-manager/peering-manager/blob/main/peering_manager/jinja2/loaders.py#L48

Overwrite a BaseLoaders get_source method returning a bool as last value as type hints allow and include template twice with cache enabled like here: https://github.com/peering-manager/peering-manager/blob/main/peering_manager/jinja2/loaders.py#L6

Untested example code snippet:

from jinja2 import BaseLoader

class MyLoader(BaseLoader):
    def get_source(self, environment, template):
        source = ...
        return source, template, True  # true should be allowed but jinja does not handle it here correctly according to type hints
...
---
...
{% include myTemp %}
{% include myTemp %}

Example trace

Traceback (most recent call last):
  File "/opt/peering-manager/peering_manager/jinja2/__init__.py", line 30, in render_jinja2
    return jinja2_template.render(**context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/peering-manager/.venv/lib/python3.11/site-packages/jinja2/environment.py", line 1301, in render
    self.environment.handle_exception()
  File "/opt/peering-manager/.venv/lib/python3.11/site-packages/jinja2/environment.py", line 936, in handle_exception
    raise rewrite_traceback_stack(source=source)
  File "<template>", line 5, in top-level template code
  File "/opt/peering-manager/.venv/lib/python3.11/site-packages/jinja2/environment.py", line 1494, in is_up_to_date
    return self._uptodate()
           ^^^^^^^^^^^^^^^^
TypeError: 'bool' object is not callable

Respect bools value and do not call it.

Environment:

MR incoming...

davidism commented 10 months ago

_uptodate has behaved the same way for 16 years, see the blame view on that line you identified: https://github.com/pallets/jinja/blame/main/src/jinja2/environment.py#L1496 It must be None or a callable, None indicates it's always up to date.

rwielk commented 10 months ago

Sorry, just misread the typehints, thanks for your quick response.

Just in case anyone stumbles into this via googe or so:

https://github.com/peering-manager/peering-manager/pull/783

fixes this in this case at the right location which is not jinja here, my bad.