Exemplo n.º 1
0
def test_default_instanciation():
    """Check Rectangle's instanciation."""
    r = Rectangle()
    assert r.type == 'Rectangle'
    assert r.width == Number(1)
    assert r.length == Number(2)
    assert r.area == Number(2)
def test_exponented():
    """Check initialization."""
    assert Exponented(Number(3)).printed == '3'
    assert Exponented(3, exponent=2).printed == '3^{2}'
    assert Exponented(Number(-3), exponent=2).printed == '(-3)^{2}'
    assert Exponented(3, exponent=Exponented(6, exponent=2))\
        .printed == '3^{6^{2}}'
Exemplo n.º 3
0
def test_instanciation():
    """Check Angle's instanciation."""
    pointO = Point(0, 0, 'O')
    pointI = Point(1, 0, 'I')
    pointJ = Point(0, 1, 'J')
    pointA = Point(1, 1, 'A')
    theta = Angle(pointI, pointO, pointJ, mark_right=True)
    assert repr(theta) == 'Angle(I, O, J)'
    assert theta.measure == Number('90')
    assert isinstance(theta.decoration, AngleDecoration)
    assert theta.decoration.label is None
    assert theta.decoration.variety is None
    assert theta.mark_right
    assert theta.vertex == pointO
    assert theta.points == [pointI, pointO, pointJ]
    theta = Angle(pointA, pointO, pointI, decoration=AngleDecoration())
    assert theta.measure == Number('315')
    assert Angle(pointI, pointO, pointA).measure == Number('45')
    assert not theta.mark_right
    assert theta.vertex == pointO
    assert theta.points == [pointA, pointO, pointI]
    theta = Angle(pointI, pointO, 60)
    assert theta.vertex == pointO
    assert theta.points[2] == Point('0.5', '0.866', 'I\'')
    A = Point(0, 0, 'A')
    X = Point(6, 1, 'X')
    Y = Point(3, 5, 'Y')
    α = Angle(X, A, Y)
    assert α.winding == 'anticlockwise'
    assert α.arms[0] == Bipoint(A, X)
    assert α.arms[1] == Bipoint(A, Y)
Exemplo n.º 4
0
def test_nonzero_digits_nb():
    """Check nonzero_digits_nb() in different cases."""
    assert Number('0').nonzero_digits_nb() == 0
    assert Number('2.0').nonzero_digits_nb() == 1
    assert Number('0.2').nonzero_digits_nb() == 1
    assert Number('0.104').nonzero_digits_nb() == 2
    assert Number('30.506').nonzero_digits_nb() == 3
Exemplo n.º 5
0
def test_length(A, B, D):
    """Check length is correct."""
    t = LineSegment(A, D)
    assert t.length == Number(4)
    s = LineSegment(A, B)
    assert s.length.rounded(Decimal('0.0001')) == Number('1.4142')
    s = LineSegment(B, A)
    assert s.length.rounded(Decimal('0.0001')) == Number('1.4142')
def test_instanciation():
    """Check IsoscelesTriangle's instanciation."""
    t = IsoscelesTriangle()
    assert t.type == 'IsoscelesTriangle'
    assert t.base_length == Number('1.5')
    assert t.equal_legs_length == Number('1')
    assert t.sides[1].mark == '||'
    assert t.sides[2].mark == '||'
Exemplo n.º 7
0
def test_digit():
    """Check Number.digit"""
    assert Number('569.72').digit(Decimal('10')) == 6
    assert Number('569.72').digit(Decimal('0.001')) == 0
    assert Number('569.72').digit(Decimal('1000')) == 0
    with pytest.raises(ValueError) as excinfo:
        Number('569.72').digit(40)
    assert str(excinfo.value) == 'Expect a power of ten, found 40 instead.'
Exemplo n.º 8
0
def test_divisions_errors():
    """Check divisions exceptions."""
    with pytest.raises(NotImplementedError) as excinfo:
        Number(6, unit=Unit('cm', exponent=Number(2))) \
            / Number(6, unit=Unit('dm', exponent=Number(3)))
    assert str(excinfo.value) == 'Cannot yet handle a ' \
                                 'division of Number(\'6 cm^2\') ' \
                                 'by Number(\'6 dm^3\').'
