Skip to content

Commit a1a8e3d

Browse files
committed
fix: account for preceeding line when patching taxonomy
1 parent a32ddbf commit a1a8e3d

File tree

4 files changed

+224
-9
lines changed

4 files changed

+224
-9
lines changed

backend/tests/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ async def database_lifespan(neo4j):
4242
yield driver
4343

4444

45-
@pytest.fixture
45+
@pytest.fixture(scope="function")
4646
async def neo4j_session(database_lifespan, anyio_backend):
4747
async with graph_db.TransactionCtx() as session:
4848
yield session

backend/tests/test_api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def test_add_taxonomy_invalid_branch_name(client):
5454
)
5555

5656
assert response.status_code == 422
57-
assert response.json() == {"detail": "branch_name: Enter a valid branch name!"}
57+
assert response.json() == {"detail": "branch_name: Enter a valid branch name!"}
5858

5959

6060
def test_add_taxonomy_duplicate_project_name(client):

backend/tests/test_export.py

Lines changed: 221 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,22 @@
99
from fastapi import UploadFile
1010

1111
from editor.controllers import project_controller
12+
from editor.models.node_models import NodeType, EntryNode
1213
from editor.entries import TaxonomyGraph
1314
from editor import graph_db
1415

1516
from .utils import FakeBackgroundTask
1617

1718

1819
@pytest.fixture()
19-
async def test_taxonomy(database_lifespan):
20+
async def taxonomy_test(database_lifespan):
2021
"""We will import a project to work with
2122
2223
We cache the project by fully duplicating it so that setup is faster
2324
"""
2425
from .utils import clean_neo4j_db
25-
# TEMPORARY
26-
await clean_neo4j_db(database_lifespan)
26+
# TEMPORARY use this to clean template in the db
27+
# await clean_neo4j_db(database_lifespan)
2728
with open("tests/data/test.txt", "rb") as test_file:
2829
async with graph_db.TransactionCtx() as session:
2930
# clean the test project
@@ -33,18 +34,232 @@ async def test_taxonomy(database_lifespan):
3334
# if the template project is not there, we create it
3435
background_tasks = FakeBackgroundTask()
3536
await taxonomy.import_taxonomy("test taxonomy", "unknown", background_tasks, UploadFile(file=test_file, filename="test.txt"))
37+
else:
38+
background_tasks = None
3639
# this runs in its own transaction
37-
await background_tasks.run()
40+
if background_tasks:
41+
await background_tasks.run()
3842
async with graph_db.TransactionCtx() as session:
3943
# clone template project as test project
4044
await project_controller.clone_project("template", "test", "branch")
4145
return TaxonomyGraph("branch", "test")
4246

4347

