#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.

Reply via email to