Exemplo n.º 9
0
def test_Number_equality():
    """Check Number __eq__ and __ne__."""
    assert Number(4) == Decimal(4)
    assert Number(4) == 4
    assert not (Number(4, unit='cm') == 4)
    assert Number(4, unit='cm') != 4
    assert Number(4) != Decimal(5)
    assert Number(4, unit='cm') != Decimal(4)
    assert Number(4, unit='cm') != Number(5, unit='cm')
    assert Number(4, unit='cm') != Number(4, unit='dm')
Exemplo n.º 10
0
def test_is_power_of_10():
    """Check is_power_of_10() in different cases."""
    for n in [1, 10, 100, 1000, 10000, -1, -10, -100]:
        assert Number(n).is_power_of_10()
    for n in [Decimal('0.1'), Decimal('0.01'), Decimal('0.001'),
              Decimal('-0.1'), Decimal('-0.01'), Decimal('-0.001')]:
        assert Number(n).is_power_of_10()
    for n in [0, 2, Decimal('0.5'), Decimal('-0.02'), Decimal('10.09'),
              1001, -999]:
        assert not Number(n).is_power_of_10()
Exemplo n.º 11
0
def test_split_exceptions():
    """Check split() raises exceptions in expected cases."""
    with pytest.raises(ValueError):
        Number(10).split(operation='*')
    with pytest.warns(UserWarning):
        Number(1).split()
    with pytest.warns(UserWarning):
        Number('0.1').split()
    with pytest.warns(UserWarning):
        Number('0.01').split()
Exemplo n.º 12
0
def test_instanciation():
    """Check Fraction's instanciation."""
    f = Fraction(5, 8)
    assert f.sign == '+'
    assert f.numerator == 5
    assert f.numerator == Number('5')
    assert f.denominator == 8
    assert f.denominator == Number('8')
    f = Fraction('+', 5, 8)
    assert f.sign == '+'
    assert f.numerator == 5
    assert f.numerator == Number('5')
    assert f.denominator == 8
    assert f.denominator == Number('8')
    f = Fraction('-', 5, 8)
    assert f.sign == '-'
    assert f.numerator == 5
    assert f.numerator == Number('5')
    assert f.denominator == 8
    assert f.denominator == Number('8')
    f = Fraction('-', -5, 8)
    assert f.sign == '-'
    assert f.numerator == -5
    assert f.numerator == Number('-5')
    assert f.denominator == 8
    assert f.denominator == Number('8')
    f = Fraction(from_decimal=Number('0.67'))
    assert f.numerator == 67
    assert f.denominator == 100
    assert f.printed == r'\dfrac{67}{100}'
Exemplo n.º 13
0
def test_AngleDecoration():
    assert repr(AngleDecoration()) == 'AngleDecoration(variety=single; '\
        'hatchmark=None; label=default; color=None; thickness=thick; '\
        'radius=0.25 cm; eccentricity=2.6)'
    ad = AngleDecoration(radius=Number(1, unit='cm'))
    assert ad.arrow_tips is None
    assert repr(ad) == \
        'AngleDecoration(variety=single; '\
        'hatchmark=None; label=default; color=None; thickness=thick; '\
        'radius=1 cm; eccentricity=1.4)'
    ad.radius = Number(2, unit='cm')
    assert repr(ad) == \
        'AngleDecoration(variety=single; '\
        'hatchmark=None; label=default; color=None; thickness=thick; '\
        'radius=2 cm; eccentricity=1.2)'
    assert AngleDecoration().tikz_attributes() \
        == '[draw, thick, angle radius = 0.25 cm]'
    assert AngleDecoration(color='green', thickness='thin').tikz_attributes() \
        == '[draw, thin, angle radius = 0.25 cm, green]'
    assert AngleDecoration(radius=Number('0.5', unit=Unit('cm'))) \
        .tikz_attributes() == '[draw, thick, angle radius = 0.5 cm]'
    with pytest.raises(ValueError) as excinfo:
        AngleDecoration(radius=Number(2, unit='cm'), gap=None)
    assert str(excinfo.value) == 'Cannot calculate the eccentricity if gap '\
        'is None.'
    with pytest.raises(TypeError) as excinfo:
        AngleDecoration(radius='2 cm')
    assert str(excinfo.value) == 'Expected a number as radius. Got ' \
        '<class \'str\'> instead.'
    with pytest.raises(TypeError) as excinfo:
        AngleDecoration(gap='2 cm')
    assert str(excinfo.value) == 'The gap value must be None or a number. '\
        'Found \'2 cm\' instead (type: <class \'str\'>).'
    with pytest.raises(TypeError) as excinfo:
        AngleDecoration().tikz_attributes(radius_coeff='a')
    assert str(excinfo.value) == 'radius_coeff must be a number, '\
        'found <class \'str\'> instead.'
    with pytest.raises(TypeError) as excinfo:
        AngleDecoration(hatchmark='unknown')
    assert str(excinfo.value) == 'AngleDecoration\'s hatchmark can be None, '\
        '\'singledash\', \'doubledash\' or \'tripledash\'. ' \
        'Found \'unknown\' instead (type: <class \'str\'>).'
    with pytest.raises(TypeError) as excinfo:
        AngleDecoration(eccentricity='a')
    assert str(excinfo.value) == 'The eccentricity of an AngleDecoration '\
        'must be None or a Number. Found <class \'str\'> instead.'
    with pytest.raises(RuntimeError) as excinfo:
        AngleDecoration().generate_tikz('A', 'B')
    assert str(excinfo.value) == 'Three Points\' names must be provided to '\
        'generate the AngleDecoration. Found 2 arguments instead.'
    with pytest.raises(TypeError) as excinfo:
        AngleDecoration(do_draw='a')
    assert str(excinfo.value) == 'do_draw must be a boolean; '\
        'got <class \'str\'> instead.'