4448
@pytest.mark.anyio
45-
async def test_no_modification(test_taxonomy):
49+
async def test_no_modification(taxonomy_test):
4650
background_tasks = FakeBackgroundTask()
47-
file_path = test_taxonomy.dump_taxonomy(background_tasks)
51+
file_path = taxonomy_test.dump_taxonomy(background_tasks)
4852
assert open(file_path).read() == open("tests/data/test.txt").read()
4953
# clean files
5054
background_tasks.run()
55+
56+
@pytest.mark.anyio
57+
async def test_remove_parent(taxonomy_test):
58+
async with graph_db.TransactionCtx() as session:
59+
# remove "yaourts allégés" for "yaourts au fruit de la passion allégés"
60+
children = await taxonomy_test.get_children("fr:yaourts-alleges")
61+
children_ids = [record["child.id"] for record in children]
62+
children_ids.remove("fr:yaourts-fruit-passion-alleges")
63+
await taxonomy_test.update_node_children("fr:yaourts-alleges", children_ids)
64+
background_tasks = FakeBackgroundTask()
65+
file_path = taxonomy_test.dump_taxonomy(background_tasks)
66+
result = list(open(file_path))
67+
# expected output
68+
expected = list(open("tests/data/test.txt"))
69+
# remaining parent id is now canonical
70+
expected[44] = "< en:Passion fruit yogurts\n"
71+
# remove the old parent line
72+
del expected[45]
73+
assert result == expected
74+
# clean files
75+
background_tasks.run()
76+
77+
78+
@pytest.mark.anyio
79+
async def test_add_parent(taxonomy_test):
80+
async with graph_db.TransactionCtx() as session:
81+
# add "en: fake-stuff" to "yaourts au fruit de la passion allégés"
82+
children = await taxonomy_test.get_children("en:fake-stuff")
83+
children_ids = [record["child.id"] for record in children]
84+
children_ids.append("fr:yaourts-fruit-passion-alleges")
85+
await taxonomy_test.update_node_children("en:fake-stuff", children_ids)
86+
background_tasks = FakeBackgroundTask()
87+
file_path = taxonomy_test.dump_taxonomy(background_tasks)
88+
result = list(open(file_path))
89+
# expected output
90+
expected = list(open("tests/data/test.txt"))
91+
# parent ids are now canonical and linted
92+
expected[44] = "< en:Passion fruit yogurts\n"
93+
expected[45] = "< fr:yaourts allégés\n"
94+
# new parent added
95+
expected.insert(46, "< en:fake-stuff\n")
96+
assert result == expected
97+
# clean files
98+
background_tasks.run()
99+
100+
101+
@pytest.mark.anyio
102+
async def test_add_synonym(taxonomy_test):
103+
async with graph_db.TransactionCtx() as session:
104+
# add synonym to yaourts au fruit de la passion
105+
node_data, = await taxonomy_test.get_nodes(NodeType.ENTRY, "fr:yaourts-fruit-passion-alleges")
106+
node = EntryNode(**dict(node_data['n']))
107+
node.tags["tags_fr"].append("yaourts allégé aux grenadilles")
108+
await taxonomy_test.update_node(NodeType.ENTRY, node)
109+
background_tasks = FakeBackgroundTask()
110+
file_path = taxonomy_test.dump_taxonomy(background_tasks)
111+
result = list(open(file_path))
112+
# expected output
113+
expected = list(open("tests/data/test.txt"))
114+
# parent ids are now canonical and linted
115+
expected[44] = "< en:Passion fruit yogurts\n"
116+
expected[45] = "< fr:yaourts allégés\n"
117+
# added the synonyms
118+
expected[46] = "fr: yaourts au fruit de la passion allégés, yaourts allégé aux grenadilles\n"
119+
assert result == expected
120+
# clean files
121+
background_tasks.run()
122+
123+
124+
@pytest.mark.anyio
125+
async def test_remove_synonym(taxonomy_test):
126+
async with graph_db.TransactionCtx() as session:
127+
# add synonym to yaourts au fruit de la passion
128+
node_data, = await taxonomy_test.get_nodes(NodeType.ENTRY, "en:yogurts")
129+
node = EntryNode(**dict(node_data['n']))
130+
node.tags["tags_fr"].remove("yoghourts")
131+
await taxonomy_test.update_node(NodeType.ENTRY, node)
132+
background_tasks = FakeBackgroundTask()
133+
file_path = taxonomy_test.dump_taxonomy(background_tasks)
134+
result = list(open(file_path))
135+
# expected output
136+
expected = list(open("tests/data/test.txt"))
137+
# removed the synonyms
138+
expected[9] = "fr: yaourts, yogourts\n"
139+
# also properties were re-ordered (linting)
140+
expected.insert(11, expected.pop(13))
141+
assert result == expected
142+
# clean files
143+
background_tasks.run()
144+
145+
146+
@pytest.mark.anyio
147+
async def test_no_comment_repeat(taxonomy_test):
148+
# we had a bug of repeating comments when modifying an entry
149+
# test it
150+
async with graph_db.TransactionCtx() as session:
151+
# just do a null edit on an entry with comments above it
152+
node_data, = await taxonomy_test.get_nodes(NodeType.ENTRY, "en:soup")
153+
node = EntryNode(**dict(node_data['n']))
154+
await taxonomy_test.update_node(NodeType.ENTRY, node)
155+
background_tasks = FakeBackgroundTask()
156+
file_path = taxonomy_test.dump_taxonomy(background_tasks)
157+
result = list(open(file_path))
158+
# expected output unchanged
159+
expected = list(open("tests/data/test.txt"))
160+
assert result == expected
161+
# clean files
162+
background_tasks.run()
163+
164+
165+
@pytest.mark.anyio
166+
async def test_add_new_entry_as_child(taxonomy_test):
167+
async with graph_db.TransactionCtx() as session:
168+
# add as children to "en:yogurts"
169+
children = await taxonomy_test.get_children("en:yogurts")
170+
children_ids = [record["child.id"] for record in children]
171+
children_ids.append("en:sweet-yogurts")
172+
await taxonomy_test.update_node_children("en:yogurts", children_ids)
173+
# update entry sweet yogurts
174+
node = EntryNode(
175+
id="en:sweet-yogurts",
176+
preceding_lines=["# yogurts with sugar"],
177+
main_language="en",
178+
tags={"tags_en": ["sweet yogurts", "yogurts with sugar"], "tags_fr": ["yaourts sucrés"]},
179+
properties={"wikipedia_en": "https://fr.wikipedia.org/wiki/Yaourt"},
180+
)
181+
await taxonomy_test.update_node(NodeType.ENTRY, node)
182+
# add a children to this new entry
183+
await taxonomy_test.update_node_children("en:sweet-yogurts", ["en:edulcorated-yogurts"])
184+
node = EntryNode(
185+
id="en:edulcorated-yogurts",
186+
preceding_lines=[],
187+
main_language="en",
188+
tags={"tags_en": ["edulcorated yogurts"]},
189+
properties={},
190+
)
191+
await taxonomy_test.update_node(NodeType.ENTRY, node)
192+
193+
background_tasks = FakeBackgroundTask()
194+
file_path = taxonomy_test.dump_taxonomy(background_tasks)
195+
result = list(open(file_path))
196+
# expected output
197+
expected = list(open("tests/data/test.txt"))
198+
# new entry inserted just after yogurts, the parent
199+
expected[16:16] =[
200+
'# yogurts with sugar\n',
201+
'< en:yogurts\n',
202+
'en: sweet yogurts, yogurts with sugar\n',
203+
'fr: yaourts sucrés\n',
204+
'\n'
205+
]
206+
# second entry added at the end
207+
expected[-1] += "\n"
208+
expected.extend([
209+
'\n', '< en:sweet yogurts\n', 'en: edulcorated yogurts\n'
210+
])
211+
assert result == expected
212+
# clean files
213+
background_tasks.run()
214+
215+
216+
@pytest.mark.anyio
217+
async def test_add_new_root_entries(taxonomy_test):
218+
async with graph_db.TransactionCtx() as session:
219+
# add an entry potatoes
220+
await taxonomy_test.create_entry_node("Potatoes", "en")
221+
node = EntryNode(
222+
id="en:potatoes",
223+
preceding_lines=["# The real potatoes"],
224+
main_language="en",
225+
tags={"tags_en": ["Potatoes"], "tags_fr": ["patates", "pommes de terres"]},
226+
)
227+
await taxonomy_test.update_node(NodeType.ENTRY, node)
228+
# and a child to it
229+
await taxonomy_test.update_node_children("en:potatoes", ["en:blue-potatoes"])
230+
node = EntryNode(
231+
id="en:blue-potatoes",
232+
main_language="en",
233+
tags={"tags_en": ["Blue Potatoes"]},
234+
)
235+
await taxonomy_test.update_node(NodeType.ENTRY, node)
236+
# add another unrelated entry cabbage
237+
await taxonomy_test.create_entry_node("Cabbage", "en")
238+
node = EntryNode(
239+
id="en:cabbage",
240+
main_language="en",
241+
tags={"tags_en": ["Cabbage"], "tags_fr": ["Choux"]},
242+
)
243+
await taxonomy_test.update_node(NodeType.ENTRY, node)
244+
background_tasks = FakeBackgroundTask()
245+
file_path = taxonomy_test.dump_taxonomy(background_tasks)
246+
result = list(open(file_path))
247+
# expected output
248+
expected = list(open("tests/data/test.txt"))
249+
# second entry added at the end
250+
expected[-1] += "\n"
251+
expected.extend([
252+
'\n',
253+
'< en:Potatoes\n', 'en: Blue Potatoes\n', '\n',
254+
'# The real potatoes\n', 'en: Potatoes\n', 'fr: patates, pommes de terres\n', '\n',
255+
'en: Cabbage\n', 'fr: Choux\n'
256+
])
257+
258+
assert result == expected
259+
# clean files
260+
background_tasks.run()
261+
262+
@pytest.mark.anyio
263+
async def test_change_entry_id(taxonomy_test):
264+
# yet to be implemented
265+
assert False

parser/openfoodfacts_taxonomy_parser/parser/taxonomy_parser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ def is_entry_synonyms_line(self, line):
237237

238238
def finalize_data(self, data, comments, saved_nodes, line_number: int):
239239
data = self._remove_separating_line(data)
240-
data.src_lines = [f"{data.src_position},{line_number}"]
240+
data.src_lines = [f"{data.src_position - len(data.preceding_lines or [])},{line_number}"]
241241
if data.get_node_type() == NodeType.ENTRY:
242242
self._add_comments(data, comments, "end")
243243
if data.id in saved_nodes:

0 commit comments

Comments
 (0)