Skip to content

Commit 1d75dc0

Browse files
LucasLefevrerrahir
authored andcommitted
m
1 parent 814516a commit 1d75dc0

11 files changed

+2215
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
from odoo.addons.base.maintenance.migrations.testing import UnitTestCase
2+
from odoo.addons.base.maintenance.migrations.util.spreadsheet.parser import (
3+
BinaryOperation,
4+
FunctionCall,
5+
Literal,
6+
UnaryOperation,
7+
ast_to_string,
8+
parse,
9+
)
10+
11+
12+
class SpreadsheetParserTest(UnitTestCase):
13+
def test_can_parse_a_function_call_with_no_argument(self):
14+
self.assertEqual(parse("RAND()"), FunctionCall("RAND", []))
15+
16+
def test_can_parse_a_function_call_with_one_argument(self):
17+
self.assertEqual(
18+
parse("SUM(1)"),
19+
FunctionCall("SUM", [Literal("NUMBER", "1")]),
20+
)
21+
22+
def test_can_parse_a_function_call_with_function_argument(self):
23+
self.assertEqual(
24+
parse("SUM(UMINUS(1))"),
25+
FunctionCall("SUM", [FunctionCall("UMINUS", [Literal("NUMBER", "1")])]),
26+
)
27+
28+
def test_can_parse_a_function_call_with_sub_expressions_as_argument(self):
29+
self.assertEqual(
30+
parse("IF(A1 > 0, 1, 2)"),
31+
FunctionCall(
32+
"IF",
33+
[
34+
BinaryOperation(">", Literal("UNKNOWN", "A1"), Literal("NUMBER", "0")),
35+
Literal("NUMBER", "1"),
36+
Literal("NUMBER", "2"),
37+
],
38+
),
39+
)
40+
41+
def test_add_a_unknown_token_for_empty_arguments(self):
42+
self.assertEqual(
43+
parse("SUM(1,)"),
44+
FunctionCall("SUM", [Literal("NUMBER", "1"), Literal("EMPTY", "")]),
45+
)
46+
47+
self.assertEqual(
48+
parse("SUM(,1)"),
49+
FunctionCall("SUM", [Literal("EMPTY", ""), Literal("NUMBER", "1")]),
50+
)
51+
52+
self.assertEqual(
53+
parse("SUM(,)"),
54+
FunctionCall("SUM", [Literal("EMPTY", ""), Literal("EMPTY", "")]),
55+
)
56+
57+
self.assertEqual(
58+
parse("SUM(,,)"),
59+
FunctionCall("SUM", [Literal("EMPTY", ""), Literal("EMPTY", ""), Literal("EMPTY", "")]),
60+
)
61+
62+
self.assertEqual(
63+
parse("SUM(,,,1)"),
64+
FunctionCall("SUM", [Literal("EMPTY", ""), Literal("EMPTY", ""), Literal("EMPTY", ""), Literal("NUMBER", "1")]),
65+
)
66+
67+
def test_can_parse_unary_operations(self):
68+
self.assertEqual(
69+
parse("-1"),
70+
UnaryOperation("-", Literal("NUMBER", "1")),
71+
)
72+
self.assertEqual(
73+
parse("+1"),
74+
UnaryOperation("+", Literal("NUMBER", "1")),
75+
)
76+
77+
def test_can_parse_numeric_values(self):
78+
self.assertEqual(parse("1"), Literal("NUMBER", "1"))
79+
self.assertEqual(parse("1.5"), Literal("NUMBER", "1.5"))
80+
self.assertEqual(parse("1."), Literal("NUMBER", "1."))
81+
self.assertEqual(parse(".5"), Literal("NUMBER", ".5"))
82+
83+
def test_can_parse_string_values(self):
84+
self.assertEqual(parse('"Hello"'), Literal("STRING", "Hello"))
85+
86+
def test_can_parse_number_expressed_as_percent(self):
87+
self.assertEqual(parse("1%"), Literal("NUMBER", "1%"))
88+
self.assertEqual(parse("100%"), Literal("NUMBER", "100%"))
89+
self.assertEqual(parse("50.0%"), Literal("NUMBER", "50.0%"))
90+
91+
def test_can_parse_binary_operations(self):
92+
self.assertEqual(
93+
parse("2-3"),
94+
BinaryOperation("-", Literal("NUMBER", "2"), Literal("NUMBER", "3")),
95+
)
96+
97+
def test_can_parse_concat_operator(self):
98+
self.assertEqual(
99+
parse("A1&A2"),
100+
BinaryOperation("&", Literal("UNKNOWN", "A1"), Literal("UNKNOWN", "A2")),
101+
)
102+
103+
def test_AND(self):
104+
self.assertEqual(
105+
parse("=AND(true, false)"),
106+
FunctionCall("AND", [Literal("BOOLEAN", "true"), Literal("BOOLEAN", "false")]),
107+
)
108+
self.assertEqual(
109+
parse("=AND(0, tRuE)"),
110+
FunctionCall("AND", [Literal("NUMBER", "0"), Literal("BOOLEAN", "tRuE")]),
111+
)
112+
113+
def test_convert_string(self):
114+
self.assertEqual(ast_to_string(parse('"hello"')), '"hello"')
115+
116+
def test_convert_debugger(self):
117+
self.assertEqual(ast_to_string(parse("?5+2")), "5+2")
118+
119+
def test_convert_boolean(self):
120+
self.assertEqual(ast_to_string(parse("TRUE")), "TRUE")
121+
self.assertEqual(ast_to_string(parse("FALSE")), "FALSE")
122+
123+
def test_convert_unary_operator(self):
124+
self.assertEqual(ast_to_string(parse("-45")), "-45")
125+
self.assertEqual(ast_to_string(parse("+45")), "+45")
126+
self.assertEqual(ast_to_string(parse("-(4+5)")), "-(4+5)")
127+
self.assertEqual(ast_to_string(parse("-4+5")), "-4+5")
128+
self.assertEqual(ast_to_string(parse("-SUM(1)")), "-SUM(1)")
129+
self.assertEqual(ast_to_string(parse("-(1+2)/5")), "-(1+2)/5")
130+
self.assertEqual(ast_to_string(parse("1*-(1+2)")), "1*-(1+2)")
131+
132+
def test_convert_binary_operator(self):
133+
self.assertEqual(ast_to_string(parse("89-45")), "89-45")
134+
self.assertEqual(ast_to_string(parse("1+2+5")), "1+2+5")
135+
self.assertEqual(ast_to_string(parse("(1+2)/5")), "(1+2)/5")
136+
self.assertEqual(ast_to_string(parse("5/(1+2)")), "5/(1+2)")
137+
self.assertEqual(ast_to_string(parse("2/(1*2)")), "2/(1*2)")
138+
self.assertEqual(ast_to_string(parse("1-2+3")), "1-2+3")
139+
self.assertEqual(ast_to_string(parse("1-(2+3)")), "1-(2+3)")
140+
self.assertEqual(ast_to_string(parse("(1+2)-3")), "1+2-3")
141+
self.assertEqual(ast_to_string(parse("(1<5)+5")), "(1<5)+5")
142+
self.assertEqual(ast_to_string(parse("1*(4*2+3)")), "1*(4*2+3)")
143+
self.assertEqual(ast_to_string(parse("1*(4+2*3)")), "1*(4+2*3)")
144+
self.assertEqual(ast_to_string(parse("1*(4*2+3*9)")), "1*(4*2+3*9)")
145+
self.assertEqual(ast_to_string(parse("1*(4-(2+3))")), "1*(4-(2+3))")
146+
self.assertEqual(ast_to_string(parse("1/(2*(2+3))")), "1/(2*(2+3))")
147+
self.assertEqual(ast_to_string(parse("1/((2+3)*2)")), "1/((2+3)*2)")
148+
self.assertEqual(ast_to_string(parse("2<(1<1)")), "2<(1<1)")
149+
self.assertEqual(ast_to_string(parse("2<=(1<1)")), "2<=(1<1)")
150+
self.assertEqual(ast_to_string(parse("2>(1<1)")), "2>(1<1)")
151+
self.assertEqual(ast_to_string(parse("2>=(1<1)")), "2>=(1<1)")
152+
self.assertEqual(ast_to_string(parse("TRUE=1=1")), "TRUE=1=1")
153+
self.assertEqual(ast_to_string(parse("TRUE=(1=1)")), "TRUE=(1=1)")
154+
155+
def test_convert_function(self):
156+
self.assertEqual(ast_to_string(parse("SUM(5,9,8)")), "SUM(5,9,8)")
157+
self.assertEqual(ast_to_string(parse("-SUM(5,9,SUM(5,9,8))")), "-SUM(5,9,SUM(5,9,8))")
158+
159+
def test_convert_references(self):
160+
self.assertEqual(ast_to_string(parse("A10")), "A10")
161+
self.assertEqual(ast_to_string(parse("Sheet1!A10")), "Sheet1!A10")
162+
self.assertEqual(ast_to_string(parse("'Sheet 1'!A10")), "'Sheet 1'!A10")
163+
self.assertEqual(ast_to_string(parse("'Sheet 1'!A10:A11")), "'Sheet 1'!A10:A11")
164+
self.assertEqual(ast_to_string(parse("SUM(A1,A2)")), "SUM(A1,A2)")
165+
166+
def test_convert_strings(self):
167+
self.assertEqual(ast_to_string(parse('"R"')), '"R"')
168+
self.assertEqual(ast_to_string(parse('CONCAT("R", "EM")')), 'CONCAT("R","EM")')
169+
170+
def test_convert_numbers(self):
171+
self.assertEqual(ast_to_string(parse("5")), "5")
172+
self.assertEqual(ast_to_string(parse("5+4")), "5+4")
173+
self.assertEqual(ast_to_string(parse("+5")), "+5")
174+
self.assertEqual(ast_to_string(parse("1%")), "1%")
175+
self.assertEqual(ast_to_string(parse("1.5")), "1.5")
176+
self.assertEqual(ast_to_string(parse("1.")), "1.")
177+
self.assertEqual(ast_to_string(parse(".5")), ".5")

