Projet

Général

Profil

0001-misc-remove-mathematic-filters-split-68673.patch

Lauréline Guérin, 02 septembre 2022 16:01

Télécharger (15,7 ko)

Voir les différences:

Subject: [PATCH] misc: remove mathematic filters + split (#68673)

they are defined in publik-django-templatetags
 combo/public/templatetags/combo.py |  95 -------------
 tests/test_public_templatetags.py  | 213 -----------------------------
 2 files changed, 308 deletions(-)
combo/public/templatetags/combo.py
18 18
import copy
19 19
import datetime
20 20
import json
21
import math
22
from decimal import Decimal
23
from decimal import DivisionByZero as DecimalDivisionByZero
24
from decimal import InvalidOperation as DecimalInvalidOperation
25 21

  
26 22
import django
27 23
from django import template
......
335 331
    return user.groups.filter(name=groupname).exists()
336 332

  
337 333

  
338
@register.filter
339
def split(string, separator=' '):
340
    return (force_str(string) or '').split(separator)
341

  
342

  
343 334
@register.filter
344 335
def strip(string, chars=None):
345 336
    if not string:
......
567 558
    yield value
568 559

  
569 560

  
570
def parse_decimal(value, default=Decimal(0)):
571
    if isinstance(value, str):
572
        # replace , by . for French users comfort
573
        value = value.replace(',', '.')
574
    try:
575
        return Decimal(value).quantize(Decimal('1.0000')).normalize()
576
    except (ArithmeticError, TypeError):
577
        return default
578

  
579

  
580
@register.filter(is_safe=False)
581
def decimal(value, arg=None):
582
    if not isinstance(value, Decimal):
583
        value = parse_decimal(value)
584
    if arg is None:
585
        return value
586
    return defaultfilters.floatformat(value, arg=arg)
587

  
588

  
589
@register.filter
590
def add(term1, term2):
591
    '''replace the "add" native django filter'''
592

  
593
    if term1 is None:
594
        term1 = ''
595
    if term2 is None:
596
        term2 = ''
597
    term1_decimal = parse_decimal(term1, default=None)
598
    term2_decimal = parse_decimal(term2, default=None)
599

  
600
    if term1_decimal is not None and term2_decimal is not None:
601
        return term1_decimal + term2_decimal
602
    if term1 == '' and term2_decimal is not None:
603
        return term2_decimal
604
    if term2 == '' and term1_decimal is not None:
605
        return term1_decimal
606
    return defaultfilters.add(term1, term2)
607

  
608

  
609
@register.filter
610
def subtract(term1, term2):
611
    return parse_decimal(term1) - parse_decimal(term2)
612

  
613

  
614
@register.filter
615
def multiply(term1, term2):
616
    return parse_decimal(term1) * parse_decimal(term2)
617

  
618

  
619
@register.filter
620
def divide(term1, term2):
621
    try:
622
        return parse_decimal(term1) / parse_decimal(term2)
623
    except DecimalInvalidOperation:
624
        return ''
625
    except DecimalDivisionByZero:
626
        return ''
627

  
628

  
629
@register.filter
630
def ceil(value):
631
    '''the smallest integer value greater than or equal to value'''
632
    return decimal(math.ceil(parse_decimal(value)))
633

  
634

  
635
@register.filter
636
def floor(value):
637
    return decimal(math.floor(parse_decimal(value)))
638

  
639

  
640
@register.filter(name='abs')
641
def abs_(value):
642
    return decimal(abs(parse_decimal(value)))
643

  
644

  
645 561
@register.filter(is_safe=False)
646 562
def phonenumber_fr(value, separator=' '):
647 563
    DROMS = ('262', '508', '590', '594', '596')
......
683 599
    if hasattr(cell, 'repeat_index'):
684 600
        ctx['repeat_index'] = cell.repeat_index
685 601
    return ctx
686

  
687

  
688
@register.filter(name='sum')
689
def sum_(list_):
690
    if isinstance(list_, str):
691
        # do not consider string as iterable, to avoid misusage
692
        return ''
693
    try:
694
        return sum(parse_decimal(term) for term in list_)
695
    except TypeError:  # list_ is not iterable
696
        return ''
tests/test_public_templatetags.py
121 121
    assert t.render(context) == 'False'
122 122

  
123 123

  
124
def test_split():
125
    t = Template('{% for x in plop|split %}{{x}}<br>{% endfor %}')
126
    assert t.render(Context({'plop': 'ab cd ef'})) == 'ab<br>cd<br>ef<br>'
127
    t = Template('{% for x in plop|split:"|" %}{{x}} {% endfor %}')
128
    assert t.render(Context({'plop': 'ab|cd|ef'})) == 'ab cd ef '
129
    t = Template('{% for x in plop|split:"|" %}{{x}} {% endfor %}')
130
    assert t.render(Context({'plop': 42})) == '42 '
131

  
132

  
133 124
def test_strip_templatetag():
134 125
    tmpl = Template('{{ foo|strip }}')
135 126
    assert tmpl.render(Context()) == ''
......
610 601
    assert t.render(Context({'value': 'error1', 'value2': 'error2'})) == ''
611 602

  
612 603

  
613
def test_decimal_templatetag():
614
    tmpl = Template('{{ plop|decimal }}')
615
    assert tmpl.render(Context({'plop': 'toto'})) == '0'
616
    assert tmpl.render(Context({'plop': '3.14'})) == '3.14'
617
    assert tmpl.render(Context({'plop': '3,14'})) == '3.14'
618
    assert tmpl.render(Context({'plop': 3.14})) == '3.14'
619
    assert tmpl.render(Context({'plop': 12345.678})) == '12345.678'
620
    assert tmpl.render(Context({'plop': None})) == '0'
621
    assert tmpl.render(Context({'plop': 0})) == '0'
622

  
623
    tmpl = Template('{{ plop|decimal:3 }}')
624
    assert tmpl.render(Context({'plop': '3.14'})) == '3.140'
625
    assert tmpl.render(Context({'plop': None})) == '0.000'
626
    tmpl = Template('{{ plop|decimal:"3" }}')
627
    assert tmpl.render(Context({'plop': '3.14'})) == '3.140'
628
    assert tmpl.render(Context({'plop': None})) == '0.000'
629

  
630
    tmpl = Template('{% if plop|decimal > 2 %}hello{% endif %}')
631
    assert tmpl.render(Context({'plop': 3})) == 'hello'
632
    assert tmpl.render(Context({'plop': '3'})) == 'hello'
633
    assert tmpl.render(Context({'plop': 2.001})) == 'hello'
634
    assert tmpl.render(Context({'plop': '2.001'})) == 'hello'
635
    assert tmpl.render(Context({'plop': 1})) == ''
636
    assert tmpl.render(Context({'plop': 1.99})) == ''
637
    assert tmpl.render(Context({'plop': '1.99'})) == ''
638
    assert tmpl.render(Context({'plop': 'x'})) == ''
639
    assert tmpl.render(Context({'plop': None})) == ''
640
    assert tmpl.render(Context({'plop': 0})) == ''
641

  
642
    tmpl = Template('{% if "3"|decimal == 3 %}hello{% endif %}')
643
    assert tmpl.render(Context()) == 'hello'
644
    tmpl = Template('{% if "3"|decimal == 3.0 %}hello{% endif %}')
645
    assert tmpl.render(Context()) == 'hello'
646
    tmpl = Template('{% if 3|decimal == 3 %}hello{% endif %}')
647
    assert tmpl.render(Context()) == 'hello'
648
    tmpl = Template('{% if 3.0|decimal == 3 %}hello{% endif %}')
649
    assert tmpl.render(Context()) == 'hello'
650
    tmpl = Template('{% if 3|decimal|decimal == 3 %}hello{% endif %}')
651
    assert tmpl.render(Context()) == 'hello'
652

  
653

  
654
def test_mathematics_templatetag():
655
    tmpl = Template('{{ term1|add:term2 }}')
656

  
657
    # using strings
658
    assert tmpl.render(Context({'term1': '1.1', 'term2': 0})) == '1.1'
659
    assert tmpl.render(Context({'term1': 'not a number', 'term2': 1.2})) == ''
660
    assert tmpl.render(Context({'term1': 0.3, 'term2': "1"})) == '1.3'
661
    assert tmpl.render(Context({'term1': 1.4, 'term2': "not a number"})) == ''
662

  
663
    # add
664
    assert tmpl.render(Context({'term1': 4, 'term2': -0.9})) == '3.1'
665
    assert tmpl.render(Context({'term1': '4', 'term2': -0.8})) == '3.2'
666
    assert tmpl.render(Context({'term1': 4, 'term2': '-0.7'})) == '3.3'
667
    assert tmpl.render(Context({'term1': '4', 'term2': '-0.6'})) == '3.4'
668
    assert tmpl.render(Context({'term1': '', 'term2': 3.5})) == '3.5'
669
    assert tmpl.render(Context({'term1': None, 'term2': 3.5})) == '3.5'
670
    assert tmpl.render(Context({'term1': 3.6, 'term2': ''})) == '3.6'
671
    assert tmpl.render(Context({'term1': '', 'term2': ''})) == ''
672
    assert tmpl.render(Context({'term1': 3.6, 'term2': None})) == '3.6'
673
    assert tmpl.render(Context({'term1': 0, 'term2': ''})) == '0'
674
    assert tmpl.render(Context({'term1': '', 'term2': 0})) == '0'
675
    assert tmpl.render(Context({'term1': 0, 'term2': 0})) == '0'
676

  
677
    # if term is '' or None and other term is decimal
678
    assert tmpl.render(Context({'term1': '', 'term2': 2.2})) == '2.2'
679
    assert tmpl.render(Context({'term1': None, 'term2': 2.2})) == '2.2'
680
    assert tmpl.render(Context({'term1': 2.2, 'term2': ''})) == '2.2'
681
    assert tmpl.render(Context({'term1': 2.2, 'term2': None})) == '2.2'
682

  
683
    # add using ',' instead of '.' decimal separator
684
    assert tmpl.render(Context({'term1': '1,1', 'term2': '2,2'})) == '3.3'
685
    assert tmpl.render(Context({'term1': '1,1', 'term2': '2.2'})) == '3.3'
686
    assert tmpl.render(Context({'term1': '1,1', 'term2': 2.2})) == '3.3'
687
    assert tmpl.render(Context({'term1': '1,1', 'term2': 0})) == '1.1'
688
    assert tmpl.render(Context({'term1': '1,1', 'term2': ''})) == '1.1'
689
    assert tmpl.render(Context({'term1': '1,1', 'term2': None})) == '1.1'
690
    assert tmpl.render(Context({'term1': '1.1', 'term2': '2,2'})) == '3.3'
691
    assert tmpl.render(Context({'term1': 1.1, 'term2': '2,2'})) == '3.3'
692
    assert tmpl.render(Context({'term1': 0, 'term2': '2,2'})) == '2.2'
693
    assert tmpl.render(Context({'term1': '', 'term2': '2,2'})) == '2.2'
694
    assert tmpl.render(Context({'term1': None, 'term2': '2,2'})) == '2.2'
695

  
696
    # subtract
697
    tmpl = Template('{{ term1|subtract:term2 }}')
698
    assert tmpl.render(Context({'term1': 5.1, 'term2': 1})) == '4.1'
699
    assert tmpl.render(Context({'term1': '5.2', 'term2': 1})) == '4.2'
700
    assert tmpl.render(Context({'term1': 5.3, 'term2': '1'})) == '4.3'
701
    assert tmpl.render(Context({'term1': '5.4', 'term2': '1'})) == '4.4'
702
    assert tmpl.render(Context({'term1': '', 'term2': -4.5})) == '4.5'
703
    assert tmpl.render(Context({'term1': 4.6, 'term2': ''})) == '4.6'
704
    assert tmpl.render(Context({'term1': '', 'term2': ''})) == '0'
705
    assert tmpl.render(Context({'term1': 0, 'term2': ''})) == '0'
706
    assert tmpl.render(Context({'term1': '', 'term2': 0})) == '0'
707
    assert tmpl.render(Context({'term1': 0, 'term2': 0})) == '0'
708

  
709
    # multiply
710
    tmpl = Template('{{ term1|multiply:term2 }}')
711
    assert tmpl.render(Context({'term1': '3', 'term2': '2'})) == '6'
712
    assert tmpl.render(Context({'term1': 2.5, 'term2': 2})) == '5.0'
713
    assert tmpl.render(Context({'term1': '2.5', 'term2': 2})) == '5.0'
714
    assert tmpl.render(Context({'term1': 2.5, 'term2': '2'})) == '5.0'
715
    assert tmpl.render(Context({'term1': '2.5', 'term2': '2'})) == '5.0'
716
    assert tmpl.render(Context({'term1': '', 'term2': '2'})) == '0'
717
    assert tmpl.render(Context({'term1': 2.5, 'term2': ''})) == '0.0'
718
    assert tmpl.render(Context({'term1': '', 'term2': ''})) == '0'
719
    assert tmpl.render(Context({'term1': 0, 'term2': ''})) == '0'
720
    assert tmpl.render(Context({'term1': '', 'term2': 0})) == '0'
721
    assert tmpl.render(Context({'term1': 0, 'term2': 0})) == '0'
722

  
723
    # divide
724
    tmpl = Template('{{ term1|divide:term2 }}')
725
    assert tmpl.render(Context({'term1': 16, 'term2': 2})) == '8'
726
    assert tmpl.render(Context({'term1': 6, 'term2': 0.75})) == '8'
727
    assert tmpl.render(Context({'term1': '6', 'term2': 0.75})) == '8'
728
    assert tmpl.render(Context({'term1': 6, 'term2': '0.75'})) == '8'
729
    assert tmpl.render(Context({'term1': '6', 'term2': '0.75'})) == '8'
730
    assert tmpl.render(Context({'term1': '', 'term2': '2'})) == '0'
731
    assert tmpl.render(Context({'term1': 6, 'term2': ''})) == ''
732
    assert tmpl.render(Context({'term1': '', 'term2': ''})) == ''
733
    assert tmpl.render(Context({'term1': 0, 'term2': ''})) == ''
734
    assert tmpl.render(Context({'term1': '', 'term2': 0})) == ''
735
    assert tmpl.render(Context({'term1': 0, 'term2': 0})) == ''
736
    tmpl = Template('{{ term1|divide:term2|decimal:2 }}')
737
    assert tmpl.render(Context({'term1': 2, 'term2': 3})) == '0.67'
738

  
739

  
740
def test_concatenation_templatetag():
741
    tmpl = Template('{{ term1|add:term2 }}')
742

  
743
    # fallback to Django native add filter
744
    assert tmpl.render(Context({'term1': 'foo', 'term2': 'bar'})) == 'foobar'
745
    assert tmpl.render(Context({'term1': 'foo', 'term2': ''})) == 'foo'
746
    assert tmpl.render(Context({'term1': 'foo', 'term2': None})) == 'foo'
747
    assert tmpl.render(Context({'term1': 'foo', 'term2': 0})) == ''
748
    assert tmpl.render(Context({'term1': '', 'term2': 'bar'})) == 'bar'
749
    assert tmpl.render(Context({'term1': '', 'term2': ''})) == ''
750
    assert tmpl.render(Context({'term1': '', 'term2': None})) == ''
751
    assert tmpl.render(Context({'term1': None, 'term2': 'bar'})) == 'bar'
752
    assert tmpl.render(Context({'term1': None, 'term2': ''})) == ''
753
    assert tmpl.render(Context({'term1': None, 'term2': None})) == ''
754
    assert tmpl.render(Context({'term1': 0, 'term2': 'bar'})) == ''
755

  
756

  
757
def test_rounding_templatetag():
758
    # ceil
759
    tmpl = Template('{{ value|ceil }}')
760
    assert tmpl.render(Context({'value': 3.14})) == '4'
761
    assert tmpl.render(Context({'value': 3.99})) == '4'
762
    assert tmpl.render(Context({'value': -3.14})) == '-3'
763
    assert tmpl.render(Context({'value': -3.99})) == '-3'
764
    assert tmpl.render(Context({'value': 0})) == '0'
765
    assert tmpl.render(Context({'value': '3.14'})) == '4'
766
    assert tmpl.render(Context({'value': '3.99'})) == '4'
767
    assert tmpl.render(Context({'value': '-3.14'})) == '-3'
768
    assert tmpl.render(Context({'value': '-3.99'})) == '-3'
769
    assert tmpl.render(Context({'value': '0'})) == '0'
770
    assert tmpl.render(Context({'value': 'not a number'})) == '0'
771
    assert tmpl.render(Context({'value': ''})) == '0'
772
    assert tmpl.render(Context({'value': None})) == '0'
773

  
774
    # floor
775
    tmpl = Template('{{ value|floor }}')
776
    assert tmpl.render(Context({'value': 3.14})) == '3'
777
    assert tmpl.render(Context({'value': 3.99})) == '3'
778
    assert tmpl.render(Context({'value': -3.14})) == '-4'
779
    assert tmpl.render(Context({'value': -3.99})) == '-4'
780
    assert tmpl.render(Context({'value': 0})) == '0'
781
    assert tmpl.render(Context({'value': '3.14'})) == '3'
782
    assert tmpl.render(Context({'value': '3.99'})) == '3'
783
    assert tmpl.render(Context({'value': '-3.14'})) == '-4'
784
    assert tmpl.render(Context({'value': '-3.99'})) == '-4'
785
    assert tmpl.render(Context({'value': '0'})) == '0'
786
    assert tmpl.render(Context({'value': 'not a number'})) == '0'
787
    assert tmpl.render(Context({'value': ''})) == '0'
788
    assert tmpl.render(Context({'value': None})) == '0'
789

  
790

  
791
def test_abs_templatetag():
792
    tmpl = Template('{{ value|abs }}')
793
    assert tmpl.render(Context({'value': 3.14})) == '3.14'
794
    assert tmpl.render(Context({'value': -3.14})) == '3.14'
795
    assert tmpl.render(Context({'value': 0})) == '0'
796
    assert tmpl.render(Context({'value': '3.14'})) == '3.14'
797
    assert tmpl.render(Context({'value': '-3.14'})) == '3.14'
798
    assert tmpl.render(Context({'value': '0'})) == '0'
799
    assert tmpl.render(Context({'value': 'not a number'})) == '0'
800
    assert tmpl.render(Context({'value': ''})) == '0'
801
    assert tmpl.render(Context({'value': None})) == '0'
802

  
803

  
804 604
def test_phonenumber_fr():
805 605
    t = Template('{{ number|phonenumber_fr }}')
806 606
    assert t.render(Context({'number': '01 23 45 67 89'})) == '01 23 45 67 89'
......
837 637
    with override_settings(LANGUAGE_CODE='fr-fr'):
838 638
        assert tmpl.render(Context({'foo': 10000})) == '10 000'
839 639
        assert tmpl.render(Context({'foo': '10000'})) == '10 000'
840

  
841

  
842
def test_sum():
843
    t = Template('{{ "2 29.5 9,5 .5"|split|sum }}')
844
    assert t.render(Context()) == '41.5'
845
    t = Template('{{ list|sum }}')
846
    assert t.render(Context({'list': [1, 2, '3']})) == '6'
847
    assert t.render(Context({'list': [1, 2, 'x']})) == '3'
848
    assert t.render(Context({'list': [None, 2.0, 'x']})) == '2'
849
    assert t.render(Context({'list': []})) == '0'
850
    assert t.render(Context({'list': None})) == ''  # list is not iterable
851
    assert t.render(Context({'list': '123'})) == ''  # consider string as not iterable
852
    assert t.render(Context()) == ''
853
-