arkindex-base-worker 0.4.0rc3__py3-none-any.whl → 0.4.0rc5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. {arkindex_base_worker-0.4.0rc3.dist-info → arkindex_base_worker-0.4.0rc5.dist-info}/METADATA +15 -14
  2. {arkindex_base_worker-0.4.0rc3.dist-info → arkindex_base_worker-0.4.0rc5.dist-info}/RECORD +24 -16
  3. {arkindex_base_worker-0.4.0rc3.dist-info → arkindex_base_worker-0.4.0rc5.dist-info}/WHEEL +1 -1
  4. arkindex_worker/cache.py +1 -1
  5. arkindex_worker/worker/__init__.py +6 -2
  6. arkindex_worker/worker/entity.py +8 -19
  7. arkindex_worker/worker/process.py +5 -0
  8. tests/test_elements_worker/{test_classifications.py → test_classification.py} +86 -0
  9. tests/test_elements_worker/test_corpus.py +31 -31
  10. tests/test_elements_worker/test_element.py +427 -0
  11. tests/test_elements_worker/test_element_create_multiple.py +715 -0
  12. tests/test_elements_worker/test_element_create_single.py +528 -0
  13. tests/test_elements_worker/test_element_list_children.py +969 -0
  14. tests/test_elements_worker/test_element_list_parents.py +530 -0
  15. tests/test_elements_worker/{test_entities.py → test_entity_create.py} +42 -245
  16. tests/test_elements_worker/test_entity_list_and_check.py +160 -0
  17. tests/test_elements_worker/test_transcription_create.py +873 -0
  18. tests/test_elements_worker/test_transcription_create_with_elements.py +951 -0
  19. tests/test_elements_worker/test_transcription_list.py +450 -0
  20. tests/test_elements_worker/test_version.py +60 -0
  21. tests/test_elements_worker/test_worker.py +525 -88
  22. tests/test_image.py +181 -198
  23. tests/test_elements_worker/test_elements.py +0 -3704
  24. tests/test_elements_worker/test_transcriptions.py +0 -2252
  25. {arkindex_base_worker-0.4.0rc3.dist-info → arkindex_base_worker-0.4.0rc5.dist-info}/LICENSE +0 -0
  26. {arkindex_base_worker-0.4.0rc3.dist-info → arkindex_base_worker-0.4.0rc5.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,715 @@
1
+ import json
2
+ import re
3
+ from uuid import UUID
4
+
5
+ import pytest
6
+
7
+ from arkindex.exceptions import ErrorResponse
8
+ from arkindex_worker.cache import (
9
+ CachedElement,
10
+ CachedImage,
11
+ )
12
+ from arkindex_worker.models import Element
13
+ from arkindex_worker.utils import DEFAULT_BATCH_SIZE
14
+
15
+ from . import BASE_API_CALLS
16
+
17
+
18
+ def test_create_elements_wrong_parent(mock_elements_worker):
19
+ with pytest.raises(
20
+ TypeError, match="Parent element should be an Element or CachedElement instance"
21
+ ):
22
+ mock_elements_worker.create_elements(
23
+ parent=None,
24
+ elements=[],
25
+ )
26
+
27
+ with pytest.raises(
28
+ TypeError, match="Parent element should be an Element or CachedElement instance"
29
+ ):
30
+ mock_elements_worker.create_elements(
31
+ parent="not element type",
32
+ elements=[],
33
+ )
34
+
35
+
36
+ def test_create_elements_no_zone(mock_elements_worker):
37
+ elt = Element({"zone": None})
38
+ with pytest.raises(
39
+ AssertionError, match="create_elements cannot be used on parents without zones"
40
+ ):
41
+ mock_elements_worker.create_elements(
42
+ parent=elt,
43
+ elements=None,
44
+ )
45
+
46
+ elt = CachedElement(
47
+ id="11111111-1111-1111-1111-1111111111", name="blah", type="blah"
48
+ )
49
+ with pytest.raises(
50
+ AssertionError, match="create_elements cannot be used on parents without images"
51
+ ):
52
+ mock_elements_worker.create_elements(
53
+ parent=elt,
54
+ elements=None,
55
+ )
56
+
57
+
58
+ def test_create_elements_wrong_elements(mock_elements_worker):
59
+ elt = Element({"zone": {"image": {"id": "image_id"}}})
60
+
61
+ with pytest.raises(
62
+ AssertionError, match="elements shouldn't be null and should be of type list"
63
+ ):
64
+ mock_elements_worker.create_elements(
65
+ parent=elt,
66
+ elements=None,
67
+ )
68
+
69
+ with pytest.raises(
70
+ AssertionError, match="elements shouldn't be null and should be of type list"
71
+ ):
72
+ mock_elements_worker.create_elements(
73
+ parent=elt,
74
+ elements="not a list",
75
+ )
76
+
77
+
78
+ def test_create_elements_wrong_elements_instance(mock_elements_worker):
79
+ elt = Element({"zone": {"image": {"id": "image_id"}}})
80
+
81
+ with pytest.raises(
82
+ AssertionError, match="Element at index 0 in elements: Should be of type dict"
83
+ ):
84
+ mock_elements_worker.create_elements(
85
+ parent=elt,
86
+ elements=["not a dict"],
87
+ )
88
+
89
+
90
+ def test_create_elements_wrong_elements_name(mock_elements_worker):
91
+ elt = Element({"zone": {"image": {"id": "image_id"}}})
92
+
93
+ with pytest.raises(
94
+ AssertionError,
95
+ match="Element at index 0 in elements: name shouldn't be null and should be of type str",
96
+ ):
97
+ mock_elements_worker.create_elements(
98
+ parent=elt,
99
+ elements=[
100
+ {
101
+ "name": None,
102
+ "type": "something",
103
+ "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
104
+ }
105
+ ],
106
+ )
107
+
108
+ with pytest.raises(
109
+ AssertionError,
110
+ match="Element at index 0 in elements: name shouldn't be null and should be of type str",
111
+ ):
112
+ mock_elements_worker.create_elements(
113
+ parent=elt,
114
+ elements=[
115
+ {
116
+ "name": 1234,
117
+ "type": "something",
118
+ "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
119
+ }
120
+ ],
121
+ )
122
+
123
+
124
+ def test_create_elements_wrong_elements_type(mock_elements_worker):
125
+ elt = Element({"zone": {"image": {"id": "image_id"}}})
126
+
127
+ with pytest.raises(
128
+ AssertionError,
129
+ match="Element at index 0 in elements: type shouldn't be null and should be of type str",
130
+ ):
131
+ mock_elements_worker.create_elements(
132
+ parent=elt,
133
+ elements=[
134
+ {
135
+ "name": "0",
136
+ "type": None,
137
+ "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
138
+ }
139
+ ],
140
+ )
141
+
142
+ with pytest.raises(
143
+ AssertionError,
144
+ match="Element at index 0 in elements: type shouldn't be null and should be of type str",
145
+ ):
146
+ mock_elements_worker.create_elements(
147
+ parent=elt,
148
+ elements=[
149
+ {
150
+ "name": "0",
151
+ "type": 1234,
152
+ "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
153
+ }
154
+ ],
155
+ )
156
+
157
+
158
+ def test_create_elements_wrong_elements_polygon(mock_elements_worker):
159
+ elt = Element({"zone": {"image": {"id": "image_id"}}})
160
+
161
+ with pytest.raises(
162
+ AssertionError,
163
+ match="Element at index 0 in elements: polygon shouldn't be null and should be of type list",
164
+ ):
165
+ mock_elements_worker.create_elements(
166
+ parent=elt,
167
+ elements=[
168
+ {
169
+ "name": "0",
170
+ "type": "something",
171
+ "polygon": None,
172
+ }
173
+ ],
174
+ )
175
+
176
+ with pytest.raises(
177
+ AssertionError,
178
+ match="Element at index 0 in elements: polygon shouldn't be null and should be of type list",
179
+ ):
180
+ mock_elements_worker.create_elements(
181
+ parent=elt,
182
+ elements=[
183
+ {
184
+ "name": "0",
185
+ "type": "something",
186
+ "polygon": "not a polygon",
187
+ }
188
+ ],
189
+ )
190
+
191
+ with pytest.raises(
192
+ AssertionError,
193
+ match="Element at index 0 in elements: polygon should have at least three points",
194
+ ):
195
+ mock_elements_worker.create_elements(
196
+ parent=elt,
197
+ elements=[
198
+ {
199
+ "name": "0",
200
+ "type": "something",
201
+ "polygon": [[1, 1], [2, 2]],
202
+ }
203
+ ],
204
+ )
205
+
206
+ with pytest.raises(
207
+ AssertionError,
208
+ match="Element at index 0 in elements: polygon points should be lists of two items",
209
+ ):
210
+ mock_elements_worker.create_elements(
211
+ parent=elt,
212
+ elements=[
213
+ {
214
+ "name": "0",
215
+ "type": "something",
216
+ "polygon": [[1, 1, 1], [2, 2, 1], [2, 1, 1], [1, 2, 1]],
217
+ }
218
+ ],
219
+ )
220
+
221
+ with pytest.raises(
222
+ AssertionError,
223
+ match="Element at index 0 in elements: polygon points should be lists of two items",
224
+ ):
225
+ mock_elements_worker.create_elements(
226
+ parent=elt,
227
+ elements=[
228
+ {
229
+ "name": "0",
230
+ "type": "something",
231
+ "polygon": [[1], [2], [2], [1]],
232
+ }
233
+ ],
234
+ )
235
+
236
+ with pytest.raises(
237
+ AssertionError,
238
+ match="Element at index 0 in elements: polygon points should be lists of two numbers",
239
+ ):
240
+ mock_elements_worker.create_elements(
241
+ parent=elt,
242
+ elements=[
243
+ {
244
+ "name": "0",
245
+ "type": "something",
246
+ "polygon": [["not a coord", 1], [2, 2], [2, 1], [1, 2]],
247
+ }
248
+ ],
249
+ )
250
+
251
+
252
+ @pytest.mark.parametrize("confidence", ["lol", "0.2", -1.0, 1.42, float("inf")])
253
+ def test_create_elements_wrong_elements_confidence(mock_elements_worker, confidence):
254
+ with pytest.raises(
255
+ AssertionError,
256
+ match=re.escape(
257
+ "Element at index 0 in elements: confidence should be None or a float in [0..1] range"
258
+ ),
259
+ ):
260
+ mock_elements_worker.create_elements(
261
+ parent=Element({"zone": {"image": {"id": "image_id"}}}),
262
+ elements=[
263
+ {
264
+ "name": "a",
265
+ "type": "something",
266
+ "polygon": [[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]],
267
+ "confidence": confidence,
268
+ }
269
+ ],
270
+ )
271
+
272
+
273
+ def test_create_elements_api_error(responses, mock_elements_worker):
274
+ elt = Element(
275
+ {
276
+ "id": "12341234-1234-1234-1234-123412341234",
277
+ "zone": {
278
+ "image": {
279
+ "id": "c0fec0fe-c0fe-c0fe-c0fe-c0fec0fec0fe",
280
+ "width": 42,
281
+ "height": 42,
282
+ "url": "http://aaaa",
283
+ }
284
+ },
285
+ }
286
+ )
287
+ responses.add(
288
+ responses.POST,
289
+ "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
290
+ status=418,
291
+ )
292
+
293
+ with pytest.raises(ErrorResponse):
294
+ mock_elements_worker.create_elements(
295
+ parent=elt,
296
+ elements=[
297
+ {
298
+ "name": "0",
299
+ "type": "something",
300
+ "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
301
+ }
302
+ ],
303
+ )
304
+
305
+ assert len(responses.calls) == len(BASE_API_CALLS) + 1
306
+ assert [
307
+ (call.request.method, call.request.url) for call in responses.calls
308
+ ] == BASE_API_CALLS + [
309
+ (
310
+ "POST",
311
+ "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
312
+ )
313
+ ]
314
+
315
+
316
+ @pytest.mark.parametrize("batch_size", [DEFAULT_BATCH_SIZE, 1])
317
+ def test_create_elements_cached_element(
318
+ batch_size, responses, mock_elements_worker_with_cache
319
+ ):
320
+ image = CachedImage.create(
321
+ id=UUID("c0fec0fe-c0fe-c0fe-c0fe-c0fec0fec0fe"),
322
+ width=42,
323
+ height=42,
324
+ url="http://aaaa",
325
+ )
326
+ elt = CachedElement.create(
327
+ id=UUID("12341234-1234-1234-1234-123412341234"),
328
+ type="parent",
329
+ image_id=image.id,
330
+ polygon="[[0, 0], [0, 1000], [1000, 1000], [1000, 0], [0, 0]]",
331
+ )
332
+
333
+ if batch_size > 1:
334
+ responses.add(
335
+ responses.POST,
336
+ "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
337
+ status=200,
338
+ json=[
339
+ {"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"},
340
+ {"id": "5468c358-b9c4-499d-8b92-d6349c58e88d"},
341
+ ],
342
+ )
343
+ else:
344
+ for elt_id in [
345
+ "497f6eca-6276-4993-bfeb-53cbbbba6f08",
346
+ "5468c358-b9c4-499d-8b92-d6349c58e88d",
347
+ ]:
348
+ responses.add(
349
+ responses.POST,
350
+ "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
351
+ status=200,
352
+ json=[{"id": elt_id}],
353
+ )
354
+
355
+ created_ids = mock_elements_worker_with_cache.create_elements(
356
+ parent=elt,
357
+ elements=[
358
+ {
359
+ "name": "0",
360
+ "type": "something",
361
+ "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
362
+ },
363
+ {
364
+ "name": "1",
365
+ "type": "something",
366
+ "polygon": [[4, 4], [5, 5], [5, 4], [4, 5]],
367
+ },
368
+ ],
369
+ batch_size=batch_size,
370
+ )
371
+
372
+ bulk_api_calls = [
373
+ (
374
+ "POST",
375
+ "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
376
+ )
377
+ ]
378
+ if batch_size != DEFAULT_BATCH_SIZE:
379
+ bulk_api_calls.append(
380
+ (
381
+ "POST",
382
+ "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
383
+ )
384
+ )
385
+
386
+ assert len(responses.calls) == len(BASE_API_CALLS) + len(bulk_api_calls)
387
+ assert [
388
+ (call.request.method, call.request.url) for call in responses.calls
389
+ ] == BASE_API_CALLS + bulk_api_calls
390
+
391
+ first_elt = {
392
+ "name": "0",
393
+ "type": "something",
394
+ "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
395
+ }
396
+ second_elt = {
397
+ "name": "1",
398
+ "type": "something",
399
+ "polygon": [[4, 4], [5, 5], [5, 4], [4, 5]],
400
+ }
401
+ empty_payload = {
402
+ "elements": [],
403
+ "worker_run_id": "56785678-5678-5678-5678-567856785678",
404
+ }
405
+
406
+ bodies = []
407
+ first_call_idx = None
408
+ if batch_size > 1:
409
+ first_call_idx = -1
410
+ bodies.append({**empty_payload, "elements": [first_elt, second_elt]})
411
+ else:
412
+ first_call_idx = -2
413
+ bodies.append({**empty_payload, "elements": [first_elt]})
414
+ bodies.append({**empty_payload, "elements": [second_elt]})
415
+
416
+ assert [
417
+ json.loads(bulk_call.request.body)
418
+ for bulk_call in responses.calls[first_call_idx:]
419
+ ] == bodies
420
+
421
+ assert created_ids == [
422
+ {"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"},
423
+ {"id": "5468c358-b9c4-499d-8b92-d6349c58e88d"},
424
+ ]
425
+
426
+ # Check that created elements were properly stored in SQLite cache
427
+ assert list(CachedElement.select().order_by(CachedElement.id)) == [
428
+ elt,
429
+ CachedElement(
430
+ id=UUID("497f6eca-6276-4993-bfeb-53cbbbba6f08"),
431
+ parent_id=elt.id,
432
+ type="something",
433
+ image_id="c0fec0fe-c0fe-c0fe-c0fe-c0fec0fec0fe",
434
+ polygon=[[1, 1], [2, 2], [2, 1], [1, 2]],
435
+ worker_run_id=UUID("56785678-5678-5678-5678-567856785678"),
436
+ confidence=None,
437
+ ),
438
+ CachedElement(
439
+ id=UUID("5468c358-b9c4-499d-8b92-d6349c58e88d"),
440
+ parent_id=elt.id,
441
+ type="something",
442
+ image_id="c0fec0fe-c0fe-c0fe-c0fe-c0fec0fec0fe",
443
+ polygon=[[4, 4], [5, 5], [5, 4], [4, 5]],
444
+ worker_run_id=UUID("56785678-5678-5678-5678-567856785678"),
445
+ confidence=None,
446
+ ),
447
+ ]
448
+
449
+
450
+ @pytest.mark.parametrize("batch_size", [DEFAULT_BATCH_SIZE, 1])
451
+ def test_create_elements(
452
+ batch_size, responses, mock_elements_worker_with_cache, tmp_path
453
+ ):
454
+ elt = Element(
455
+ {
456
+ "id": "12341234-1234-1234-1234-123412341234",
457
+ "zone": {
458
+ "image": {
459
+ "id": "c0fec0fe-c0fe-c0fe-c0fe-c0fec0fec0fe",
460
+ "width": 42,
461
+ "height": 42,
462
+ "url": "http://aaaa",
463
+ }
464
+ },
465
+ }
466
+ )
467
+
468
+ if batch_size > 1:
469
+ responses.add(
470
+ responses.POST,
471
+ "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
472
+ status=200,
473
+ json=[
474
+ {"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"},
475
+ {"id": "5468c358-b9c4-499d-8b92-d6349c58e88d"},
476
+ ],
477
+ )
478
+ else:
479
+ for elt_id in [
480
+ "497f6eca-6276-4993-bfeb-53cbbbba6f08",
481
+ "5468c358-b9c4-499d-8b92-d6349c58e88d",
482
+ ]:
483
+ responses.add(
484
+ responses.POST,
485
+ "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
486
+ status=200,
487
+ json=[{"id": elt_id}],
488
+ )
489
+
490
+ created_ids = mock_elements_worker_with_cache.create_elements(
491
+ parent=elt,
492
+ elements=[
493
+ {
494
+ "name": "0",
495
+ "type": "something",
496
+ "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
497
+ },
498
+ {
499
+ "name": "1",
500
+ "type": "something",
501
+ "polygon": [[4, 4], [5, 5], [5, 4], [4, 5]],
502
+ },
503
+ ],
504
+ batch_size=batch_size,
505
+ )
506
+
507
+ bulk_api_calls = [
508
+ (
509
+ "POST",
510
+ "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
511
+ )
512
+ ]
513
+ if batch_size != DEFAULT_BATCH_SIZE:
514
+ bulk_api_calls.append(
515
+ (
516
+ "POST",
517
+ "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
518
+ )
519
+ )
520
+
521
+ assert len(responses.calls) == len(BASE_API_CALLS) + len(bulk_api_calls)
522
+ assert [
523
+ (call.request.method, call.request.url) for call in responses.calls
524
+ ] == BASE_API_CALLS + bulk_api_calls
525
+
526
+ first_elt = {
527
+ "name": "0",
528
+ "type": "something",
529
+ "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
530
+ }
531
+ second_elt = {
532
+ "name": "1",
533
+ "type": "something",
534
+ "polygon": [[4, 4], [5, 5], [5, 4], [4, 5]],
535
+ }
536
+ empty_payload = {
537
+ "elements": [],
538
+ "worker_run_id": "56785678-5678-5678-5678-567856785678",
539
+ }
540
+
541
+ bodies = []
542
+ first_call_idx = None
543
+ if batch_size > 1:
544
+ first_call_idx = -1
545
+ bodies.append({**empty_payload, "elements": [first_elt, second_elt]})
546
+ else:
547
+ first_call_idx = -2
548
+ bodies.append({**empty_payload, "elements": [first_elt]})
549
+ bodies.append({**empty_payload, "elements": [second_elt]})
550
+
551
+ assert [
552
+ json.loads(bulk_call.request.body)
553
+ for bulk_call in responses.calls[first_call_idx:]
554
+ ] == bodies
555
+
556
+ assert created_ids == [
557
+ {"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"},
558
+ {"id": "5468c358-b9c4-499d-8b92-d6349c58e88d"},
559
+ ]
560
+
561
+ # Check that created elements were properly stored in SQLite cache
562
+ assert (tmp_path / "db.sqlite").is_file()
563
+
564
+ assert list(CachedElement.select()) == [
565
+ CachedElement(
566
+ id=UUID("497f6eca-6276-4993-bfeb-53cbbbba6f08"),
567
+ parent_id=UUID("12341234-1234-1234-1234-123412341234"),
568
+ type="something",
569
+ image_id="c0fec0fe-c0fe-c0fe-c0fe-c0fec0fec0fe",
570
+ polygon=[[1, 1], [2, 2], [2, 1], [1, 2]],
571
+ worker_run_id=UUID("56785678-5678-5678-5678-567856785678"),
572
+ confidence=None,
573
+ ),
574
+ CachedElement(
575
+ id=UUID("5468c358-b9c4-499d-8b92-d6349c58e88d"),
576
+ parent_id=UUID("12341234-1234-1234-1234-123412341234"),
577
+ type="something",
578
+ image_id="c0fec0fe-c0fe-c0fe-c0fe-c0fec0fec0fe",
579
+ polygon=[[4, 4], [5, 5], [5, 4], [4, 5]],
580
+ worker_run_id=UUID("56785678-5678-5678-5678-567856785678"),
581
+ confidence=None,
582
+ ),
583
+ ]
584
+
585
+
586
+ def test_create_elements_confidence(
587
+ responses, mock_elements_worker_with_cache, tmp_path
588
+ ):
589
+ elt = Element(
590
+ {
591
+ "id": "12341234-1234-1234-1234-123412341234",
592
+ "zone": {
593
+ "image": {
594
+ "id": "c0fec0fe-c0fe-c0fe-c0fe-c0fec0fec0fe",
595
+ "width": 42,
596
+ "height": 42,
597
+ "url": "http://aaaa",
598
+ }
599
+ },
600
+ }
601
+ )
602
+ responses.add(
603
+ responses.POST,
604
+ "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
605
+ status=200,
606
+ json=[{"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"}],
607
+ )
608
+
609
+ created_ids = mock_elements_worker_with_cache.create_elements(
610
+ parent=elt,
611
+ elements=[
612
+ {
613
+ "name": "0",
614
+ "type": "something",
615
+ "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
616
+ "confidence": 0.42,
617
+ }
618
+ ],
619
+ )
620
+
621
+ assert len(responses.calls) == len(BASE_API_CALLS) + 1
622
+ assert [
623
+ (call.request.method, call.request.url) for call in responses.calls
624
+ ] == BASE_API_CALLS + [
625
+ (
626
+ "POST",
627
+ "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
628
+ ),
629
+ ]
630
+ assert json.loads(responses.calls[-1].request.body) == {
631
+ "elements": [
632
+ {
633
+ "name": "0",
634
+ "type": "something",
635
+ "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
636
+ "confidence": 0.42,
637
+ }
638
+ ],
639
+ "worker_run_id": "56785678-5678-5678-5678-567856785678",
640
+ }
641
+ assert created_ids == [{"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"}]
642
+
643
+ # Check that created elements were properly stored in SQLite cache
644
+ assert (tmp_path / "db.sqlite").is_file()
645
+
646
+ assert list(CachedElement.select()) == [
647
+ CachedElement(
648
+ id=UUID("497f6eca-6276-4993-bfeb-53cbbbba6f08"),
649
+ parent_id=UUID("12341234-1234-1234-1234-123412341234"),
650
+ type="something",
651
+ image_id="c0fec0fe-c0fe-c0fe-c0fe-c0fec0fec0fe",
652
+ polygon=[[1, 1], [2, 2], [2, 1], [1, 2]],
653
+ worker_run_id=UUID("56785678-5678-5678-5678-567856785678"),
654
+ confidence=0.42,
655
+ )
656
+ ]
657
+
658
+
659
+ def test_create_elements_integrity_error(
660
+ responses, mock_elements_worker_with_cache, caplog
661
+ ):
662
+ elt = Element(
663
+ {
664
+ "id": "12341234-1234-1234-1234-123412341234",
665
+ "zone": {
666
+ "image": {
667
+ "id": "c0fec0fe-c0fe-c0fe-c0fe-c0fec0fec0fe",
668
+ "width": 42,
669
+ "height": 42,
670
+ "url": "http://aaaa",
671
+ }
672
+ },
673
+ }
674
+ )
675
+ responses.add(
676
+ responses.POST,
677
+ "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
678
+ status=200,
679
+ json=[
680
+ # Duplicate IDs, which will cause an IntegrityError when stored in the cache
681
+ {"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"},
682
+ {"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"},
683
+ ],
684
+ )
685
+
686
+ elements = [
687
+ {
688
+ "name": "0",
689
+ "type": "something",
690
+ "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
691
+ },
692
+ {
693
+ "name": "1",
694
+ "type": "something",
695
+ "polygon": [[1, 1], [3, 3], [3, 1], [1, 3]],
696
+ },
697
+ ]
698
+
699
+ created_ids = mock_elements_worker_with_cache.create_elements(
700
+ parent=elt,
701
+ elements=elements,
702
+ )
703
+
704
+ assert created_ids == [
705
+ {"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"},
706
+ {"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"},
707
+ ]
708
+
709
+ assert len(caplog.records) == 3
710
+ assert caplog.records[-1].levelname == "WARNING"
711
+ assert caplog.records[-1].message.startswith(
712
+ "Couldn't save created elements in local cache:"
713
+ )
714
+
715
+ assert list(CachedElement.select()) == []