Exemplo n.º 14
0
def test_measures_2D():
    """Check Angle's measure."""
    Ω = Point(0, 0, 'Ω')
    X = Point(12, 2, 'X')
    Y = Point(-6, -1, 'Y')
    α = Angle(X, Ω, Y)
    X = Point(6, 1, 'X')
    Y = Point(-6, -1, 'Y')
    α = Angle(X, Ω, Y)
    assert α.measure.rounded(Number('0.001')) == 180
    β = Angle(X, Ω, Point(1, -6, 'Z'))
    assert β.measure.rounded(Number('0.001')) == Number(270)
Exemplo n.º 15
0
def test_multiplications_errors():
    """Check subtractions exceptions."""
    with pytest.raises(TypeError) as excinfo:
        8 * Sign('-')
    assert str(excinfo.value) == 'Cannot multiply a Sign by a <class \'int\'>.'

    with pytest.raises(NotImplementedError) as excinfo:
        Number(6, unit=Unit('cm', exponent=Number(2))) \
            * Number(6, unit=Unit('dm', exponent=Number(3)))
    assert str(excinfo.value) == 'Cannot yet handle a ' \
                                 'multiplication of Number(\'6 cm^2\') ' \
                                 'by Number(\'6 dm^3\').'
Exemplo n.º 16
0
def test_power():
    """Check __pow__, __rpow__, __ipow__."""
    assert isinstance(pow(Number(4), Number(4)), Number)
    assert isinstance(pow(4, Number(4)), Number)
    assert isinstance(pow(Number(4), 4), Number)
    assert isinstance(Number(4) ** Number(4), Number)
    assert isinstance(4 ** Number(4), Number)
    assert isinstance(Number(4) ** 4, Number)
    n = Number(4)
    n **= Number(4)
    assert isinstance(n, Number)
    n **= 4
    assert isinstance(n, Number)
Exemplo n.º 17
0
def test_sides_labeling(pointO, pointA, pointB, pointC):
    """Check Polygon's sides' labeling."""
    p = Polygon(pointO, pointA, pointB, pointC)
    with pytest.raises(ValueError) as excinfo:
        p.setup_labels(['', '', ''])
    assert str(excinfo.value) == 'The number of labels (3) should be equal ' \
        'to the number of line segments (4).'
    p.setup_labels([
        Number(7, unit='cm'),
        Number(5, unit='cm'),
        Number(6, unit='cm'),
        Number(4, unit='cm')
    ])
    assert all(s.label_mask is None for s in p.sides)
    with pytest.raises(ValueError) as excinfo:
        p.setup_labels([
            Number(7, unit='cm'),
            Number(5, unit='cm'),
            Number(6, unit='cm'),
            Number(4, unit='cm')
        ],
                       masks=['', ''])
    assert str(excinfo.value) == 'The number of label masks (2) should be '\
        'equal to the number of line segments (4).'
    with pytest.raises(ValueError) as excinfo:
        p.setup_labels()
    assert str(excinfo.value) == 'There must be at least either labels or '\
        'masks to setup. Both are undefined (None).'
