Projet

Général

Profil

0001-wcs-resolve-card_ids-lazily-74306.patch

Benjamin Dauvergne, 08 février 2023 10:13

Télécharger (6,84 ko)

Voir les différences:

Subject: [PATCH] wcs: resolve card_ids lazily (#74306)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The class LazyValue is a thunk[1] like in lazy evaluated language it is
initialized with a function needing no argument and store its result on
first call.

Direct access to the context to get the ids is replaced by calls to new
method WcsCardCell.get_card_ids(context). Original get_card_ids() is
renamed resolve_card_ids() and used with LazyValue to implement the lazy
evaluation of card_ids.

This line was modified as it does not really work :

	if·','·in·first_cell.card_ids:

since card_ids can contain templates like

        {{ ...|join:"," }}

which will evaluate to True even if the template returns only one card
(one test was broken because of this, the bug was hidden by eager
evaluation of card_ids previously).

[1]: https://en.wikipedia.org/wiki/Thunk
 combo/apps/wcs/models.py | 38 +++++++++++++++++++++++++++++---------
 tests/wcs/test_card.py   | 10 +++++++---
 2 files changed, 36 insertions(+), 12 deletions(-)
combo/apps/wcs/models.py
822 822
        return escape(self.custom_title) or self.cached_title or None
823 823

  
824 824

  
825
class LazyValue:
826
    sentinel = object()
827

  
828
    def __init__(self, getter):
829
        self.value = self.sentinel
830
        self.getter = getter
831

  
832
    def __call__(self):
833
        if self.value is self.sentinel:
834
            self.value = self.getter()
835
        return self.value
836

  
837

  
825 838
@register_cell_class
826 839
class WcsCardCell(CardMixin, CellBase):
827 840
    carddef_reference = models.CharField(_('Card Model'), max_length=150)
......
872 885
    class Meta:
873 886
        verbose_name = _('Card(s)')
874 887

  
888
    def get_card_ids(self, context):
889
        lazy_value = context.get(self.global_context_key)
890
        if lazy_value is not None:
891
            return lazy_value()
892
        return []
893

  
875 894
    def save(self, *args, **kwargs):
876 895
        super().save(*args, **kwargs)
877 896

  
......
960 979
            # don't call wcs on page loading
961 980
            return
962 981
        if self.carddef_reference and self.global_context_key not in context:
963
            card_ids = self.get_card_ids(context, request)
964
            context[self.global_context_key] = card_ids
982
            # self.resolve_card_ids(context, request)
983
            context[self.global_context_key] = LazyValue(lambda: self.resolve_card_ids(context, request))
965 984

  
966 985
    def get_repeat_template(self, context):
967 986
        if self.display_mode == 'table':
968 987
            # don't repeat cell if table display mode
969 988
            return []
970
        return len(context.get(self.global_context_key) or [])
989
        return len(self.get_card_ids(context))
971 990

  
972 991
    def get_related_card_path(self):
973 992
        if self.related_card_path == '__all__':
......
1026 1045

  
1027 1046
    def get_card_data_from_ids(self, card_id, context):
1028 1047
        # get the correct card from all known cards for ids in context
1029
        card_ids = context.get(self.global_context_key)
1048
        card_ids = self.get_card_ids(context)
1030 1049
        if not card_ids:
1031 1050
            return None
1032 1051
        if len(card_ids) == 1:
......
1287 1306
        if first_cell.related_card_path:
1288 1307
            # no explicit ids
1289 1308
            return []
1290
        if ',' in first_cell.card_ids:
1309
        card_ids = first_cell.get_card_ids(context)
1310
        if len(card_ids) > 1:
1291 1311
            # multiple ids, can not follow relations
1292 1312
            return []
1293 1313
        first_cell.repeat_index = 0
......
1324 1344
        except (VariableDoesNotExist, TemplateSyntaxError):
1325 1345
            return []
1326 1346

  
1327
    def get_card_ids(self, original_context, request):
1347
    def resolve_card_ids(self, original_context, request):
1328 1348
        if not self.carddef_reference:
1329 1349
            # not configured
1330 1350
            return []
......
1367 1387
        return []
1368 1388

  
1369 1389
    def get_card_id(self, context):
1370
        repeat_index = getattr(self, 'repeat_index', context.get('repeat_index'))
1390
        repeat_index = getattr(self, 'repeat_index', context.get('repeat_index')) or 0
1371 1391
        if repeat_index is not None:
1372 1392
            try:
1373
                return context.get(self.global_context_key)[repeat_index]
1393
                return self.get_card_ids(context)[repeat_index]
1374 1394
            except (IndexError, TypeError):
1375 1395
                return None
1376 1396

  
......
1475 1495
            card_page = matching_pages[0]
1476 1496
            extra_context['card_page_base_url'] = card_page.get_online_url()
1477 1497

  
1478
        card_ids = context.get(self.global_context_key)
1498
        card_ids = self.get_card_ids(context)
1479 1499
        if not card_ids and self.related_card_path != '__all__':
1480 1500
            extra_context['card_objects'] = []
1481 1501
        else:
tests/wcs/test_card.py
1360 1360

  
1361 1361

  
1362 1362
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
1363
def test_card_cell_table_mode_render_identifier_from_related(mock_send, nocache, app):
1363
def test_card_cell_table_mode_render_identifier_from_related(mock_send, app):
1364 1364
    page = Page.objects.create(title='xxx', slug='foo', template_name='standard')
1365 1365
    WcsCardCell.objects.create(
1366 1366
        page=page,
......
1407 1407
    check(urls)
1408 1408

  
1409 1409
    # direct and multiple relation (items)
1410
    # clear cache to see call to /api/cards/card_a/1/
1411
    from django.core.cache import cache
1412

  
1413
    cache.clear()
1410 1414
    cell2.carddef_reference = 'default:card_b'  # reset
1411 1415
    cell2.related_card_path = 'sluga/cardsb'
1412 1416
    cell2.save()
......
2275 2279
    assert PyQuery(result).find('.value a').attr['class'] is None
2276 2280

  
2277 2281
    # empty label or no value/no file field/unknown field: no link in output
2278
    context[cell.global_context_key] = [12]
2282
    context[cell.global_context_key] = lambda: [12]
2279 2283
    result = cell.render(context)
2280 2284
    assert PyQuery(result).find('.value a') == []
2281
    context[cell.global_context_key] = [11]
2285
    context[cell.global_context_key] = lambda: [11]
2282 2286
    cell.modify_global_context(context, request)
2283 2287
    cell.repeat_index = 0
2284 2288
    cell.custom_schema['cells'][0]['link_field'] = 'fielda'
2285
-