django-stubs icon indicating copy to clipboard operation
django-stubs copied to clipboard

django.template.Template.render() has incorrectly typed argument

Open asib opened this issue 3 years ago • 3 comments

Bug report

What's wrong

django.template.Template.render() has the following stub (see here):

def render(self, context: Optional[Union[Context, Dict[str, Any]]]) -> SafeString: ...

However, the implementation of this method below makes it impossible to pass in a Dict[str, Any] (see here) as it immediately attempts to access an attribute render_context:

def render(self, context):
    "Display stage -- can be called many times"
    with context.render_context.push_state(self):
        if context.template is None:
            with context.bind_template(self):
                context.template_name = self.name
                return self._render(context)
        else:
            return self._render(context)

From the looks of it, the various backends define their own Template class, some (all?) of which have a render() method that accepts dictionaries, but this is not the case for the standard django.template.Template class.

I don't know enough of the surrounding context to say whether this is intended or not, but it seems wrong from a first glance. Apologies if this has already been answered, I did have a look through the issues on the repo to try to find similar queries.

How is that should be

The stub for django.template.Template.render() should be changed to:

def render(self, context: Optional[Context]) -> SafeString: ...

System information

  • OS: macOS 12.2.1
  • python version: 3.10.6
  • django version: 4.0.7
  • mypy version: 0.971
  • django-stubs version: 1.12.0
  • django-stubs-ext version: 0.5.0

asib avatar Sep 09 '22 11:09 asib

PRs are welcome

sobolevn avatar Sep 09 '22 12:09 sobolevn

Just to confirm - this is indeed a bug? Happy to work on a PR if so.

asib avatar Sep 09 '22 12:09 asib

It looks like it, yes. The stubs are unfortunately not verified against Django's codebase at current, so we rely on spotting fixes from usage, like you've done 😊

adamchainz avatar Sep 09 '22 13:09 adamchainz

I think, that since the function unconditionally accesses the render_context attribute, the context argument also shouldn't be typed as Optional. It should always expect a Context object to be passed in.

def render(self, context: Context) -> SafeString: ...

Majsvaffla avatar Sep 23 '22 10:09 Majsvaffla