Exemplo n.º 18
0
def test_lbl_perimeter(pointO, pointA, pointB, pointC):
    """Check Polygon's sides' labeling."""
    p = Polygon(pointO, pointA, pointB, pointC)
    with pytest.raises(RuntimeError) as excinfo:
        p.lbl_perimeter
    assert str(excinfo.value) == 'All labels must have been set as Numbers ' \
        'in order to calculate the perimeter from labels.'
    p.setup_labels([
        Number(7, unit='cm'),
        Number(5, unit='cm'),
        Number(6, unit='cm'),
        Number(4, unit='cm')
    ],
                   masks=[None, None, '?', ' '])
    assert p.lbl_perimeter == Number(22, unit='cm')
Exemplo n.º 19
0
def test_subtractions():
    """Check __sub__, __rsub__, __isub__, __neg__."""
    assert isinstance(Number(4) - Number(4), Number)
    assert isinstance(4 - Number(4), Number)
    assert isinstance(Number(4) - 4, Number)
    n = Number(4)
    n -= Number(1)
    assert isinstance(n, Number)
    n -= 1
    assert isinstance(n, Number)
    assert isinstance(-n, Number)
    assert Number(9, unit='cm') - Number(3, unit='cm') == Number(6, unit='cm')
Exemplo n.º 20
0
def test_marked_angles():
    """Check Angle's instanciation."""
    pointO = Point(0, 0, 'O')
    pointI = Point(1, 0, 'I')
    pointJ = Point(0, 1, 'J')
    required.tikz_library['angles'] = False
    theta = Angle(pointI, pointO, pointJ)
    assert theta.tikz_decorations() == ''
    theta.decoration = AngleDecoration(color='red',
                                       thickness='ultra thick',
                                       radius=Number(2))
    assert theta.tikz_decorations() \
        == 'pic [draw, ultra thick, angle radius = 2, red] {angle = I--O--J}'
    assert required.tikz_library['angles']
    required.tikz_library['angles'] = False
    theta.mark_right = True
    theta.decoration = AngleDecoration()
    assert theta.label is None
    assert theta.tikz_decorations() == ''
    assert not required.tikz_library['angles']
    assert theta.tikz_rightangle_mark() == \
        '\draw[thick, cm={cos(0), sin(0), -sin(0), cos(0), (O)}]' \
        ' (0.25 cm, 0) -- (0.25 cm, 0.25 cm) -- (0, 0.25 cm);'
    assert theta.tikz_rightangle_mark(winding='clockwise') == \
        '\draw[thick, cm={cos(0), sin(0), -sin(0), cos(0), (O)}]' \
        ' (0.25 cm, 0) -- (0.25 cm, -0.25 cm) -- (0, -0.25 cm);'
    with pytest.raises(ValueError) as excinfo:
        theta.tikz_rightangle_mark(winding=None)
    assert str(excinfo.value) == 'Expect \'clockwise\' or \'anticlockwise\'. '\
        'Found \'None\' instead.'
