Skip to content

Commit 4fa93c4

Browse files
authored
Merge pull request #530 from mapswipe/handle_foreign_key_violation
handling invalid matches
2 parents 475e993 + 11866cc commit 4fa93c4

File tree

16 files changed

+115
-38
lines changed

16 files changed

+115
-38
lines changed

.github/workflows/actions.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
working-directory: ./mapswipe_workers
2121
run: |
2222
python -m pip install --upgrade pip
23-
pip install flake8 black==19.10b0 isort
23+
pip install flake8 black==22.3.0 isort
2424
- name: Code style
2525
working-directory: ./mapswipe_workers
2626
run: |

mapswipe_workers/.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
repos:
33
- repo: https://github.com/psf/black
4-
rev: 19.10b0
4+
rev: 22.3.0
55
hooks:
66
- id: black
77
- repo: https://gitlab.com/pycqa/flake8

mapswipe_workers/mapswipe_workers/firebase_to_postgres/transfer_results.py

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def transfer_results(project_id_list=None):
5454
return project_id_list_transfered
5555

5656

57-
def transfer_results_for_project(project_id, results):
57+
def transfer_results_for_project(project_id, results, filter_mode: bool = False):
5858
"""Transfer the results for a specific project.
5959
Save results into an in-memory file.
6060
Copy the results to postgres.
@@ -90,18 +90,27 @@ def transfer_results_for_project(project_id, results):
9090
# results at relatively high speed.
9191
results_file = results_to_file(results, project_id)
9292
truncate_temp_results()
93-
save_results_to_postgres(results_file)
93+
save_results_to_postgres(results_file, project_id, filter_mode=filter_mode)
9494
except psycopg2.errors.ForeignKeyViolation as e:
95+
9596
sentry.capture_exception(e)
9697
sentry.capture_message(
9798
"could not transfer results to postgres due to ForeignKeyViolation: "
98-
f"{project_id}"
99+
f"{project_id}; filter_mode={filter_mode}"
99100
)
100101
logger.exception(e)
101102
logger.warning(
102103
"could not transfer results to postgres due to ForeignKeyViolation: "
103-
f"{project_id}"
104+
f"{project_id}; filter_mode={filter_mode}"
104105
)
106+
107+
# There is an exception where additional invalid tasks are in a group.
108+
# If that happens we arrive here and add the flag filtermode=true
109+
# to this function, which could solve the issue in save_results_to_postgres.
110+
# If it does not solve the issue we arrive again but
111+
# since filtermode is already true, we will not try to transfer results again.
112+
if not filter_mode:
113+
transfer_results_for_project(project_id, results, filter_mode=True)
105114
except Exception as e:
106115
sentry.capture_exception(e)
107116
sentry.capture_message(f"could not transfer results to postgres: {project_id}")
@@ -259,14 +268,16 @@ def results_to_file(results, projectId):
259268
return results_file
260269

261270

262-
def save_results_to_postgres(results_file):
271+
def save_results_to_postgres(results_file, project_id, filter_mode: bool):
263272
"""
264273
Saves results to a temporary table in postgres
265274
using the COPY Statement of Postgres
266275
for a more efficient import into the database.
267276
Parameters
268277
----------
269278
results_file: io.StringIO
279+
filter_mode: boolean
280+
If true, try to filter out invalid results.
270281
"""
271282

272283
p_con = auth.postgresDB()
@@ -283,6 +294,23 @@ def save_results_to_postgres(results_file):
283294
p_con.copy_from(results_file, "results_temp", columns)
284295
results_file.close()
285296

297+
if filter_mode:
298+
logger.warn(f"trying to remove invalid tasks from {project_id}.")
299+
300+
filter_query = """
301+
DELETE FROM results_temp
302+
where task_id in (
303+
select task_id from results_temp where task_id not in (
304+
select r.task_id from results_temp r join (
305+
select * from tasks where project_id = %(project_id)s
306+
) as t
307+
on r.group_id = t.group_id
308+
and r.task_id = t.task_id
309+
)
310+
)
311+
"""
312+
p_con.query(filter_query, {"project_id": project_id})
313+
286314
query_insert_results = """
287315
INSERT INTO results
288316
SELECT * FROM results_temp

