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}}'
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)
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
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 == '||'
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.'
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\').'
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')
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()
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()
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}'
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.'
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)
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\').'
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)
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).'
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')
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')
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.'
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
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}
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
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()
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'
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')
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.'
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'))
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
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()
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)