Exemplo n.º 21
0
def test_reducing():
    """Check reducing is correct."""
    assert not Fraction(5, 8).is_reducible()
    assert Fraction(6, 8).is_reducible()
    assert Fraction(5, 8).reduced() == Fraction(5, 8)
    assert Fraction(6, 8).reduced() == Fraction(3, 4)
    with pytest.raises(TypeError) as excinfo:
        Fraction(6, 8).reduced_by('2')
    assert str(excinfo.value) == 'A Fraction can be reduced only by an ' \
        'integer, got <class \'str\'> instead.'
    with pytest.raises(TypeError) as excinfo:
        Fraction(6, 8).reduced_by(Number('2.4'))
    assert str(excinfo.value) == 'A Fraction can be reduced only by an ' \
        'integer, got 2.4 instead.'
    with pytest.raises(ValueError) as excinfo:
        Fraction(6, 8).reduced_by(4)
    assert str(excinfo.value) == 'Cannot divide 6 by 4 and get an integer.'
    with pytest.raises(ValueError) as excinfo:
        Fraction(6, 8).reduced_by(3)
    assert str(excinfo.value) == 'Cannot divide 8 by 3 and get an integer.'
    assert Fraction(6, 8).reduced_by(2) == Fraction(3, 4)
    assert Fraction(16, 8).reduced_by(8) == 2
    assert Fraction('-', 6, 8).reduced_by(2) == Fraction('-', 3, 4)
    assert Fraction('-', 16, 8).reduced_by(8) == -2
    assert Fraction(-6, 8).reduced_by(2) == Fraction(-3, 4)
    assert Fraction(-16, 8).reduced_by(8) == -2
    assert Fraction(6, -8).reduced_by(2) == Fraction(3, -4)
    assert Fraction(16, -8).reduced_by(8) == -2
    assert Fraction(6, 8).reduced_by(-2) == Fraction(3, 4)
    assert Fraction(16, 8).reduced_by(-8) == 2
    with pytest.raises(StopFractionReduction) as excinfo:
        Fraction(3, 4).reduce()
    assert str(excinfo.value) == 'Fraction(3, 4) can no further be reduced.'
    assert Fraction(6, 8).reduce() == Fraction(3, 4)
    assert Fraction(9, 3).reduce() == 3
Exemplo n.º 22
0
def test_digits():
    """Check Number.digits()"""
    assert Number('569.72').digits == {Decimal('100'): 5,
                                       Decimal('10'): 6,
                                       Decimal('1'): 9,
                                       Decimal('0.1'): 7,
                                       Decimal('0.01'): 2}
Exemplo n.º 23
0
def test_Unit():
    """Check the Unit class."""
    assert Unit('cm').printed == r'\si{cm}'
    assert Unit('cm', exponent=Number(2)).printed == r'\si{cm^{2}}'
    u = Unit('cm')
    assert Unit(u).printed == r'\si{cm}'
    assert Unit(u, exponent=2).printed == r'\si{cm^{2}}'
    assert Unit(u, exponent=Number(3)).printed == r'\si{cm^{3}}'
    u = Unit('cm', exponent=2)
    assert Unit(u).printed == r'\si{cm^{2}}'
    v = Unit('cm', exponent=2)
    assert u == v
    w = Unit(v, exponent=3)
    assert v != w
    w = Unit(v, exponent=2)
    assert v == w
    assert u != 6
Exemplo n.º 24
0
def test_point_at():
    """Check point_at is correct."""
    s = LineSegment(Point(0, 0, 'A'), Point(1, 1, 'B'))
    with pytest.raises(TypeError) as excinfo:
        s.point_at('a')
    assert str(excinfo.value) == 'position must be a number, found ' \
        '<class \'str\'> instead.'
    assert s.point_at(Number('0.5')) == s.midpoint()
    assert s.point_at(Number('0.75')) == Point('0.75', '0.75')
    assert s.point_at(Number(2)) == Point(2, 2)
    assert s.point_at(0) == Point(0, 0)
    assert s.point_at(1) == Point(1, 1)
    assert s.point_at(-2) == Point(-2, -2)
    s = LineSegment(Point(1, 1, 'A'), Point(3, 4, 'B'))
    assert s.point_at(Number('0.8')) == Point('2.6', '3.4')
    assert s.point_at(2) == Point(5, 7)
    assert s.point_at(Number('0.5')) == s.midpoint()
Exemplo n.º 25
0
def test_conversions():
    """Check numbers' conversions."""
    i = Number(6, unit='m')
    j = i.converted_to('cm')
    assert str(j.unit) == 'cm'
    assert j.uiprinted == '600 cm'
    i = Number('0.25', unit='kg')
    j = i.converted_to('kg')
    assert str(j.unit) == 'kg'
    assert j.uiprinted == '0.25 kg'
    i = Number('1.096', unit='L')
    j = i.converted_to('hL')
    assert str(j.unit) == 'hL'
    assert j.uiprinted == '0.01096 hL'