mapswipe_workers/mapswipe_workers/generate_stats/project_stats.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,9 @@ def get_agg_results_by_task_id(
335335
# add task geometry using left join
336336
tasks_df.drop(columns=["project_id", "group_id"], inplace=True)
337337
agg_results_df = results_by_task_id_df.merge(
338-
tasks_df, left_on="task_id", right_on="task_id",
338+
tasks_df,
339+
left_on="task_id",
340+
right_on="task_id",
339341
)
340342
logger.info("added geometry to aggregated results")
341343

mapswipe_workers/mapswipe_workers/mapswipe_workers.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,10 @@ def run_create_tutorials() -> None:
331331

332332
@cli.command("archive")
333333
@click.option(
334-
"--project-id", "-i", help=("Archive project with giving project id"), type=str,
334+
"--project-id",
335+
"-i",
336+
help=("Archive project with giving project id"),
337+
type=str,
335338
)
336339
@click.option(
337340
"--project-ids",
@@ -359,7 +362,10 @@ def run_archive_project(project_id, project_ids):
359362

360363
@cli.command("delete")
361364
@click.option(
362-
"--project-id", "-i", help=("Delete project with giving project id"), type=str,
365+
"--project-id",
366+
"-i",
367+
help=("Delete project with giving project id"),
368+
type=str,
363369
)
364370
@click.option(
365371
"--project-ids",

mapswipe_workers/mapswipe_workers/project_types/arbitrary_geometry/group.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ class Group(BaseGroup):
88
def __init__(self, project: object, groupId: int) -> None:
99
super().__init__(project, groupId)
1010

11-
def create_tasks(self, feature_ids: List, features: List,) -> None:
11+
def create_tasks(
12+
self,
13+
feature_ids: List,
14+
features: List,
15+
) -> None:
1216
"""Create tasks for a group
1317
1418
feature_geometries is a list of geometries or feature in geojson format.

mapswipe_workers/mapswipe_workers/project_types/arbitrary_geometry/task.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77

88
class Task(BaseTask):
99
def __init__(
10-
self, group: object, featureId: Union[int, str], feature: Dict,
10+
self,
11+
group: object,
12+
featureId: Union[int, str],
13+
feature: Dict,
1114
):
1215
"""
1316
Parameters

mapswipe_workers/mapswipe_workers/project_types/base/project.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,9 @@ def save_project(self):
136136
# Make sure projects get saved in Postgres and Firebase successful
137137
try:
138138
self.save_to_postgres(
139-
project, groups, groupsOfTasks,
139+
project,
140+
groups,
141+
groupsOfTasks,
140142
)
141143
logger.info(
142144
f"{self.projectId}" f" - the project has been saved" f" to postgres"
@@ -168,7 +170,9 @@ def save_project(self):
168170

169171
try:
170172
self.save_to_firebase(
171-
project, groups, groupsOfTasks,
173+
project,
174+
groups,
175+
groupsOfTasks,
172176
)
173177
logger.info(
174178
f"{self.projectId}" f" - the project has been saved" f" to firebase"
@@ -493,7 +497,10 @@ def create_groups_txt_file(self, groups):
493497
"project_type_specifics",
494498
)
495499
w = csv.DictWriter(
496-
groups_txt_file, fieldnames=fieldnames, delimiter="\t", quotechar="'",
500+
groups_txt_file,
501+
fieldnames=fieldnames,
502+
delimiter="\t",
503+
quotechar="'",
497504
)
498505

499506
for groupId, group in groups.items():
@@ -575,7 +582,10 @@ def create_tasks_txt_file(self, groupsOfTasks):
575582
"project_type_specifics",
576583
)
577584
w = csv.DictWriter(
578-
tasks_txt_file, fieldnames=fieldnames, delimiter="\t", quotechar="'",
585+
tasks_txt_file,
586+
fieldnames=fieldnames,
587+
delimiter="\t",
588+
quotechar="'",
579589
)
580590

581591
for groupId, tasks in groupsOfTasks.items():

mapswipe_workers/mapswipe_workers/utils/geojson_functions.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,11 @@ def create_geojson_file_from_dict(final_groups_dict, outfile):
206206

207207
dataSource = driver.CreateDataSource(outfile_temp)
208208
# create layer
209-
layer = dataSource.CreateLayer(outfile_temp, srs, geom_type=ogr.wkbPolygon,)
209+
layer = dataSource.CreateLayer(
210+
outfile_temp,
211+
srs,
212+
geom_type=ogr.wkbPolygon,
213+
)
210214

211215
# create fields
212216
field_id = ogr.FieldDefn("group_id", ogr.OFTInteger)
@@ -295,7 +299,11 @@ def create_geojson_file(geometries, outfile):
295299

296300
dataSource = driver.CreateDataSource(outfile_temp)
297301
# create layer
298-
layer = dataSource.CreateLayer(outfile_temp, srs, geom_type=ogr.wkbPolygon,)
302+
layer = dataSource.CreateLayer(
303+
outfile_temp,
304+
srs,
305+
geom_type=ogr.wkbPolygon,
306+
)
299307

300308
# create fields
301309
field_id = ogr.FieldDefn("id", ogr.OFTInteger)

mapswipe_workers/mapswipe_workers/utils/tile_functions.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,10 @@ def tile_coords_zoom_and_tileserver_to_url(
9696
# https://www.maptiler.com/google-maps-coordinates-tile-bounds-projection/
9797
tile_y = int(math.pow(2, tile_z) - tile_y) - 1
9898
url = tile_server["url"].format(
99-
key=tile_server["apiKey"], x=tile_x, y=tile_y, z=tile_z,
99+
key=tile_server["apiKey"],
100+
x=tile_x,
101+
y=tile_y,
102+
z=tile_z,
100103
)
101104
elif "{-y}" in tile_server["url"]:
102105
# this uses not the standard TMS tile y coordinate,
@@ -105,10 +108,18 @@ def tile_coords_zoom_and_tileserver_to_url(
105108
# https://www.maptiler.com/google-maps-coordinates-tile-bounds-projection/
106109
tile_y = int(math.pow(2, tile_z) - tile_y) - 1
107110
url = tile_server["url"].replace("{-y}", "{y}")
108-
url = url.format(key=tile_server["apiKey"], x=tile_x, y=tile_y, z=tile_z,)
111+
url = url.format(
112+
key=tile_server["apiKey"],
113+
x=tile_x,
114+
y=tile_y,
115+
z=tile_z,
116+
)
109117
else:
110118
url = tile_server["url"].format(
111-
key=tile_server["apiKey"], x=tile_x, y=tile_y, z=tile_z,
119+
key=tile_server["apiKey"],
120+
x=tile_x,
121+
y=tile_y,
122+
z=tile_z,
112123
)
113124

114125
return url

0 commit comments

Comments
 (0)