#35735: For python 3.9+ class property may not be accessible by Django's
template
system
---------------------------------+----------------------------------------
Reporter: Fabian Braun | Owner: Fabian Braun
Type: Bug | Status: closed
Component: Template system | Version: dev
Severity: Normal | Resolution: needsinfo
Keywords: | Triage Stage: Unreviewed
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
---------------------------------+----------------------------------------
Description changed by Fabian Braun:
Old description:
> Before python 3.9 class properties were always available through the
> template system. If you had a class
> {{{
> class MyClass:
> in_template = True
> do_not_call_in_templates = True # prevent instantiation
>
> @classmethod
> def render_all_objects(cls):
> ...
> }}}
> you could access the class property in the template through (if it was
> contained in the context) `{{ MyClass.in_template }}` or `{{ MyClass.
> render_all_objects }}`.
>
> The template system first gets the class `MyClass` (and does not
> instantiate it) or gets it as a result of a callable `get_my_class`. Then
> it checks if the class is subscriptable (i.e. tries
> `MyClass["in_template"]`), will fail and then will get the in_template
> property.
>
> As of python 3.9 some classes actually are subscriptable and trying to
> get the item will not fail: Typing shortcuts introduced syntax like
> `list[int]`. These hide class properties or methods from the template
> system.
>
> Here's a test (that might go into
> tests/template_tests/syntax_tests/tests_basic.py) which passes on Python
> 3.9 and fails on Python 3.10+:
> {{{
> @setup({"basic-syntax19b": "{{ klass.in_template }}"})
> def test_access_class_property(self):
> class MyClass(list):
> in_template = True
> do_not_call_in_templates = True # prevent instantiation
>
> output = self.engine.render_to_string("basic-syntax19b",
> {"klass": MyClass})
> self.assertEqual(output, "True")
> }}}
>
> I'd be happy to propose a fix that will not call a classes'
> `__class_getitem__` method.
>
> Thanks to [https://github.com/benzkji Ben Stähli] and [https://github.com
> /last-partizan Serhii Tereshchenko] for figuring out this issue.
>
> References:
>
> * https://github.com/django-cms/django-cms/issues/7948
New description:
Before python 3.9 class properties were always available through the
template system. If you had a class
{{{
class MyClass(list):
in_template = True
do_not_call_in_templates = True # prevent instantiation
@classmethod
def render_all_objects(cls):
...
}}}
you could access the class property in the template through (if it was
contained in the context) `{{ MyClass.in_template }}` or `{{ MyClass.
render_all_objects }}`.
The template system first gets the class `MyClass` (and does not
instantiate it) or gets it as a result of a callable `get_my_class`. Then
it checks if the class is subscriptable (i.e. tries
`MyClass["in_template"]`), will fail and then will get the in_template
property.
As of python 3.9 some classes actually are subscriptable and trying to get
the item will not fail: Typing shortcuts introduced syntax like
`list[int]`. These hide class properties or methods from the template
system.
Here's a test (that might go into
tests/template_tests/syntax_tests/tests_basic.py) which passes on Python
3.9 and fails on Python 3.10+:
{{{
@setup({"basic-syntax19b": "{{ klass.in_template }}"})
def test_access_class_property(self):
class MyClass(list):
in_template = True
do_not_call_in_templates = True # prevent instantiation
output = self.engine.render_to_string("basic-syntax19b", {"klass":
MyClass})
self.assertEqual(output, "True")
}}}
I'd be happy to propose a fix that will not call a classes'
`__class_getitem__` method.
Thanks to [https://github.com/benzkji Ben Stähli] and [https://github.com
/last-partizan Serhii Tereshchenko] for figuring out this issue.
References:
* https://github.com/django-cms/django-cms/issues/7948
--
--
Ticket URL: <https://code.djangoproject.com/ticket/35735#comment:7>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/01070191c3917b88-08fac4ee-c511-4ccf-ad93-819f9c9723eb-000000%40eu-central-1.amazonses.com.