src/util/fields.py

+5
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ def make_index_name(table_name, column_name):
3737
return "%s_%s_index" % (table_name, column_name)
3838

3939

40+
from . import spreadsheet
4041
from .const import ENVIRON
4142
from .context import adapt_context, clean_context
4243
from .domains import _adapt_one_domain, _replace_path, _valid_path_to, adapt_domains
@@ -320,6 +321,8 @@ def adapter(leaf, is_or, negated):
320321
for inh in for_each_inherit(cr, model, skip_inherit):
321322
remove_field(cr, inh.model, fieldname, cascade=cascade, drop_column=drop_column, skip_inherit=skip_inherit)
322323

324+
spreadsheet.remove_field_in_all_spreadsheets(cr, model, fieldname)
325+
323326

324327
def remove_field_metadata(cr, model, fieldname, skip_inherit=()):
325328
"""
@@ -534,6 +537,8 @@ def rename_field(cr, model, old, new, update_references=True, domain_adapter=Non
534537
for inh in for_each_inherit(cr, model, skip_inherit):
535538
rename_field(cr, inh.model, old, new, update_references=update_references, skip_inherit=skip_inherit)
536539

540+
spreadsheet.rename_field_in_all_spreadsheets(cr, model, old, new)
541+
537542

538543
def convert_field_to_html(cr, model, field, skip_inherit=()):
539544
_validate_model(model)

src/util/models.py

+5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import logging
1010
import re
1111

12+
from . import spreadsheet
1213
from .const import ENVIRON
1314
from .fields import IMD_FIELD_PATTERN, remove_field
1415
from .helpers import _ir_values_value, _validate_model, model_of_table, table_of_model
@@ -214,6 +215,8 @@ def remove_model(cr, model, drop_table=True, ignore_m2m=()):
214215
category="Removed Models",
215216
)
216217

218+
spreadsheet.remove_model_in_all_spreadsheets(cr, model)
219+
217220

218221
# compat layer...
219222
delete_model = remove_model
@@ -344,6 +347,8 @@ def rename_model(cr, old, new, rename_table=True):
344347
""".format(col_prefix=col_prefix, old=old.replace(".", r"\."), new=new)
345348
)
346349

350+
spreadsheet.rename_model_in_all_spreadsheets(cr, model, new)
351+
347352

348353
def merge_model(cr, source, target, drop_table=True, fields_mapping=None, ignore_m2m=()):
349354
"""

src/util/spreadsheet/__init__.py

+13
Original file line numberDiff line numberDiff line change
@@ -1 +1,14 @@
1+
import logging
2+
3+
14
from .tokenizer import *
5+
from .parser import *
6+
from .o_spreadsheet import *
7+
8+
9+
_logger = logging.getLogger(__name__)
10+
11+
12+
from .fields import *
13+
from .models import *
14+
from .misc import *

0 commit comments

Comments
 (0)