Exemplo n.º 26
0
def test_quantize():
    """Check quantize() is correct."""
    assert Number(2).quantize(Decimal('0.01')).printed == '2.00'
    assert Number('3.6').quantize(Decimal('0.01')).printed == '3.60'
    assert Number('3.6', unit='mL').quantize(Decimal('0.01')) \
        == Number('3.60', unit='mL')
    assert Number('3.6', unit='mL').quantize(Number('0.01')) \
        == Number('3.60', unit='mL')
Exemplo n.º 27
0
def test_cut_exceptions():
    """Check cut() raises exceptions in expected cases."""
    with pytest.raises(ValueError) as excinfo:
        Number(10).cut(overlap=-1)
    assert str(excinfo.value) == 'overlap must be a positive int. Got a ' \
        'negative int instead.'
    with pytest.raises(TypeError) as excinfo:
        Number(10).cut(overlap='a')
    assert str(excinfo.value) == 'When overlap is used, it must be an int. ' \
        'Got a <class \'str\'> instead.'
    with pytest.raises(ValueError) as excinfo:
        Number('4.3').cut(overlap=1)
    assert str(excinfo.value) == 'Given overlap is too high.'
    with pytest.raises(ValueError) as excinfo:
        Number('4.15').cut(overlap=1)
    assert str(excinfo.value) == 'Given overlap is too high.'
    with pytest.raises(ValueError) as excinfo:
        Number('4.683').cut(overlap=2)
    assert str(excinfo.value) == 'Only 0 <= overlap <= 1 is implemented yet.'
Exemplo n.º 28
0
def test_rotation3D():
    """Check 3D rotating."""
    pointO = Point(0, 0, 0, 'O')
    pointA = Point(1, 0, 0, 'A')
    with pytest.raises(TypeError) as excinfo:
        pointA.rotate(pointO, Number(30), pointO)
    assert str(excinfo.value) == 'Expected either None or a Vector as '\
        'axis, found Point O(0, 0, 0) instead.'
    pointZ = Point(0, 0, 1, 'Z')
    vz = Vector(pointO, pointZ)
    assert pointA.rotate(pointO, Number(30), vz).coordinates \
        == (Number('0.866'), Number('0.5'), Number('0'))
    pointY = Point(0, 1, 0, 'Y')
    vy = Vector(pointO, pointY)
    assert pointA.rotate(pointO, Number(30), vy).coordinates \
        == (Number('0.866'), Number('0'), Number('-0.5'))
Exemplo n.º 29
0
def test_lowest_nonzero_digit_index():
    """Check lowest_nonzero_digit_index() in different cases."""
    assert Number('0').lowest_nonzero_digit_index() is None
    assert Number('1.2').lowest_nonzero_digit_index() == 1
    assert Number('1.09').lowest_nonzero_digit_index() == 2
    assert Number('4.006').lowest_nonzero_digit_index() == 3
    assert Number('40').lowest_nonzero_digit_index() == -1
    assert Number('300').lowest_nonzero_digit_index() == -2
    assert Number('6000').lowest_nonzero_digit_index() == -3
Exemplo n.º 30
0
def test_instanciation():
    """Check Point's instanciation."""
    p = Point(0, 0, 'A')
    assert not p.three_dimensional
    assert p.x == p.y == 0
    assert p.name == 'A'
    assert p.label == 'A'
    p = Point(0, 0, 'A', label='?')
    assert p.name == 'A'
    assert p.label == '?'
    p = Point('0.1', '0.7', 'B')
    assert p.x == Number('0.1')
    assert p.y == Number('0.7')
    p = Point(0, 0, None)
    assert p.name is None
    p = Point(0.1, 0.7, 'B')
    assert p.x == Number('0.1')
    assert p.y == Number('0.7')
    p = Point(0, 0, 0, 'O')
    assert p.three_dimensional
    def __init__(self, build_data, **options):
        """
        :param build_data: data used to build the question, in the form of a
        pair of numbers (a, b). Question will be "Calculate a1 × b + a2 × b"
        where a1 + a2 = a. Factors of each product may be swapped.
        :type build_data: tuple
        """
        super().setup("minimal", **options)
        # super().setup("nb_variants", nb=build_data, **options)
        self.transduration = 21
        if not is_integer(build_data[1]):
            self.transduration = 30
        split_as = options.get('split_as', 'dig1')
        split_options = {'int_as_halves': False,
                         'int_as_quarters': False,
                         'int_as_halves_or_quarters': False}
        if split_as in ['halves', 'quarters', 'halves_or_quarters']:
            split_options.update({'int_as_' + split_as: True})
        elif split_as == 'dig1':
            split_options.update({'dig': 1})
        a, b = build_data
        a, b = Number(a), Number(b)
        a1, a2 = a.split(**split_options)
        n1n2 = [a1, b]
        n3n4 = [a2, b]
        if options.get('do_shuffle', True):
            random.shuffle(n1n2)
            random.shuffle(n3n4)
        n1, n2 = n1n2.pop(), n1n2.pop()
        n3, n4 = n3n4.pop(), n3n4.pop()
        super().setup("numbers", nb=[n1, n2, n3, n4], shuffle_nbs=False,
                      **options)

        self.math_expr = r'{} \times {} + {} \times {}'\
            .format(self.nb1.printed, self.nb2.printed, self.nb3.printed,
                    self.nb4.printed)
        self.answer = (a * b).standardized()
Exemplo n.º 32
0
def merge_nb_unit_pairs(arg: object, w_prefix=''):
    r"""
    Merge all occurences of {nbN} {\*_unit} in arg.wording into {nbN\_\*_unit}.

    In the same time, the matching attribute arg.nbN\_\*_unit is set to
    Number(nbN, unit=Unit(arg.\*_unit))
    (the possible exponent is taken into account too).

    :param arg: the object whose attribute wording will be processed. It must
      have a wording attribute as well as nbN and \*_unit attributes.
    :type arg: object
    :rtype: None

    :Example:

    >>> class Object(object): pass
    ...
    >>> arg = Object()
    >>> arg.wording = 'I have {nb1} {capacity_unit} of water.'
    >>> arg.nb1 = 2
    >>> arg.capacity_unit = 'L'
    >>> merge_nb_unit_pairs(arg)
    >>> arg.wording
    'I have {nb1_capacity_unit} of water.'
    >>> arg.nb1_capacity_unit
    '\\SI{2}{L}'
    """
    w_object_wording = getattr(arg, w_prefix + 'wording')
    logger = settings.dbg_logger.getChild('wording.merge_nb_unit_pairs')
    logger.debug("Retrieved wording: " + w_object_wording + "\n")
    new_words_list = []
    words = w_object_wording.split()
    skip_next_w = False
    for i, w in enumerate(words):
        next_w = words[i + 1] if i <= len(words) - 2 else None
        logger.debug("w= " + w + " next_w= " + str(next_w))
        next_w_is_a_unit = False
        if next_w is not None and (is_unit(next_w) or is_unitN(next_w)):
            next_w_is_a_unit = True
        logger.debug(" next_w_is_a_unit: " + str(next_w_is_a_unit) + "\n")
        if is_wrapped(w) and w[1:3] == "nb" and next_w_is_a_unit:
            n = w[1:-1]
            u = ""
            if is_wrapped(next_w):
                u = next_w[1:-1]
                p = ""
            elif is_wrapped_P(next_w):
                u = next_w[1:-2]
                p = next_w[-1]
            new_attr_name = n + "_" + u
            expnt = None
            if u.startswith('area'):
                expnt = Number(2)
            elif u.startswith('volume'):
                expnt = Number(3)
            U = Unit(getattr(arg, u), exponent=expnt)
            N = Number(getattr(arg, n), unit=U)
            if physical_quantity(U) == 'currency':
                if is_integer(N):
                    N = N.quantize(Number('1'))
                else:
                    N = N.quantize(Number('0.01'))
            new_val = N.printed
            new_words_list += ["{" + new_attr_name + "}" + p]
            logger.debug(" setattr: name=" + str(new_attr_name) + "; val= "
                         + str(new_val) + "\n")
            setattr(arg, new_attr_name, new_val)
            skip_next_w = True
        elif skip_next_w:
            skip_next_w = False
        else:
            new_words_list += [w]
    new_wording = " ".join(new_words_list)
    logger.debug(" setattr: name=" + w_prefix + 'wording' + "; val= "
                 + new_wording + "\n")
    setattr(arg, w_prefix + 'wording', new_wording)