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
@@ -1,3704 +0,0 @@
1
- import json
2
- import re
3
- from argparse import Namespace
4
- from uuid import UUID
5
-
6
- import pytest
7
- from responses import matchers
8
-
9
- from arkindex.exceptions import ErrorResponse
10
- from arkindex_worker.cache import (
11
- SQL_VERSION,
12
- CachedElement,
13
- CachedImage,
14
- create_version_table,
15
- init_cache_db,
16
- )
17
- from arkindex_worker.models import Element
18
- from arkindex_worker.utils import DEFAULT_BATCH_SIZE
19
- from arkindex_worker.worker import ElementsWorker
20
- from arkindex_worker.worker.dataset import DatasetState
21
- from arkindex_worker.worker.element import MissingTypeError
22
- from arkindex_worker.worker.process import ProcessMode
23
- from tests import CORPUS_ID
24
-
25
- from . import BASE_API_CALLS
26
-
27
-
28
- def test_list_corpus_types(responses, mock_elements_worker):
29
- responses.add(
30
- responses.GET,
31
- f"http://testserver/api/v1/corpus/{CORPUS_ID}/",
32
- json={
33
- "id": CORPUS_ID,
34
- "types": [{"slug": "folder"}, {"slug": "page"}],
35
- },
36
- )
37
-
38
- mock_elements_worker.list_corpus_types()
39
-
40
- assert mock_elements_worker.corpus_types == {
41
- "folder": {"slug": "folder"},
42
- "page": {"slug": "page"},
43
- }
44
-
45
-
46
- def test_check_required_types_argument_types(mock_elements_worker):
47
- with pytest.raises(
48
- AssertionError, match="At least one element type slug is required."
49
- ):
50
- mock_elements_worker.check_required_types()
51
-
52
- with pytest.raises(AssertionError, match="Element type slugs must be strings."):
53
- mock_elements_worker.check_required_types("lol", 42)
54
-
55
-
56
- def test_check_required_types(mock_elements_worker):
57
- mock_elements_worker.corpus_types = {
58
- "folder": {"slug": "folder"},
59
- "page": {"slug": "page"},
60
- }
61
-
62
- assert mock_elements_worker.check_required_types("page")
63
- assert mock_elements_worker.check_required_types("page", "folder")
64
-
65
- with pytest.raises(
66
- MissingTypeError,
67
- match=re.escape(
68
- "Element types act, text_line were not found in corpus (11111111-1111-1111-1111-111111111111)."
69
- ),
70
- ):
71
- assert mock_elements_worker.check_required_types("page", "text_line", "act")
72
-
73
-
74
- def test_create_missing_types(responses, mock_elements_worker):
75
- mock_elements_worker.corpus_types = {
76
- "folder": {"slug": "folder"},
77
- "page": {"slug": "page"},
78
- }
79
-
80
- responses.add(
81
- responses.POST,
82
- "http://testserver/api/v1/elements/type/",
83
- match=[
84
- matchers.json_params_matcher(
85
- {
86
- "slug": "text_line",
87
- "display_name": "text_line",
88
- "folder": False,
89
- "corpus": CORPUS_ID,
90
- }
91
- )
92
- ],
93
- )
94
- responses.add(
95
- responses.POST,
96
- "http://testserver/api/v1/elements/type/",
97
- match=[
98
- matchers.json_params_matcher(
99
- {
100
- "slug": "act",
101
- "display_name": "act",
102
- "folder": False,
103
- "corpus": CORPUS_ID,
104
- }
105
- )
106
- ],
107
- )
108
-
109
- assert mock_elements_worker.check_required_types(
110
- "page", "text_line", "act", create_missing=True
111
- )
112
-
113
-
114
- def test_get_elements_elements_list_arg_wrong_type(
115
- monkeypatch, tmp_path, mock_elements_worker
116
- ):
117
- elements_path = tmp_path / "elements.json"
118
- elements_path.write_text("{}")
119
-
120
- monkeypatch.setenv("TASK_ELEMENTS", str(elements_path))
121
- worker = ElementsWorker()
122
- worker.configure()
123
-
124
- with pytest.raises(AssertionError, match="Elements list must be a list"):
125
- worker.get_elements()
126
-
127
-
128
- def test_get_elements_elements_list_arg_empty_list(
129
- monkeypatch, tmp_path, mock_elements_worker
130
- ):
131
- elements_path = tmp_path / "elements.json"
132
- elements_path.write_text("[]")
133
-
134
- monkeypatch.setenv("TASK_ELEMENTS", str(elements_path))
135
- worker = ElementsWorker()
136
- worker.configure()
137
-
138
- with pytest.raises(AssertionError, match="No elements in elements list"):
139
- worker.get_elements()
140
-
141
-
142
- def test_get_elements_elements_list_arg_missing_id(
143
- monkeypatch, tmp_path, mock_elements_worker
144
- ):
145
- elements_path = tmp_path / "elements.json"
146
- elements_path.write_text(json.dumps([{"type": "volume"}]))
147
-
148
- monkeypatch.setenv("TASK_ELEMENTS", str(elements_path))
149
- worker = ElementsWorker()
150
- worker.configure()
151
-
152
- elt_list = worker.get_elements()
153
-
154
- assert elt_list == []
155
-
156
-
157
- def test_get_elements_elements_list_arg_not_uuid(
158
- monkeypatch, tmp_path, mock_elements_worker
159
- ):
160
- elements_path = tmp_path / "elements.json"
161
- elements_path.write_text(
162
- json.dumps(
163
- [
164
- {"id": "volumeid", "type": "volume"},
165
- {"id": "pageid", "type": "page"},
166
- {"id": "actid", "type": "act"},
167
- {"id": "surfaceid", "type": "surface"},
168
- ]
169
- )
170
- )
171
-
172
- monkeypatch.setenv("TASK_ELEMENTS", str(elements_path))
173
- worker = ElementsWorker()
174
- worker.configure()
175
-
176
- with pytest.raises(
177
- Exception,
178
- match="These element IDs are invalid: volumeid, pageid, actid, surfaceid",
179
- ):
180
- worker.get_elements()
181
-
182
-
183
- def test_get_elements_elements_list_arg(monkeypatch, tmp_path, mock_elements_worker):
184
- elements_path = tmp_path / "elements.json"
185
- elements_path.write_text(
186
- json.dumps(
187
- [
188
- {"id": "11111111-1111-1111-1111-111111111111", "type": "volume"},
189
- {"id": "22222222-2222-2222-2222-222222222222", "type": "page"},
190
- {"id": "33333333-3333-3333-3333-333333333333", "type": "act"},
191
- ]
192
- )
193
- )
194
-
195
- monkeypatch.setenv("TASK_ELEMENTS", str(elements_path))
196
- worker = ElementsWorker()
197
- worker.configure()
198
-
199
- elt_list = worker.get_elements()
200
-
201
- assert elt_list == [
202
- "11111111-1111-1111-1111-111111111111",
203
- "22222222-2222-2222-2222-222222222222",
204
- "33333333-3333-3333-3333-333333333333",
205
- ]
206
-
207
-
208
- def test_get_elements_element_arg_not_uuid(mocker, mock_elements_worker):
209
- mocker.patch(
210
- "arkindex_worker.worker.base.argparse.ArgumentParser.parse_args",
211
- return_value=Namespace(
212
- element=["volumeid", "pageid"],
213
- config={},
214
- verbose=False,
215
- elements_list=None,
216
- database=None,
217
- dev=True,
218
- set=[],
219
- ),
220
- )
221
-
222
- worker = ElementsWorker()
223
- worker.configure()
224
-
225
- with pytest.raises(
226
- Exception, match="These element IDs are invalid: volumeid, pageid"
227
- ):
228
- worker.get_elements()
229
-
230
-
231
- def test_get_elements_element_arg(mocker, mock_elements_worker):
232
- mocker.patch(
233
- "arkindex_worker.worker.base.argparse.ArgumentParser.parse_args",
234
- return_value=Namespace(
235
- element=[
236
- "11111111-1111-1111-1111-111111111111",
237
- "22222222-2222-2222-2222-222222222222",
238
- ],
239
- config={},
240
- verbose=False,
241
- elements_list=None,
242
- database=None,
243
- dev=True,
244
- set=[],
245
- ),
246
- )
247
-
248
- worker = ElementsWorker()
249
- worker.configure()
250
-
251
- elt_list = worker.get_elements()
252
-
253
- assert elt_list == [
254
- "11111111-1111-1111-1111-111111111111",
255
- "22222222-2222-2222-2222-222222222222",
256
- ]
257
-
258
-
259
- def test_get_elements_dataset_set_arg(responses, mocker, mock_elements_worker):
260
- mocker.patch(
261
- "arkindex_worker.worker.base.argparse.ArgumentParser.parse_args",
262
- return_value=Namespace(
263
- element=[],
264
- config={},
265
- verbose=False,
266
- elements_list=None,
267
- database=None,
268
- dev=True,
269
- set=[(UUID("11111111-1111-1111-1111-111111111111"), "train")],
270
- ),
271
- )
272
-
273
- # Mock RetrieveDataset call
274
- responses.add(
275
- responses.GET,
276
- "http://testserver/api/v1/datasets/11111111-1111-1111-1111-111111111111/",
277
- status=200,
278
- json={
279
- "id": "11111111-1111-1111-1111-111111111111",
280
- "name": "My dataset",
281
- "description": "A dataset about cats.",
282
- "sets": ["train", "dev", "test"],
283
- "state": DatasetState.Complete.value,
284
- },
285
- content_type="application/json",
286
- )
287
-
288
- # Mock ListSetElements call
289
- element = {
290
- "id": "22222222-2222-2222-2222-222222222222",
291
- "type": "page",
292
- "name": "1",
293
- "corpus": {
294
- "id": "11111111-1111-1111-1111-111111111111",
295
- },
296
- "thumbnail_url": "http://example.com",
297
- "zone": {
298
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
299
- "polygon": [[0, 0], [0, 0], [0, 0]],
300
- "image": {
301
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
302
- "path": "string",
303
- "width": 0,
304
- "height": 0,
305
- "url": "http://example.com",
306
- "s3_url": "string",
307
- "status": "checked",
308
- "server": {
309
- "display_name": "string",
310
- "url": "http://example.com",
311
- "max_width": 2147483647,
312
- "max_height": 2147483647,
313
- },
314
- },
315
- "url": "http://example.com",
316
- },
317
- "rotation_angle": 0,
318
- "mirrored": False,
319
- "created": "2019-08-24T14:15:22Z",
320
- "classes": [
321
- {
322
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
323
- "ml_class": {
324
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
325
- "name": "string",
326
- },
327
- "state": "pending",
328
- "confidence": 0,
329
- "high_confidence": True,
330
- "worker_run": {
331
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
332
- "summary": "string",
333
- },
334
- }
335
- ],
336
- "metadata": [
337
- {
338
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
339
- "type": "text",
340
- "name": "string",
341
- "value": "string",
342
- "dates": [{"type": "exact", "year": 0, "month": 1, "day": 1}],
343
- }
344
- ],
345
- "transcriptions": [
346
- {
347
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
348
- "text": "string",
349
- "confidence": 0,
350
- "orientation": "horizontal-lr",
351
- "worker_run": {
352
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
353
- "summary": "string",
354
- },
355
- }
356
- ],
357
- "has_children": True,
358
- "worker_run": {
359
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
360
- "summary": "string",
361
- },
362
- "confidence": 1,
363
- }
364
- responses.add(
365
- responses.GET,
366
- "http://testserver/api/v1/datasets/11111111-1111-1111-1111-111111111111/elements/?set=train&with_count=true",
367
- status=200,
368
- json={
369
- "next": None,
370
- "previous": None,
371
- "results": [
372
- {
373
- "set": "train",
374
- "element": element,
375
- }
376
- ],
377
- "count": 1,
378
- },
379
- content_type="application/json",
380
- )
381
-
382
- worker = ElementsWorker()
383
- worker.configure()
384
-
385
- elt_list = worker.get_elements()
386
-
387
- assert elt_list == [
388
- Element(**element),
389
- ]
390
-
391
-
392
- def test_get_elements_dataset_set_api(responses, mocker, mock_elements_worker):
393
- # Mock ListProcessSets call
394
- responses.add(
395
- responses.GET,
396
- "http://testserver/api/v1/process/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeffff/sets/",
397
- status=200,
398
- json={
399
- "next": None,
400
- "previous": None,
401
- "results": [
402
- {
403
- "id": "33333333-3333-3333-3333-333333333333",
404
- "dataset": {"id": "11111111-1111-1111-1111-111111111111"},
405
- "set_name": "train",
406
- }
407
- ],
408
- "count": 1,
409
- },
410
- content_type="application/json",
411
- )
412
-
413
- # Mock ListSetElements call
414
- element = {
415
- "id": "22222222-2222-2222-2222-222222222222",
416
- "type": "page",
417
- "name": "1",
418
- "corpus": {
419
- "id": "11111111-1111-1111-1111-111111111111",
420
- },
421
- "thumbnail_url": "http://example.com",
422
- "zone": {
423
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
424
- "polygon": [[0, 0], [0, 0], [0, 0]],
425
- "image": {
426
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
427
- "path": "string",
428
- "width": 0,
429
- "height": 0,
430
- "url": "http://example.com",
431
- "s3_url": "string",
432
- "status": "checked",
433
- "server": {
434
- "display_name": "string",
435
- "url": "http://example.com",
436
- "max_width": 2147483647,
437
- "max_height": 2147483647,
438
- },
439
- },
440
- "url": "http://example.com",
441
- },
442
- "rotation_angle": 0,
443
- "mirrored": False,
444
- "created": "2019-08-24T14:15:22Z",
445
- "classes": [
446
- {
447
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
448
- "ml_class": {
449
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
450
- "name": "string",
451
- },
452
- "state": "pending",
453
- "confidence": 0,
454
- "high_confidence": True,
455
- "worker_run": {
456
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
457
- "summary": "string",
458
- },
459
- }
460
- ],
461
- "metadata": [
462
- {
463
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
464
- "type": "text",
465
- "name": "string",
466
- "value": "string",
467
- "dates": [{"type": "exact", "year": 0, "month": 1, "day": 1}],
468
- }
469
- ],
470
- "transcriptions": [
471
- {
472
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
473
- "text": "string",
474
- "confidence": 0,
475
- "orientation": "horizontal-lr",
476
- "worker_run": {
477
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
478
- "summary": "string",
479
- },
480
- }
481
- ],
482
- "has_children": True,
483
- "worker_run": {
484
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
485
- "summary": "string",
486
- },
487
- "confidence": 1,
488
- }
489
- responses.add(
490
- responses.GET,
491
- "http://testserver/api/v1/datasets/11111111-1111-1111-1111-111111111111/elements/?set=train&with_count=true",
492
- status=200,
493
- json={
494
- "next": None,
495
- "previous": None,
496
- "results": [
497
- {
498
- "set": "train",
499
- "element": element,
500
- }
501
- ],
502
- "count": 1,
503
- },
504
- content_type="application/json",
505
- )
506
-
507
- # Update ProcessMode to Dataset
508
- mock_elements_worker.process_information["mode"] = ProcessMode.Dataset
509
-
510
- elt_list = mock_elements_worker.get_elements()
511
-
512
- assert elt_list == [
513
- Element(**element),
514
- ]
515
-
516
-
517
- def test_get_elements_both_args_error(mocker, mock_elements_worker, tmp_path):
518
- elements_path = tmp_path / "elements.json"
519
- elements_path.write_text(
520
- json.dumps(
521
- [
522
- {"id": "volumeid", "type": "volume"},
523
- {"id": "pageid", "type": "page"},
524
- {"id": "actid", "type": "act"},
525
- {"id": "surfaceid", "type": "surface"},
526
- ]
527
- )
528
- )
529
- mocker.patch(
530
- "arkindex_worker.worker.base.argparse.ArgumentParser.parse_args",
531
- return_value=Namespace(
532
- element=["anotherid", "againanotherid"],
533
- verbose=False,
534
- elements_list=elements_path.open(),
535
- database=None,
536
- dev=False,
537
- set=[],
538
- ),
539
- )
540
-
541
- worker = ElementsWorker()
542
- worker.configure()
543
-
544
- with pytest.raises(
545
- AssertionError, match="elements-list and element CLI args shouldn't be both set"
546
- ):
547
- worker.get_elements()
548
-
549
-
550
- def test_database_arg(mocker, mock_elements_worker, tmp_path):
551
- database_path = tmp_path / "my_database.sqlite"
552
- init_cache_db(database_path)
553
- create_version_table()
554
-
555
- mocker.patch(
556
- "arkindex_worker.worker.base.argparse.ArgumentParser.parse_args",
557
- return_value=Namespace(
558
- element=["volumeid", "pageid"],
559
- verbose=False,
560
- elements_list=None,
561
- database=database_path,
562
- dev=False,
563
- set=[],
564
- ),
565
- )
566
-
567
- worker = ElementsWorker(support_cache=True)
568
- worker.configure()
569
-
570
- assert worker.use_cache is True
571
- assert worker.cache_path == database_path
572
-
573
-
574
- def test_database_arg_cache_missing_version_table(
575
- mocker, mock_elements_worker, tmp_path
576
- ):
577
- database_path = tmp_path / "my_database.sqlite"
578
- database_path.touch()
579
-
580
- mocker.patch(
581
- "arkindex_worker.worker.base.argparse.ArgumentParser.parse_args",
582
- return_value=Namespace(
583
- element=["volumeid", "pageid"],
584
- verbose=False,
585
- elements_list=None,
586
- database=database_path,
587
- dev=False,
588
- set=[],
589
- ),
590
- )
591
-
592
- worker = ElementsWorker(support_cache=True)
593
- with pytest.raises(
594
- AssertionError,
595
- match=f"The SQLite database {database_path} does not have the correct cache version, it should be {SQL_VERSION}",
596
- ):
597
- worker.configure()
598
-
599
-
600
- def test_load_corpus_classes_api_error(responses, mock_elements_worker):
601
- responses.add(
602
- responses.GET,
603
- f"http://testserver/api/v1/corpus/{CORPUS_ID}/classes/",
604
- status=418,
605
- )
606
-
607
- assert not mock_elements_worker.classes
608
- with pytest.raises(
609
- Exception, match="Stopping pagination as data will be incomplete"
610
- ):
611
- mock_elements_worker.load_corpus_classes()
612
-
613
- assert len(responses.calls) == len(BASE_API_CALLS) + 5
614
- assert [
615
- (call.request.method, call.request.url) for call in responses.calls
616
- ] == BASE_API_CALLS + [
617
- # We do 5 retries
618
- (
619
- "GET",
620
- f"http://testserver/api/v1/corpus/{CORPUS_ID}/classes/",
621
- ),
622
- (
623
- "GET",
624
- f"http://testserver/api/v1/corpus/{CORPUS_ID}/classes/",
625
- ),
626
- (
627
- "GET",
628
- f"http://testserver/api/v1/corpus/{CORPUS_ID}/classes/",
629
- ),
630
- (
631
- "GET",
632
- f"http://testserver/api/v1/corpus/{CORPUS_ID}/classes/",
633
- ),
634
- (
635
- "GET",
636
- f"http://testserver/api/v1/corpus/{CORPUS_ID}/classes/",
637
- ),
638
- ]
639
- assert not mock_elements_worker.classes
640
-
641
-
642
- def test_load_corpus_classes(responses, mock_elements_worker):
643
- responses.add(
644
- responses.GET,
645
- f"http://testserver/api/v1/corpus/{CORPUS_ID}/classes/",
646
- status=200,
647
- json={
648
- "count": 3,
649
- "next": None,
650
- "results": [
651
- {
652
- "id": "0000",
653
- "name": "good",
654
- },
655
- {
656
- "id": "1111",
657
- "name": "average",
658
- },
659
- {
660
- "id": "2222",
661
- "name": "bad",
662
- },
663
- ],
664
- },
665
- )
666
-
667
- assert not mock_elements_worker.classes
668
- mock_elements_worker.load_corpus_classes()
669
-
670
- assert len(responses.calls) == len(BASE_API_CALLS) + 1
671
- assert [
672
- (call.request.method, call.request.url) for call in responses.calls
673
- ] == BASE_API_CALLS + [
674
- (
675
- "GET",
676
- f"http://testserver/api/v1/corpus/{CORPUS_ID}/classes/",
677
- ),
678
- ]
679
- assert mock_elements_worker.classes == {
680
- "good": "0000",
681
- "average": "1111",
682
- "bad": "2222",
683
- }
684
-
685
-
686
- def test_create_sub_element_wrong_element(mock_elements_worker):
687
- with pytest.raises(
688
- AssertionError, match="element shouldn't be null and should be of type Element"
689
- ):
690
- mock_elements_worker.create_sub_element(
691
- element=None,
692
- type="something",
693
- name="0",
694
- polygon=[[1, 1], [2, 2], [2, 1], [1, 2]],
695
- )
696
-
697
- with pytest.raises(
698
- AssertionError, match="element shouldn't be null and should be of type Element"
699
- ):
700
- mock_elements_worker.create_sub_element(
701
- element="not element type",
702
- type="something",
703
- name="0",
704
- polygon=[[1, 1], [2, 2], [2, 1], [1, 2]],
705
- )
706
-
707
-
708
- def test_create_sub_element_wrong_type(mock_elements_worker):
709
- elt = Element({"zone": None})
710
-
711
- with pytest.raises(
712
- AssertionError, match="type shouldn't be null and should be of type str"
713
- ):
714
- mock_elements_worker.create_sub_element(
715
- element=elt,
716
- type=None,
717
- name="0",
718
- polygon=[[1, 1], [2, 2], [2, 1], [1, 2]],
719
- )
720
-
721
- with pytest.raises(
722
- AssertionError, match="type shouldn't be null and should be of type str"
723
- ):
724
- mock_elements_worker.create_sub_element(
725
- element=elt,
726
- type=1234,
727
- name="0",
728
- polygon=[[1, 1], [2, 2], [2, 1], [1, 2]],
729
- )
730
-
731
-
732
- def test_create_sub_element_wrong_name(mock_elements_worker):
733
- elt = Element({"zone": None})
734
-
735
- with pytest.raises(
736
- AssertionError, match="name shouldn't be null and should be of type str"
737
- ):
738
- mock_elements_worker.create_sub_element(
739
- element=elt,
740
- type="something",
741
- name=None,
742
- polygon=[[1, 1], [2, 2], [2, 1], [1, 2]],
743
- )
744
-
745
- with pytest.raises(
746
- AssertionError, match="name shouldn't be null and should be of type str"
747
- ):
748
- mock_elements_worker.create_sub_element(
749
- element=elt,
750
- type="something",
751
- name=1234,
752
- polygon=[[1, 1], [2, 2], [2, 1], [1, 2]],
753
- )
754
-
755
-
756
- def test_create_sub_element_wrong_polygon(mock_elements_worker):
757
- elt = Element({"zone": None})
758
-
759
- with pytest.raises(AssertionError, match="polygon should be None or a list"):
760
- mock_elements_worker.create_sub_element(
761
- element=elt,
762
- type="something",
763
- name="O",
764
- polygon="not a polygon",
765
- )
766
-
767
- with pytest.raises(
768
- AssertionError, match="polygon should have at least three points"
769
- ):
770
- mock_elements_worker.create_sub_element(
771
- element=elt,
772
- type="something",
773
- name="O",
774
- polygon=[[1, 1], [2, 2]],
775
- )
776
-
777
- with pytest.raises(
778
- AssertionError, match="polygon points should be lists of two items"
779
- ):
780
- mock_elements_worker.create_sub_element(
781
- element=elt,
782
- type="something",
783
- name="O",
784
- polygon=[[1, 1, 1], [2, 2, 1], [2, 1, 1], [1, 2, 1]],
785
- )
786
-
787
- with pytest.raises(
788
- AssertionError, match="polygon points should be lists of two items"
789
- ):
790
- mock_elements_worker.create_sub_element(
791
- element=elt,
792
- type="something",
793
- name="O",
794
- polygon=[[1], [2], [2], [1]],
795
- )
796
-
797
- with pytest.raises(
798
- AssertionError, match="polygon points should be lists of two numbers"
799
- ):
800
- mock_elements_worker.create_sub_element(
801
- element=elt,
802
- type="something",
803
- name="O",
804
- polygon=[["not a coord", 1], [2, 2], [2, 1], [1, 2]],
805
- )
806
-
807
-
808
- @pytest.mark.parametrize("confidence", ["lol", "0.2", -1.0, 1.42, float("inf")])
809
- def test_create_sub_element_wrong_confidence(mock_elements_worker, confidence):
810
- with pytest.raises(
811
- AssertionError,
812
- match=re.escape("confidence should be None or a float in [0..1] range"),
813
- ):
814
- mock_elements_worker.create_sub_element(
815
- element=Element({"zone": None}),
816
- type="something",
817
- name="blah",
818
- polygon=[[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]],
819
- confidence=confidence,
820
- )
821
-
822
-
823
- @pytest.mark.parametrize(
824
- ("image", "error_type", "error_message"),
825
- [
826
- (1, AssertionError, "image should be None or string"),
827
- ("not a uuid", ValueError, "image is not a valid uuid."),
828
- ],
829
- )
830
- def test_create_sub_element_wrong_image(
831
- mock_elements_worker, image, error_type, error_message
832
- ):
833
- with pytest.raises(error_type, match=re.escape(error_message)):
834
- mock_elements_worker.create_sub_element(
835
- element=Element({"zone": None}),
836
- type="something",
837
- name="blah",
838
- polygon=[[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]],
839
- image=image,
840
- )
841
-
842
-
843
- def test_create_sub_element_wrong_image_and_polygon(mock_elements_worker):
844
- with pytest.raises(
845
- AssertionError,
846
- match=re.escape(
847
- "An image or a parent with an image is required to create an element with a polygon."
848
- ),
849
- ):
850
- mock_elements_worker.create_sub_element(
851
- element=Element({"zone": None}),
852
- type="something",
853
- name="blah",
854
- polygon=[[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]],
855
- image=None,
856
- )
857
-
858
-
859
- def test_create_sub_element_api_error(responses, mock_elements_worker):
860
- elt = Element(
861
- {
862
- "id": "12341234-1234-1234-1234-123412341234",
863
- "corpus": {"id": CORPUS_ID},
864
- "zone": {"image": {"id": "22222222-2222-2222-2222-222222222222"}},
865
- }
866
- )
867
- responses.add(
868
- responses.POST,
869
- "http://testserver/api/v1/elements/create/",
870
- status=418,
871
- )
872
-
873
- with pytest.raises(ErrorResponse):
874
- mock_elements_worker.create_sub_element(
875
- element=elt,
876
- type="something",
877
- name="0",
878
- polygon=[[1, 1], [2, 2], [2, 1], [1, 2]],
879
- )
880
-
881
- assert len(responses.calls) == len(BASE_API_CALLS) + 1
882
- assert [
883
- (call.request.method, call.request.url) for call in responses.calls
884
- ] == BASE_API_CALLS + [("POST", "http://testserver/api/v1/elements/create/")]
885
-
886
-
887
- @pytest.mark.parametrize("slim_output", [True, False])
888
- def test_create_sub_element(responses, mock_elements_worker, slim_output):
889
- elt = Element(
890
- {
891
- "id": "12341234-1234-1234-1234-123412341234",
892
- "corpus": {"id": CORPUS_ID},
893
- "zone": {"image": {"id": "22222222-2222-2222-2222-222222222222"}},
894
- }
895
- )
896
- child_elt = {
897
- "id": "12345678-1234-1234-1234-123456789123",
898
- "corpus": {"id": CORPUS_ID},
899
- "zone": {"image": {"id": "22222222-2222-2222-2222-222222222222"}},
900
- }
901
- responses.add(
902
- responses.POST,
903
- "http://testserver/api/v1/elements/create/",
904
- status=200,
905
- json=child_elt,
906
- )
907
-
908
- element_creation_response = mock_elements_worker.create_sub_element(
909
- element=elt,
910
- type="something",
911
- name="0",
912
- polygon=[[1, 1], [2, 2], [2, 1], [1, 2]],
913
- slim_output=slim_output,
914
- )
915
-
916
- assert len(responses.calls) == len(BASE_API_CALLS) + 1
917
- assert [
918
- (call.request.method, call.request.url) for call in responses.calls
919
- ] == BASE_API_CALLS + [
920
- (
921
- "POST",
922
- "http://testserver/api/v1/elements/create/",
923
- ),
924
- ]
925
- assert json.loads(responses.calls[-1].request.body) == {
926
- "type": "something",
927
- "name": "0",
928
- "image": None,
929
- "corpus": CORPUS_ID,
930
- "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
931
- "parent": "12341234-1234-1234-1234-123412341234",
932
- "worker_run_id": "56785678-5678-5678-5678-567856785678",
933
- "confidence": None,
934
- }
935
- if slim_output:
936
- assert element_creation_response == "12345678-1234-1234-1234-123456789123"
937
- else:
938
- assert Element(element_creation_response) == Element(child_elt)
939
-
940
-
941
- def test_create_sub_element_confidence(responses, mock_elements_worker):
942
- elt = Element(
943
- {
944
- "id": "12341234-1234-1234-1234-123412341234",
945
- "corpus": {"id": CORPUS_ID},
946
- "zone": {"image": {"id": "22222222-2222-2222-2222-222222222222"}},
947
- }
948
- )
949
- responses.add(
950
- responses.POST,
951
- "http://testserver/api/v1/elements/create/",
952
- status=200,
953
- json={"id": "12345678-1234-1234-1234-123456789123"},
954
- )
955
-
956
- sub_element_id = mock_elements_worker.create_sub_element(
957
- element=elt,
958
- type="something",
959
- name="0",
960
- polygon=[[1, 1], [2, 2], [2, 1], [1, 2]],
961
- confidence=0.42,
962
- )
963
-
964
- assert len(responses.calls) == len(BASE_API_CALLS) + 1
965
- assert [
966
- (call.request.method, call.request.url) for call in responses.calls
967
- ] == BASE_API_CALLS + [
968
- ("POST", "http://testserver/api/v1/elements/create/"),
969
- ]
970
- assert json.loads(responses.calls[-1].request.body) == {
971
- "type": "something",
972
- "name": "0",
973
- "image": None,
974
- "corpus": CORPUS_ID,
975
- "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
976
- "parent": "12341234-1234-1234-1234-123412341234",
977
- "worker_run_id": "56785678-5678-5678-5678-567856785678",
978
- "confidence": 0.42,
979
- }
980
- assert sub_element_id == "12345678-1234-1234-1234-123456789123"
981
-
982
-
983
- def test_create_elements_wrong_parent(mock_elements_worker):
984
- with pytest.raises(
985
- TypeError, match="Parent element should be an Element or CachedElement instance"
986
- ):
987
- mock_elements_worker.create_elements(
988
- parent=None,
989
- elements=[],
990
- )
991
-
992
- with pytest.raises(
993
- TypeError, match="Parent element should be an Element or CachedElement instance"
994
- ):
995
- mock_elements_worker.create_elements(
996
- parent="not element type",
997
- elements=[],
998
- )
999
-
1000
-
1001
- def test_create_elements_no_zone(mock_elements_worker):
1002
- elt = Element({"zone": None})
1003
- with pytest.raises(
1004
- AssertionError, match="create_elements cannot be used on parents without zones"
1005
- ):
1006
- mock_elements_worker.create_elements(
1007
- parent=elt,
1008
- elements=None,
1009
- )
1010
-
1011
- elt = CachedElement(
1012
- id="11111111-1111-1111-1111-1111111111", name="blah", type="blah"
1013
- )
1014
- with pytest.raises(
1015
- AssertionError, match="create_elements cannot be used on parents without images"
1016
- ):
1017
- mock_elements_worker.create_elements(
1018
- parent=elt,
1019
- elements=None,
1020
- )
1021
-
1022
-
1023
- def test_create_elements_wrong_elements(mock_elements_worker):
1024
- elt = Element({"zone": {"image": {"id": "image_id"}}})
1025
-
1026
- with pytest.raises(
1027
- AssertionError, match="elements shouldn't be null and should be of type list"
1028
- ):
1029
- mock_elements_worker.create_elements(
1030
- parent=elt,
1031
- elements=None,
1032
- )
1033
-
1034
- with pytest.raises(
1035
- AssertionError, match="elements shouldn't be null and should be of type list"
1036
- ):
1037
- mock_elements_worker.create_elements(
1038
- parent=elt,
1039
- elements="not a list",
1040
- )
1041
-
1042
-
1043
- def test_create_elements_wrong_elements_instance(mock_elements_worker):
1044
- elt = Element({"zone": {"image": {"id": "image_id"}}})
1045
-
1046
- with pytest.raises(
1047
- AssertionError, match="Element at index 0 in elements: Should be of type dict"
1048
- ):
1049
- mock_elements_worker.create_elements(
1050
- parent=elt,
1051
- elements=["not a dict"],
1052
- )
1053
-
1054
-
1055
- def test_create_elements_wrong_elements_name(mock_elements_worker):
1056
- elt = Element({"zone": {"image": {"id": "image_id"}}})
1057
-
1058
- with pytest.raises(
1059
- AssertionError,
1060
- match="Element at index 0 in elements: name shouldn't be null and should be of type str",
1061
- ):
1062
- mock_elements_worker.create_elements(
1063
- parent=elt,
1064
- elements=[
1065
- {
1066
- "name": None,
1067
- "type": "something",
1068
- "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
1069
- }
1070
- ],
1071
- )
1072
-
1073
- with pytest.raises(
1074
- AssertionError,
1075
- match="Element at index 0 in elements: name shouldn't be null and should be of type str",
1076
- ):
1077
- mock_elements_worker.create_elements(
1078
- parent=elt,
1079
- elements=[
1080
- {
1081
- "name": 1234,
1082
- "type": "something",
1083
- "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
1084
- }
1085
- ],
1086
- )
1087
-
1088
-
1089
- def test_create_elements_wrong_elements_type(mock_elements_worker):
1090
- elt = Element({"zone": {"image": {"id": "image_id"}}})
1091
-
1092
- with pytest.raises(
1093
- AssertionError,
1094
- match="Element at index 0 in elements: type shouldn't be null and should be of type str",
1095
- ):
1096
- mock_elements_worker.create_elements(
1097
- parent=elt,
1098
- elements=[
1099
- {
1100
- "name": "0",
1101
- "type": None,
1102
- "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
1103
- }
1104
- ],
1105
- )
1106
-
1107
- with pytest.raises(
1108
- AssertionError,
1109
- match="Element at index 0 in elements: type shouldn't be null and should be of type str",
1110
- ):
1111
- mock_elements_worker.create_elements(
1112
- parent=elt,
1113
- elements=[
1114
- {
1115
- "name": "0",
1116
- "type": 1234,
1117
- "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
1118
- }
1119
- ],
1120
- )
1121
-
1122
-
1123
- def test_create_elements_wrong_elements_polygon(mock_elements_worker):
1124
- elt = Element({"zone": {"image": {"id": "image_id"}}})
1125
-
1126
- with pytest.raises(
1127
- AssertionError,
1128
- match="Element at index 0 in elements: polygon shouldn't be null and should be of type list",
1129
- ):
1130
- mock_elements_worker.create_elements(
1131
- parent=elt,
1132
- elements=[
1133
- {
1134
- "name": "0",
1135
- "type": "something",
1136
- "polygon": None,
1137
- }
1138
- ],
1139
- )
1140
-
1141
- with pytest.raises(
1142
- AssertionError,
1143
- match="Element at index 0 in elements: polygon shouldn't be null and should be of type list",
1144
- ):
1145
- mock_elements_worker.create_elements(
1146
- parent=elt,
1147
- elements=[
1148
- {
1149
- "name": "0",
1150
- "type": "something",
1151
- "polygon": "not a polygon",
1152
- }
1153
- ],
1154
- )
1155
-
1156
- with pytest.raises(
1157
- AssertionError,
1158
- match="Element at index 0 in elements: polygon should have at least three points",
1159
- ):
1160
- mock_elements_worker.create_elements(
1161
- parent=elt,
1162
- elements=[
1163
- {
1164
- "name": "0",
1165
- "type": "something",
1166
- "polygon": [[1, 1], [2, 2]],
1167
- }
1168
- ],
1169
- )
1170
-
1171
- with pytest.raises(
1172
- AssertionError,
1173
- match="Element at index 0 in elements: polygon points should be lists of two items",
1174
- ):
1175
- mock_elements_worker.create_elements(
1176
- parent=elt,
1177
- elements=[
1178
- {
1179
- "name": "0",
1180
- "type": "something",
1181
- "polygon": [[1, 1, 1], [2, 2, 1], [2, 1, 1], [1, 2, 1]],
1182
- }
1183
- ],
1184
- )
1185
-
1186
- with pytest.raises(
1187
- AssertionError,
1188
- match="Element at index 0 in elements: polygon points should be lists of two items",
1189
- ):
1190
- mock_elements_worker.create_elements(
1191
- parent=elt,
1192
- elements=[
1193
- {
1194
- "name": "0",
1195
- "type": "something",
1196
- "polygon": [[1], [2], [2], [1]],
1197
- }
1198
- ],
1199
- )
1200
-
1201
- with pytest.raises(
1202
- AssertionError,
1203
- match="Element at index 0 in elements: polygon points should be lists of two numbers",
1204
- ):
1205
- mock_elements_worker.create_elements(
1206
- parent=elt,
1207
- elements=[
1208
- {
1209
- "name": "0",
1210
- "type": "something",
1211
- "polygon": [["not a coord", 1], [2, 2], [2, 1], [1, 2]],
1212
- }
1213
- ],
1214
- )
1215
-
1216
-
1217
- @pytest.mark.parametrize("confidence", ["lol", "0.2", -1.0, 1.42, float("inf")])
1218
- def test_create_elements_wrong_elements_confidence(mock_elements_worker, confidence):
1219
- with pytest.raises(
1220
- AssertionError,
1221
- match=re.escape(
1222
- "Element at index 0 in elements: confidence should be None or a float in [0..1] range"
1223
- ),
1224
- ):
1225
- mock_elements_worker.create_elements(
1226
- parent=Element({"zone": {"image": {"id": "image_id"}}}),
1227
- elements=[
1228
- {
1229
- "name": "a",
1230
- "type": "something",
1231
- "polygon": [[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]],
1232
- "confidence": confidence,
1233
- }
1234
- ],
1235
- )
1236
-
1237
-
1238
- def test_create_elements_api_error(responses, mock_elements_worker):
1239
- elt = Element(
1240
- {
1241
- "id": "12341234-1234-1234-1234-123412341234",
1242
- "zone": {
1243
- "image": {
1244
- "id": "c0fec0fe-c0fe-c0fe-c0fe-c0fec0fec0fe",
1245
- "width": 42,
1246
- "height": 42,
1247
- "url": "http://aaaa",
1248
- }
1249
- },
1250
- }
1251
- )
1252
- responses.add(
1253
- responses.POST,
1254
- "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
1255
- status=418,
1256
- )
1257
-
1258
- with pytest.raises(ErrorResponse):
1259
- mock_elements_worker.create_elements(
1260
- parent=elt,
1261
- elements=[
1262
- {
1263
- "name": "0",
1264
- "type": "something",
1265
- "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
1266
- }
1267
- ],
1268
- )
1269
-
1270
- assert len(responses.calls) == len(BASE_API_CALLS) + 1
1271
- assert [
1272
- (call.request.method, call.request.url) for call in responses.calls
1273
- ] == BASE_API_CALLS + [
1274
- (
1275
- "POST",
1276
- "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
1277
- )
1278
- ]
1279
-
1280
-
1281
- @pytest.mark.parametrize("batch_size", [DEFAULT_BATCH_SIZE, 1])
1282
- def test_create_elements_cached_element(
1283
- batch_size, responses, mock_elements_worker_with_cache
1284
- ):
1285
- image = CachedImage.create(
1286
- id=UUID("c0fec0fe-c0fe-c0fe-c0fe-c0fec0fec0fe"),
1287
- width=42,
1288
- height=42,
1289
- url="http://aaaa",
1290
- )
1291
- elt = CachedElement.create(
1292
- id=UUID("12341234-1234-1234-1234-123412341234"),
1293
- type="parent",
1294
- image_id=image.id,
1295
- polygon="[[0, 0], [0, 1000], [1000, 1000], [1000, 0], [0, 0]]",
1296
- )
1297
-
1298
- if batch_size > 1:
1299
- responses.add(
1300
- responses.POST,
1301
- "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
1302
- status=200,
1303
- json=[
1304
- {"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"},
1305
- {"id": "5468c358-b9c4-499d-8b92-d6349c58e88d"},
1306
- ],
1307
- )
1308
- else:
1309
- for elt_id in [
1310
- "497f6eca-6276-4993-bfeb-53cbbbba6f08",
1311
- "5468c358-b9c4-499d-8b92-d6349c58e88d",
1312
- ]:
1313
- responses.add(
1314
- responses.POST,
1315
- "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
1316
- status=200,
1317
- json=[{"id": elt_id}],
1318
- )
1319
-
1320
- created_ids = mock_elements_worker_with_cache.create_elements(
1321
- parent=elt,
1322
- elements=[
1323
- {
1324
- "name": "0",
1325
- "type": "something",
1326
- "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
1327
- },
1328
- {
1329
- "name": "1",
1330
- "type": "something",
1331
- "polygon": [[4, 4], [5, 5], [5, 4], [4, 5]],
1332
- },
1333
- ],
1334
- batch_size=batch_size,
1335
- )
1336
-
1337
- bulk_api_calls = [
1338
- (
1339
- "POST",
1340
- "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
1341
- )
1342
- ]
1343
- if batch_size != DEFAULT_BATCH_SIZE:
1344
- bulk_api_calls.append(
1345
- (
1346
- "POST",
1347
- "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
1348
- )
1349
- )
1350
-
1351
- assert len(responses.calls) == len(BASE_API_CALLS) + len(bulk_api_calls)
1352
- assert [
1353
- (call.request.method, call.request.url) for call in responses.calls
1354
- ] == BASE_API_CALLS + bulk_api_calls
1355
-
1356
- first_elt = {
1357
- "name": "0",
1358
- "type": "something",
1359
- "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
1360
- }
1361
- second_elt = {
1362
- "name": "1",
1363
- "type": "something",
1364
- "polygon": [[4, 4], [5, 5], [5, 4], [4, 5]],
1365
- }
1366
- empty_payload = {
1367
- "elements": [],
1368
- "worker_run_id": "56785678-5678-5678-5678-567856785678",
1369
- }
1370
-
1371
- bodies = []
1372
- first_call_idx = None
1373
- if batch_size > 1:
1374
- first_call_idx = -1
1375
- bodies.append({**empty_payload, "elements": [first_elt, second_elt]})
1376
- else:
1377
- first_call_idx = -2
1378
- bodies.append({**empty_payload, "elements": [first_elt]})
1379
- bodies.append({**empty_payload, "elements": [second_elt]})
1380
-
1381
- assert [
1382
- json.loads(bulk_call.request.body)
1383
- for bulk_call in responses.calls[first_call_idx:]
1384
- ] == bodies
1385
-
1386
- assert created_ids == [
1387
- {"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"},
1388
- {"id": "5468c358-b9c4-499d-8b92-d6349c58e88d"},
1389
- ]
1390
-
1391
- # Check that created elements were properly stored in SQLite cache
1392
- assert list(CachedElement.select().order_by(CachedElement.id)) == [
1393
- elt,
1394
- CachedElement(
1395
- id=UUID("497f6eca-6276-4993-bfeb-53cbbbba6f08"),
1396
- parent_id=elt.id,
1397
- type="something",
1398
- image_id="c0fec0fe-c0fe-c0fe-c0fe-c0fec0fec0fe",
1399
- polygon=[[1, 1], [2, 2], [2, 1], [1, 2]],
1400
- worker_run_id=UUID("56785678-5678-5678-5678-567856785678"),
1401
- confidence=None,
1402
- ),
1403
- CachedElement(
1404
- id=UUID("5468c358-b9c4-499d-8b92-d6349c58e88d"),
1405
- parent_id=elt.id,
1406
- type="something",
1407
- image_id="c0fec0fe-c0fe-c0fe-c0fe-c0fec0fec0fe",
1408
- polygon=[[4, 4], [5, 5], [5, 4], [4, 5]],
1409
- worker_run_id=UUID("56785678-5678-5678-5678-567856785678"),
1410
- confidence=None,
1411
- ),
1412
- ]
1413
-
1414
-
1415
- @pytest.mark.parametrize("batch_size", [DEFAULT_BATCH_SIZE, 1])
1416
- def test_create_elements(
1417
- batch_size, responses, mock_elements_worker_with_cache, tmp_path
1418
- ):
1419
- elt = Element(
1420
- {
1421
- "id": "12341234-1234-1234-1234-123412341234",
1422
- "zone": {
1423
- "image": {
1424
- "id": "c0fec0fe-c0fe-c0fe-c0fe-c0fec0fec0fe",
1425
- "width": 42,
1426
- "height": 42,
1427
- "url": "http://aaaa",
1428
- }
1429
- },
1430
- }
1431
- )
1432
-
1433
- if batch_size > 1:
1434
- responses.add(
1435
- responses.POST,
1436
- "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
1437
- status=200,
1438
- json=[
1439
- {"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"},
1440
- {"id": "5468c358-b9c4-499d-8b92-d6349c58e88d"},
1441
- ],
1442
- )
1443
- else:
1444
- for elt_id in [
1445
- "497f6eca-6276-4993-bfeb-53cbbbba6f08",
1446
- "5468c358-b9c4-499d-8b92-d6349c58e88d",
1447
- ]:
1448
- responses.add(
1449
- responses.POST,
1450
- "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
1451
- status=200,
1452
- json=[{"id": elt_id}],
1453
- )
1454
-
1455
- created_ids = mock_elements_worker_with_cache.create_elements(
1456
- parent=elt,
1457
- elements=[
1458
- {
1459
- "name": "0",
1460
- "type": "something",
1461
- "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
1462
- },
1463
- {
1464
- "name": "1",
1465
- "type": "something",
1466
- "polygon": [[4, 4], [5, 5], [5, 4], [4, 5]],
1467
- },
1468
- ],
1469
- batch_size=batch_size,
1470
- )
1471
-
1472
- bulk_api_calls = [
1473
- (
1474
- "POST",
1475
- "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
1476
- )
1477
- ]
1478
- if batch_size != DEFAULT_BATCH_SIZE:
1479
- bulk_api_calls.append(
1480
- (
1481
- "POST",
1482
- "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
1483
- )
1484
- )
1485
-
1486
- assert len(responses.calls) == len(BASE_API_CALLS) + len(bulk_api_calls)
1487
- assert [
1488
- (call.request.method, call.request.url) for call in responses.calls
1489
- ] == BASE_API_CALLS + bulk_api_calls
1490
-
1491
- first_elt = {
1492
- "name": "0",
1493
- "type": "something",
1494
- "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
1495
- }
1496
- second_elt = {
1497
- "name": "1",
1498
- "type": "something",
1499
- "polygon": [[4, 4], [5, 5], [5, 4], [4, 5]],
1500
- }
1501
- empty_payload = {
1502
- "elements": [],
1503
- "worker_run_id": "56785678-5678-5678-5678-567856785678",
1504
- }
1505
-
1506
- bodies = []
1507
- first_call_idx = None
1508
- if batch_size > 1:
1509
- first_call_idx = -1
1510
- bodies.append({**empty_payload, "elements": [first_elt, second_elt]})
1511
- else:
1512
- first_call_idx = -2
1513
- bodies.append({**empty_payload, "elements": [first_elt]})
1514
- bodies.append({**empty_payload, "elements": [second_elt]})
1515
-
1516
- assert [
1517
- json.loads(bulk_call.request.body)
1518
- for bulk_call in responses.calls[first_call_idx:]
1519
- ] == bodies
1520
-
1521
- assert created_ids == [
1522
- {"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"},
1523
- {"id": "5468c358-b9c4-499d-8b92-d6349c58e88d"},
1524
- ]
1525
-
1526
- # Check that created elements were properly stored in SQLite cache
1527
- assert (tmp_path / "db.sqlite").is_file()
1528
-
1529
- assert list(CachedElement.select()) == [
1530
- CachedElement(
1531
- id=UUID("497f6eca-6276-4993-bfeb-53cbbbba6f08"),
1532
- parent_id=UUID("12341234-1234-1234-1234-123412341234"),
1533
- type="something",
1534
- image_id="c0fec0fe-c0fe-c0fe-c0fe-c0fec0fec0fe",
1535
- polygon=[[1, 1], [2, 2], [2, 1], [1, 2]],
1536
- worker_run_id=UUID("56785678-5678-5678-5678-567856785678"),
1537
- confidence=None,
1538
- ),
1539
- CachedElement(
1540
- id=UUID("5468c358-b9c4-499d-8b92-d6349c58e88d"),
1541
- parent_id=UUID("12341234-1234-1234-1234-123412341234"),
1542
- type="something",
1543
- image_id="c0fec0fe-c0fe-c0fe-c0fe-c0fec0fec0fe",
1544
- polygon=[[4, 4], [5, 5], [5, 4], [4, 5]],
1545
- worker_run_id=UUID("56785678-5678-5678-5678-567856785678"),
1546
- confidence=None,
1547
- ),
1548
- ]
1549
-
1550
-
1551
- def test_create_elements_confidence(
1552
- responses, mock_elements_worker_with_cache, tmp_path
1553
- ):
1554
- elt = Element(
1555
- {
1556
- "id": "12341234-1234-1234-1234-123412341234",
1557
- "zone": {
1558
- "image": {
1559
- "id": "c0fec0fe-c0fe-c0fe-c0fe-c0fec0fec0fe",
1560
- "width": 42,
1561
- "height": 42,
1562
- "url": "http://aaaa",
1563
- }
1564
- },
1565
- }
1566
- )
1567
- responses.add(
1568
- responses.POST,
1569
- "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
1570
- status=200,
1571
- json=[{"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"}],
1572
- )
1573
-
1574
- created_ids = mock_elements_worker_with_cache.create_elements(
1575
- parent=elt,
1576
- elements=[
1577
- {
1578
- "name": "0",
1579
- "type": "something",
1580
- "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
1581
- "confidence": 0.42,
1582
- }
1583
- ],
1584
- )
1585
-
1586
- assert len(responses.calls) == len(BASE_API_CALLS) + 1
1587
- assert [
1588
- (call.request.method, call.request.url) for call in responses.calls
1589
- ] == BASE_API_CALLS + [
1590
- (
1591
- "POST",
1592
- "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
1593
- ),
1594
- ]
1595
- assert json.loads(responses.calls[-1].request.body) == {
1596
- "elements": [
1597
- {
1598
- "name": "0",
1599
- "type": "something",
1600
- "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
1601
- "confidence": 0.42,
1602
- }
1603
- ],
1604
- "worker_run_id": "56785678-5678-5678-5678-567856785678",
1605
- }
1606
- assert created_ids == [{"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"}]
1607
-
1608
- # Check that created elements were properly stored in SQLite cache
1609
- assert (tmp_path / "db.sqlite").is_file()
1610
-
1611
- assert list(CachedElement.select()) == [
1612
- CachedElement(
1613
- id=UUID("497f6eca-6276-4993-bfeb-53cbbbba6f08"),
1614
- parent_id=UUID("12341234-1234-1234-1234-123412341234"),
1615
- type="something",
1616
- image_id="c0fec0fe-c0fe-c0fe-c0fe-c0fec0fec0fe",
1617
- polygon=[[1, 1], [2, 2], [2, 1], [1, 2]],
1618
- worker_run_id=UUID("56785678-5678-5678-5678-567856785678"),
1619
- confidence=0.42,
1620
- )
1621
- ]
1622
-
1623
-
1624
- def test_create_elements_integrity_error(
1625
- responses, mock_elements_worker_with_cache, caplog
1626
- ):
1627
- elt = Element(
1628
- {
1629
- "id": "12341234-1234-1234-1234-123412341234",
1630
- "zone": {
1631
- "image": {
1632
- "id": "c0fec0fe-c0fe-c0fe-c0fe-c0fec0fec0fe",
1633
- "width": 42,
1634
- "height": 42,
1635
- "url": "http://aaaa",
1636
- }
1637
- },
1638
- }
1639
- )
1640
- responses.add(
1641
- responses.POST,
1642
- "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/",
1643
- status=200,
1644
- json=[
1645
- # Duplicate IDs, which will cause an IntegrityError when stored in the cache
1646
- {"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"},
1647
- {"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"},
1648
- ],
1649
- )
1650
-
1651
- elements = [
1652
- {
1653
- "name": "0",
1654
- "type": "something",
1655
- "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]],
1656
- },
1657
- {
1658
- "name": "1",
1659
- "type": "something",
1660
- "polygon": [[1, 1], [3, 3], [3, 1], [1, 3]],
1661
- },
1662
- ]
1663
-
1664
- created_ids = mock_elements_worker_with_cache.create_elements(
1665
- parent=elt,
1666
- elements=elements,
1667
- )
1668
-
1669
- assert created_ids == [
1670
- {"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"},
1671
- {"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"},
1672
- ]
1673
-
1674
- assert len(caplog.records) == 3
1675
- assert caplog.records[-1].levelname == "WARNING"
1676
- assert caplog.records[-1].message.startswith(
1677
- "Couldn't save created elements in local cache:"
1678
- )
1679
-
1680
- assert list(CachedElement.select()) == []
1681
-
1682
-
1683
- @pytest.mark.parametrize(
1684
- ("params", "error_message"),
1685
- [
1686
- (
1687
- {"parent": None, "child": None},
1688
- "parent shouldn't be null and should be of type Element",
1689
- ),
1690
- (
1691
- {"parent": "not an element", "child": None},
1692
- "parent shouldn't be null and should be of type Element",
1693
- ),
1694
- (
1695
- {"parent": Element(zone=None), "child": None},
1696
- "child shouldn't be null and should be of type Element",
1697
- ),
1698
- (
1699
- {"parent": Element(zone=None), "child": "not an element"},
1700
- "child shouldn't be null and should be of type Element",
1701
- ),
1702
- ],
1703
- )
1704
- def test_create_element_parent_invalid_params(
1705
- mock_elements_worker, params, error_message
1706
- ):
1707
- with pytest.raises(AssertionError, match=re.escape(error_message)):
1708
- mock_elements_worker.create_element_parent(**params)
1709
-
1710
-
1711
- def test_create_element_parent_api_error(responses, mock_elements_worker):
1712
- parent = Element({"id": "12341234-1234-1234-1234-123412341234"})
1713
- child = Element({"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"})
1714
- responses.add(
1715
- responses.POST,
1716
- "http://testserver/api/v1/element/497f6eca-6276-4993-bfeb-53cbbbba6f08/parent/12341234-1234-1234-1234-123412341234/",
1717
- status=418,
1718
- )
1719
-
1720
- with pytest.raises(ErrorResponse):
1721
- mock_elements_worker.create_element_parent(
1722
- parent=parent,
1723
- child=child,
1724
- )
1725
-
1726
- assert len(responses.calls) == len(BASE_API_CALLS) + 1
1727
- assert [
1728
- (call.request.method, call.request.url) for call in responses.calls
1729
- ] == BASE_API_CALLS + [
1730
- (
1731
- "POST",
1732
- "http://testserver/api/v1/element/497f6eca-6276-4993-bfeb-53cbbbba6f08/parent/12341234-1234-1234-1234-123412341234/",
1733
- )
1734
- ]
1735
-
1736
-
1737
- def test_create_element_parent(responses, mock_elements_worker):
1738
- parent = Element({"id": "12341234-1234-1234-1234-123412341234"})
1739
- child = Element({"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"})
1740
- responses.add(
1741
- responses.POST,
1742
- "http://testserver/api/v1/element/497f6eca-6276-4993-bfeb-53cbbbba6f08/parent/12341234-1234-1234-1234-123412341234/",
1743
- status=200,
1744
- json={
1745
- "parent": "12341234-1234-1234-1234-123412341234",
1746
- "child": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
1747
- },
1748
- )
1749
-
1750
- created_element_parent = mock_elements_worker.create_element_parent(
1751
- parent=parent,
1752
- child=child,
1753
- )
1754
-
1755
- assert len(responses.calls) == len(BASE_API_CALLS) + 1
1756
- assert [
1757
- (call.request.method, call.request.url) for call in responses.calls
1758
- ] == BASE_API_CALLS + [
1759
- (
1760
- "POST",
1761
- "http://testserver/api/v1/element/497f6eca-6276-4993-bfeb-53cbbbba6f08/parent/12341234-1234-1234-1234-123412341234/",
1762
- ),
1763
- ]
1764
- assert created_element_parent == {
1765
- "parent": "12341234-1234-1234-1234-123412341234",
1766
- "child": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
1767
- }
1768
-
1769
-
1770
- @pytest.mark.parametrize(
1771
- ("arg_name", "data", "error_message"),
1772
- [
1773
- (
1774
- "parent",
1775
- None,
1776
- "parent shouldn't be null and should be of type Element",
1777
- ),
1778
- (
1779
- "parent",
1780
- "not element type",
1781
- "parent shouldn't be null and should be of type Element",
1782
- ),
1783
- (
1784
- "children",
1785
- None,
1786
- "children shouldn't be null and should be of type list",
1787
- ),
1788
- (
1789
- "children",
1790
- "not a list",
1791
- "children shouldn't be null and should be of type list",
1792
- ),
1793
- (
1794
- "children",
1795
- [
1796
- Element({"id": "11111111-1111-1111-1111-111111111111"}),
1797
- "not element type",
1798
- ],
1799
- "Child at index 1 in children: Should be of type Element",
1800
- ),
1801
- ],
1802
- )
1803
- def test_create_element_children_wrong_params(
1804
- arg_name, data, error_message, mock_elements_worker
1805
- ):
1806
- with pytest.raises(AssertionError, match=error_message):
1807
- mock_elements_worker.create_element_children(
1808
- **{
1809
- "parent": Element({"id": "12341234-1234-1234-1234-123412341234"}),
1810
- "children": [
1811
- Element({"id": "11111111-1111-1111-1111-111111111111"}),
1812
- Element({"id": "22222222-2222-2222-2222-222222222222"}),
1813
- ],
1814
- # Overwrite with wrong data
1815
- arg_name: data,
1816
- },
1817
- )
1818
-
1819
-
1820
- def test_create_element_children_api_error(responses, mock_elements_worker):
1821
- parent = Element({"id": "12341234-1234-1234-1234-123412341234"})
1822
- responses.add(
1823
- responses.POST,
1824
- f"http://testserver/api/v1/element/parent/{parent.id}/",
1825
- status=418,
1826
- )
1827
-
1828
- with pytest.raises(ErrorResponse):
1829
- mock_elements_worker.create_element_children(
1830
- parent=parent,
1831
- children=[
1832
- Element({"id": "11111111-1111-1111-1111-111111111111"}),
1833
- Element({"id": "22222222-2222-2222-2222-222222222222"}),
1834
- ],
1835
- )
1836
-
1837
- assert len(responses.calls) == len(BASE_API_CALLS) + 1
1838
- assert [
1839
- (call.request.method, call.request.url) for call in responses.calls
1840
- ] == BASE_API_CALLS + [
1841
- (
1842
- "POST",
1843
- f"http://testserver/api/v1/element/parent/{parent.id}/",
1844
- )
1845
- ]
1846
-
1847
-
1848
- @pytest.mark.parametrize("batch_size", [DEFAULT_BATCH_SIZE, 1])
1849
- def test_create_element_children(batch_size, responses, mock_elements_worker):
1850
- parent = Element({"id": "12341234-1234-1234-1234-123412341234"})
1851
-
1852
- first_child = Element({"id": "11111111-1111-1111-1111-111111111111"})
1853
- second_child = Element({"id": "22222222-2222-2222-2222-222222222222"})
1854
-
1855
- responses.add(
1856
- responses.POST,
1857
- f"http://testserver/api/v1/element/parent/{parent.id}/",
1858
- status=200,
1859
- json={"children": []},
1860
- )
1861
-
1862
- mock_elements_worker.create_element_children(
1863
- parent=parent,
1864
- children=[first_child, second_child],
1865
- batch_size=batch_size,
1866
- )
1867
-
1868
- bulk_api_calls = [
1869
- (
1870
- "POST",
1871
- f"http://testserver/api/v1/element/parent/{parent.id}/",
1872
- )
1873
- ]
1874
- if batch_size != DEFAULT_BATCH_SIZE:
1875
- bulk_api_calls.append(
1876
- (
1877
- "POST",
1878
- f"http://testserver/api/v1/element/parent/{parent.id}/",
1879
- )
1880
- )
1881
-
1882
- assert len(responses.calls) == len(BASE_API_CALLS) + len(bulk_api_calls)
1883
- assert [
1884
- (call.request.method, call.request.url) for call in responses.calls
1885
- ] == BASE_API_CALLS + bulk_api_calls
1886
-
1887
- bodies = []
1888
- first_call_idx = None
1889
- if batch_size > 1:
1890
- first_call_idx = -1
1891
- bodies.append({"children": [first_child.id, second_child.id]})
1892
- else:
1893
- first_call_idx = -2
1894
- bodies.append({"children": [first_child.id]})
1895
- bodies.append({"children": [second_child.id]})
1896
-
1897
- assert [
1898
- json.loads(bulk_call.request.body)
1899
- for bulk_call in responses.calls[first_call_idx:]
1900
- ] == bodies
1901
-
1902
-
1903
- @pytest.mark.parametrize(
1904
- ("payload", "error"),
1905
- [
1906
- # Element
1907
- (
1908
- {"element": None},
1909
- "element shouldn't be null and should be an Element or CachedElement",
1910
- ),
1911
- (
1912
- {"element": "not element type"},
1913
- "element shouldn't be null and should be an Element or CachedElement",
1914
- ),
1915
- ],
1916
- )
1917
- def test_partial_update_element_wrong_param_element(
1918
- mock_elements_worker, payload, error
1919
- ):
1920
- api_payload = {
1921
- "element": Element({"zone": None}),
1922
- **payload,
1923
- }
1924
-
1925
- with pytest.raises(AssertionError, match=error):
1926
- mock_elements_worker.partial_update_element(
1927
- **api_payload,
1928
- )
1929
-
1930
-
1931
- @pytest.mark.parametrize(
1932
- ("payload", "error"),
1933
- [
1934
- # Type
1935
- ({"type": 1234}, "type should be a str"),
1936
- ({"type": None}, "type should be a str"),
1937
- ],
1938
- )
1939
- def test_partial_update_element_wrong_param_type(mock_elements_worker, payload, error):
1940
- api_payload = {
1941
- "element": Element({"zone": None}),
1942
- **payload,
1943
- }
1944
-
1945
- with pytest.raises(AssertionError, match=error):
1946
- mock_elements_worker.partial_update_element(
1947
- **api_payload,
1948
- )
1949
-
1950
-
1951
- @pytest.mark.parametrize(
1952
- ("payload", "error"),
1953
- [
1954
- # Name
1955
- ({"name": 1234}, "name should be a str"),
1956
- ({"name": None}, "name should be a str"),
1957
- ],
1958
- )
1959
- def test_partial_update_element_wrong_param_name(mock_elements_worker, payload, error):
1960
- api_payload = {
1961
- "element": Element({"zone": None}),
1962
- **payload,
1963
- }
1964
-
1965
- with pytest.raises(AssertionError, match=error):
1966
- mock_elements_worker.partial_update_element(
1967
- **api_payload,
1968
- )
1969
-
1970
-
1971
- @pytest.mark.parametrize(
1972
- ("payload", "error"),
1973
- [
1974
- # Polygon
1975
- ({"polygon": "not a polygon"}, "polygon should be a list"),
1976
- ({"polygon": None}, "polygon should be a list"),
1977
- ({"polygon": [[1, 1], [2, 2]]}, "polygon should have at least three points"),
1978
- (
1979
- {"polygon": [[1, 1, 1], [2, 2, 1], [2, 1, 1], [1, 2, 1]]},
1980
- "polygon points should be lists of two items",
1981
- ),
1982
- (
1983
- {"polygon": [[1], [2], [2], [1]]},
1984
- "polygon points should be lists of two items",
1985
- ),
1986
- (
1987
- {"polygon": [["not a coord", 1], [2, 2], [2, 1], [1, 2]]},
1988
- "polygon points should be lists of two numbers",
1989
- ),
1990
- ],
1991
- )
1992
- def test_partial_update_element_wrong_param_polygon(
1993
- mock_elements_worker, payload, error
1994
- ):
1995
- api_payload = {
1996
- "element": Element({"zone": None}),
1997
- **payload,
1998
- }
1999
-
2000
- with pytest.raises(AssertionError, match=error):
2001
- mock_elements_worker.partial_update_element(
2002
- **api_payload,
2003
- )
2004
-
2005
-
2006
- @pytest.mark.parametrize(
2007
- ("payload", "error"),
2008
- [
2009
- # Confidence
2010
- ({"confidence": "lol"}, "confidence should be None or a float in [0..1] range"),
2011
- ({"confidence": "0.2"}, "confidence should be None or a float in [0..1] range"),
2012
- ({"confidence": -1.0}, "confidence should be None or a float in [0..1] range"),
2013
- ({"confidence": 1.42}, "confidence should be None or a float in [0..1] range"),
2014
- (
2015
- {"confidence": float("inf")},
2016
- "confidence should be None or a float in [0..1] range",
2017
- ),
2018
- ],
2019
- )
2020
- def test_partial_update_element_wrong_param_conf(mock_elements_worker, payload, error):
2021
- api_payload = {
2022
- "element": Element({"zone": None}),
2023
- **payload,
2024
- }
2025
-
2026
- with pytest.raises(AssertionError, match=re.escape(error)):
2027
- mock_elements_worker.partial_update_element(
2028
- **api_payload,
2029
- )
2030
-
2031
-
2032
- @pytest.mark.parametrize(
2033
- ("payload", "error"),
2034
- [
2035
- # Rotation angle
2036
- ({"rotation_angle": "lol"}, "rotation_angle should be a positive integer"),
2037
- ({"rotation_angle": -1}, "rotation_angle should be a positive integer"),
2038
- ({"rotation_angle": 0.5}, "rotation_angle should be a positive integer"),
2039
- ({"rotation_angle": None}, "rotation_angle should be a positive integer"),
2040
- ],
2041
- )
2042
- def test_partial_update_element_wrong_param_rota(mock_elements_worker, payload, error):
2043
- api_payload = {
2044
- "element": Element({"zone": None}),
2045
- **payload,
2046
- }
2047
-
2048
- with pytest.raises(AssertionError, match=error):
2049
- mock_elements_worker.partial_update_element(
2050
- **api_payload,
2051
- )
2052
-
2053
-
2054
- @pytest.mark.parametrize(
2055
- ("payload", "error"),
2056
- [
2057
- # Mirrored
2058
- ({"mirrored": "lol"}, "mirrored should be a boolean"),
2059
- ({"mirrored": 1234}, "mirrored should be a boolean"),
2060
- ({"mirrored": None}, "mirrored should be a boolean"),
2061
- ],
2062
- )
2063
- def test_partial_update_element_wrong_param_mir(mock_elements_worker, payload, error):
2064
- api_payload = {
2065
- "element": Element({"zone": None}),
2066
- **payload,
2067
- }
2068
-
2069
- with pytest.raises(AssertionError, match=error):
2070
- mock_elements_worker.partial_update_element(
2071
- **api_payload,
2072
- )
2073
-
2074
-
2075
- @pytest.mark.parametrize(
2076
- ("payload", "error"),
2077
- [
2078
- # Image
2079
- ({"image": "lol"}, "image should be a UUID"),
2080
- ({"image": 1234}, "image should be a UUID"),
2081
- ({"image": None}, "image should be a UUID"),
2082
- ],
2083
- )
2084
- def test_partial_update_element_wrong_param_image(mock_elements_worker, payload, error):
2085
- api_payload = {
2086
- "element": Element({"zone": None}),
2087
- **payload,
2088
- }
2089
-
2090
- with pytest.raises(AssertionError, match=error):
2091
- mock_elements_worker.partial_update_element(
2092
- **api_payload,
2093
- )
2094
-
2095
-
2096
- def test_partial_update_element_api_error(responses, mock_elements_worker):
2097
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
2098
- responses.add(
2099
- responses.PATCH,
2100
- f"http://testserver/api/v1/element/{elt.id}/",
2101
- status=418,
2102
- )
2103
-
2104
- with pytest.raises(ErrorResponse):
2105
- mock_elements_worker.partial_update_element(
2106
- element=elt,
2107
- type="something",
2108
- name="0",
2109
- polygon=[[1, 1], [2, 2], [2, 1], [1, 2]],
2110
- )
2111
-
2112
- assert len(responses.calls) == len(BASE_API_CALLS) + 1
2113
- assert [
2114
- (call.request.method, call.request.url) for call in responses.calls
2115
- ] == BASE_API_CALLS + [("PATCH", f"http://testserver/api/v1/element/{elt.id}/")]
2116
-
2117
-
2118
- @pytest.mark.usefixtures("_mock_cached_elements", "_mock_cached_images")
2119
- @pytest.mark.parametrize(
2120
- "payload",
2121
- [
2122
- (
2123
- {
2124
- "polygon": [[10, 10], [20, 20], [20, 10], [10, 20]],
2125
- "confidence": None,
2126
- }
2127
- ),
2128
- (
2129
- {
2130
- "rotation_angle": 45,
2131
- "mirrored": False,
2132
- }
2133
- ),
2134
- (
2135
- {
2136
- "polygon": [[10, 10], [20, 20], [20, 10], [10, 20]],
2137
- "confidence": None,
2138
- "rotation_angle": 45,
2139
- "mirrored": False,
2140
- }
2141
- ),
2142
- ],
2143
- )
2144
- def test_partial_update_element(responses, mock_elements_worker_with_cache, payload):
2145
- elt = CachedElement.select().first()
2146
- new_image = CachedImage.select().first()
2147
-
2148
- elt_response = {
2149
- "image": str(new_image.id),
2150
- **payload,
2151
- }
2152
- responses.add(
2153
- responses.PATCH,
2154
- f"http://testserver/api/v1/element/{elt.id}/",
2155
- status=200,
2156
- # UUID not allowed in JSON
2157
- json=elt_response,
2158
- )
2159
-
2160
- element_update_response = mock_elements_worker_with_cache.partial_update_element(
2161
- element=elt,
2162
- **{**elt_response, "image": new_image.id},
2163
- )
2164
-
2165
- assert len(responses.calls) == len(BASE_API_CALLS) + 1
2166
- assert [
2167
- (call.request.method, call.request.url) for call in responses.calls
2168
- ] == BASE_API_CALLS + [
2169
- (
2170
- "PATCH",
2171
- f"http://testserver/api/v1/element/{elt.id}/",
2172
- ),
2173
- ]
2174
- assert json.loads(responses.calls[-1].request.body) == elt_response
2175
- assert element_update_response == elt_response
2176
-
2177
- cached_element = CachedElement.get(CachedElement.id == elt.id)
2178
- # Always present in payload
2179
- assert str(cached_element.image_id) == elt_response["image"]
2180
- # Optional params
2181
- if "polygon" in payload:
2182
- # Cast to string as this is the only difference compared to model
2183
- elt_response["polygon"] = str(elt_response["polygon"])
2184
-
2185
- for param in payload:
2186
- assert getattr(cached_element, param) == elt_response[param]
2187
-
2188
-
2189
- @pytest.mark.usefixtures("_mock_cached_elements")
2190
- @pytest.mark.parametrize("confidence", [None, 0.42])
2191
- def test_partial_update_element_confidence(
2192
- responses, mock_elements_worker_with_cache, confidence
2193
- ):
2194
- elt = CachedElement.select().first()
2195
- elt_response = {
2196
- "polygon": [[10, 10], [20, 20], [20, 10], [10, 20]],
2197
- "confidence": confidence,
2198
- }
2199
- responses.add(
2200
- responses.PATCH,
2201
- f"http://testserver/api/v1/element/{elt.id}/",
2202
- status=200,
2203
- json=elt_response,
2204
- )
2205
-
2206
- element_update_response = mock_elements_worker_with_cache.partial_update_element(
2207
- element=elt,
2208
- **elt_response,
2209
- )
2210
-
2211
- assert len(responses.calls) == len(BASE_API_CALLS) + 1
2212
- assert [
2213
- (call.request.method, call.request.url) for call in responses.calls
2214
- ] == BASE_API_CALLS + [
2215
- (
2216
- "PATCH",
2217
- f"http://testserver/api/v1/element/{elt.id}/",
2218
- ),
2219
- ]
2220
- assert json.loads(responses.calls[-1].request.body) == elt_response
2221
- assert element_update_response == elt_response
2222
-
2223
- cached_element = CachedElement.get(CachedElement.id == elt.id)
2224
- assert cached_element.polygon == str(elt_response["polygon"])
2225
- assert cached_element.confidence == confidence
2226
-
2227
-
2228
- def test_list_elements_wrong_folder(mock_elements_worker):
2229
- with pytest.raises(AssertionError, match="folder should be of type bool"):
2230
- mock_elements_worker.list_elements(folder="not bool")
2231
-
2232
-
2233
- def test_list_elements_wrong_name(mock_elements_worker):
2234
- with pytest.raises(AssertionError, match="name should be of type str"):
2235
- mock_elements_worker.list_elements(name=1234)
2236
-
2237
-
2238
- def test_list_elements_wrong_top_level(mock_elements_worker):
2239
- with pytest.raises(AssertionError, match="top_level should be of type bool"):
2240
- mock_elements_worker.list_elements(top_level="not bool")
2241
-
2242
-
2243
- def test_list_elements_wrong_type(mock_elements_worker):
2244
- with pytest.raises(AssertionError, match="type should be of type str"):
2245
- mock_elements_worker.list_elements(type=1234)
2246
-
2247
-
2248
- def test_list_elements_wrong_with_classes(mock_elements_worker):
2249
- with pytest.raises(AssertionError, match="with_classes should be of type bool"):
2250
- mock_elements_worker.list_elements(with_classes="not bool")
2251
-
2252
-
2253
- def test_list_elements_wrong_with_corpus(mock_elements_worker):
2254
- with pytest.raises(AssertionError, match="with_corpus should be of type bool"):
2255
- mock_elements_worker.list_elements(with_corpus="not bool")
2256
-
2257
-
2258
- def test_list_elements_wrong_with_has_children(mock_elements_worker):
2259
- with pytest.raises(
2260
- AssertionError, match="with_has_children should be of type bool"
2261
- ):
2262
- mock_elements_worker.list_elements(with_has_children="not bool")
2263
-
2264
-
2265
- def test_list_elements_wrong_with_zone(mock_elements_worker):
2266
- with pytest.raises(AssertionError, match="with_zone should be of type bool"):
2267
- mock_elements_worker.list_elements(with_zone="not bool")
2268
-
2269
-
2270
- def test_list_elements_wrong_with_metadata(mock_elements_worker):
2271
- with pytest.raises(AssertionError, match="with_metadata should be of type bool"):
2272
- mock_elements_worker.list_elements(with_metadata="not bool")
2273
-
2274
-
2275
- @pytest.mark.parametrize(
2276
- ("param", "value"),
2277
- [
2278
- ("worker_run", 1234),
2279
- ("transcription_worker_run", 1234),
2280
- ],
2281
- )
2282
- def test_list_elements_wrong_worker_run(mock_elements_worker, param, value):
2283
- with pytest.raises(AssertionError, match=f"{param} should be of type str or bool"):
2284
- mock_elements_worker.list_elements(**{param: value})
2285
-
2286
-
2287
- @pytest.mark.parametrize(
2288
- ("param", "alternative", "value"),
2289
- [
2290
- ("worker_version", "worker_run", 1234),
2291
- ("transcription_worker_version", "transcription_worker_run", 1234),
2292
- ],
2293
- )
2294
- def test_list_elements_wrong_worker_version(
2295
- mock_elements_worker, param, alternative, value
2296
- ):
2297
- # WARNING: pytest.deprecated_call must be placed BEFORE pytest.raises, otherwise `match` argument won't be checked
2298
- with (
2299
- pytest.deprecated_call(
2300
- match=f"`{param}` usage is deprecated. Consider using `{alternative}` instead."
2301
- ),
2302
- pytest.raises(AssertionError, match=f"{param} should be of type str or bool"),
2303
- ):
2304
- mock_elements_worker.list_elements(**{param: value})
2305
-
2306
-
2307
- @pytest.mark.parametrize(
2308
- "param",
2309
- [
2310
- "worker_run",
2311
- "transcription_worker_run",
2312
- ],
2313
- )
2314
- def test_list_elements_wrong_bool_worker_run(mock_elements_worker, param):
2315
- with pytest.raises(
2316
- AssertionError, match=f"if of type bool, {param} can only be set to False"
2317
- ):
2318
- mock_elements_worker.list_elements(**{param: True})
2319
-
2320
-
2321
- @pytest.mark.parametrize(
2322
- ("param", "alternative"),
2323
- [
2324
- ("worker_version", "worker_run"),
2325
- ("transcription_worker_version", "transcription_worker_run"),
2326
- ],
2327
- )
2328
- def test_list_elements_wrong_bool_worker_version(
2329
- mock_elements_worker, param, alternative
2330
- ):
2331
- # WARNING: pytest.deprecated_call must be placed BEFORE pytest.raises, otherwise `match` argument won't be checked
2332
- with (
2333
- pytest.deprecated_call(
2334
- match=f"`{param}` usage is deprecated. Consider using `{alternative}` instead."
2335
- ),
2336
- pytest.raises(
2337
- AssertionError, match=f"if of type bool, {param} can only be set to False"
2338
- ),
2339
- ):
2340
- mock_elements_worker.list_elements(**{param: True})
2341
-
2342
-
2343
- def test_list_elements_api_error(responses, mock_elements_worker):
2344
- responses.add(
2345
- responses.GET,
2346
- f"http://testserver/api/v1/corpus/{mock_elements_worker.corpus_id}/elements/",
2347
- status=418,
2348
- )
2349
-
2350
- with pytest.raises(
2351
- Exception, match="Stopping pagination as data will be incomplete"
2352
- ):
2353
- next(mock_elements_worker.list_elements())
2354
-
2355
- assert len(responses.calls) == len(BASE_API_CALLS) + 5
2356
- assert [
2357
- (call.request.method, call.request.url) for call in responses.calls
2358
- ] == BASE_API_CALLS + [
2359
- # We do 5 retries
2360
- (
2361
- "GET",
2362
- f"http://testserver/api/v1/corpus/{mock_elements_worker.corpus_id}/elements/",
2363
- ),
2364
- (
2365
- "GET",
2366
- f"http://testserver/api/v1/corpus/{mock_elements_worker.corpus_id}/elements/",
2367
- ),
2368
- (
2369
- "GET",
2370
- f"http://testserver/api/v1/corpus/{mock_elements_worker.corpus_id}/elements/",
2371
- ),
2372
- (
2373
- "GET",
2374
- f"http://testserver/api/v1/corpus/{mock_elements_worker.corpus_id}/elements/",
2375
- ),
2376
- (
2377
- "GET",
2378
- f"http://testserver/api/v1/corpus/{mock_elements_worker.corpus_id}/elements/",
2379
- ),
2380
- ]
2381
-
2382
-
2383
- def test_list_elements(responses, mock_elements_worker):
2384
- expected_children = [
2385
- {
2386
- "id": "0000",
2387
- "type": "page",
2388
- "name": "Test",
2389
- "corpus": {},
2390
- "thumbnail_url": None,
2391
- "zone": {},
2392
- "best_classes": None,
2393
- "has_children": None,
2394
- "worker_version_id": None,
2395
- "worker_run_id": None,
2396
- },
2397
- {
2398
- "id": "1111",
2399
- "type": "page",
2400
- "name": "Test 2",
2401
- "corpus": {},
2402
- "thumbnail_url": None,
2403
- "zone": {},
2404
- "best_classes": None,
2405
- "has_children": None,
2406
- "worker_version_id": None,
2407
- "worker_run_id": None,
2408
- },
2409
- {
2410
- "id": "2222",
2411
- "type": "page",
2412
- "name": "Test 3",
2413
- "corpus": {},
2414
- "thumbnail_url": None,
2415
- "zone": {},
2416
- "best_classes": None,
2417
- "has_children": None,
2418
- "worker_version_id": None,
2419
- "worker_run_id": None,
2420
- },
2421
- ]
2422
- responses.add(
2423
- responses.GET,
2424
- f"http://testserver/api/v1/corpus/{mock_elements_worker.corpus_id}/elements/",
2425
- status=200,
2426
- json={
2427
- "count": 3,
2428
- "next": None,
2429
- "results": expected_children,
2430
- },
2431
- )
2432
-
2433
- for idx, child in enumerate(mock_elements_worker.list_elements()):
2434
- assert child == expected_children[idx]
2435
-
2436
- assert len(responses.calls) == len(BASE_API_CALLS) + 1
2437
- assert [
2438
- (call.request.method, call.request.url) for call in responses.calls
2439
- ] == BASE_API_CALLS + [
2440
- (
2441
- "GET",
2442
- f"http://testserver/api/v1/corpus/{mock_elements_worker.corpus_id}/elements/",
2443
- ),
2444
- ]
2445
-
2446
-
2447
- def test_list_elements_manual_worker_version(responses, mock_elements_worker):
2448
- expected_children = [
2449
- {
2450
- "id": "0000",
2451
- "type": "page",
2452
- "name": "Test",
2453
- "corpus": {},
2454
- "thumbnail_url": None,
2455
- "zone": {},
2456
- "best_classes": None,
2457
- "has_children": None,
2458
- "worker_version_id": None,
2459
- "worker_run_id": None,
2460
- }
2461
- ]
2462
- responses.add(
2463
- responses.GET,
2464
- f"http://testserver/api/v1/corpus/{mock_elements_worker.corpus_id}/elements/?worker_version=False",
2465
- status=200,
2466
- json={
2467
- "count": 1,
2468
- "next": None,
2469
- "results": expected_children,
2470
- },
2471
- )
2472
-
2473
- with pytest.deprecated_call(
2474
- match="`worker_version` usage is deprecated. Consider using `worker_run` instead."
2475
- ):
2476
- for idx, child in enumerate(
2477
- mock_elements_worker.list_elements(worker_version=False)
2478
- ):
2479
- assert child == expected_children[idx]
2480
-
2481
- assert len(responses.calls) == len(BASE_API_CALLS) + 1
2482
- assert [
2483
- (call.request.method, call.request.url) for call in responses.calls
2484
- ] == BASE_API_CALLS + [
2485
- (
2486
- "GET",
2487
- f"http://testserver/api/v1/corpus/{mock_elements_worker.corpus_id}/elements/?worker_version=False",
2488
- ),
2489
- ]
2490
-
2491
-
2492
- def test_list_elements_manual_worker_run(responses, mock_elements_worker):
2493
- expected_children = [
2494
- {
2495
- "id": "0000",
2496
- "type": "page",
2497
- "name": "Test",
2498
- "corpus": {},
2499
- "thumbnail_url": None,
2500
- "zone": {},
2501
- "best_classes": None,
2502
- "has_children": None,
2503
- "worker_version_id": None,
2504
- "worker_run_id": None,
2505
- }
2506
- ]
2507
- responses.add(
2508
- responses.GET,
2509
- f"http://testserver/api/v1/corpus/{mock_elements_worker.corpus_id}/elements/?worker_run=False",
2510
- status=200,
2511
- json={
2512
- "count": 1,
2513
- "next": None,
2514
- "results": expected_children,
2515
- },
2516
- )
2517
-
2518
- for idx, child in enumerate(mock_elements_worker.list_elements(worker_run=False)):
2519
- assert child == expected_children[idx]
2520
-
2521
- assert len(responses.calls) == len(BASE_API_CALLS) + 1
2522
- assert [
2523
- (call.request.method, call.request.url) for call in responses.calls
2524
- ] == BASE_API_CALLS + [
2525
- (
2526
- "GET",
2527
- f"http://testserver/api/v1/corpus/{mock_elements_worker.corpus_id}/elements/?worker_run=False",
2528
- ),
2529
- ]
2530
-
2531
-
2532
- def test_list_elements_with_cache_unhandled_param(mock_elements_worker_with_cache):
2533
- with pytest.raises(
2534
- AssertionError,
2535
- match="When using the local cache, you can only filter by 'type' and/or 'worker_version' and/or 'worker_run'",
2536
- ):
2537
- mock_elements_worker_with_cache.list_elements(with_corpus=True)
2538
-
2539
-
2540
- @pytest.mark.usefixtures("_mock_cached_elements")
2541
- @pytest.mark.parametrize(
2542
- ("filters", "expected_ids"),
2543
- [
2544
- # Filter on element should give all elements inserted
2545
- (
2546
- {},
2547
- (
2548
- "99999999-9999-9999-9999-999999999999",
2549
- "12341234-1234-1234-1234-123412341234",
2550
- "11111111-1111-1111-1111-111111111111",
2551
- "22222222-2222-2222-2222-222222222222",
2552
- "33333333-3333-3333-3333-333333333333",
2553
- ),
2554
- ),
2555
- # Filter on element and page should give the second element
2556
- (
2557
- {"type": "page"},
2558
- ("22222222-2222-2222-2222-222222222222",),
2559
- ),
2560
- # Filter on element and worker run should give second
2561
- (
2562
- {
2563
- "worker_run": "56785678-5678-5678-5678-567856785678",
2564
- },
2565
- (
2566
- "12341234-1234-1234-1234-123412341234",
2567
- "22222222-2222-2222-2222-222222222222",
2568
- ),
2569
- ),
2570
- # Filter on element, manual worker run should give first and third
2571
- (
2572
- {"worker_run": False},
2573
- (
2574
- "99999999-9999-9999-9999-999999999999",
2575
- "11111111-1111-1111-1111-111111111111",
2576
- "33333333-3333-3333-3333-333333333333",
2577
- ),
2578
- ),
2579
- ],
2580
- )
2581
- def test_list_elements_with_cache(
2582
- responses, mock_elements_worker_with_cache, filters, expected_ids
2583
- ):
2584
- # Check we have 5 elements already present in database
2585
- assert CachedElement.select().count() == 5
2586
-
2587
- # Query database through cache
2588
- elements = mock_elements_worker_with_cache.list_elements(**filters)
2589
- assert elements.count() == len(expected_ids)
2590
- for child, expected_id in zip(elements.order_by("id"), expected_ids, strict=True):
2591
- assert child.id == UUID(expected_id)
2592
-
2593
- # Check the worker never hits the API for elements
2594
- assert len(responses.calls) == len(BASE_API_CALLS)
2595
- assert [
2596
- (call.request.method, call.request.url) for call in responses.calls
2597
- ] == BASE_API_CALLS
2598
-
2599
-
2600
- @pytest.mark.usefixtures("_mock_cached_elements")
2601
- @pytest.mark.parametrize(
2602
- ("filters", "expected_ids"),
2603
- [
2604
- # Filter on element and worker version
2605
- (
2606
- {
2607
- "worker_version": "56785678-5678-5678-5678-567856785678",
2608
- },
2609
- (
2610
- "12341234-1234-1234-1234-123412341234",
2611
- "11111111-1111-1111-1111-111111111111",
2612
- "22222222-2222-2222-2222-222222222222",
2613
- ),
2614
- ),
2615
- # Filter on element, type double_page and worker version
2616
- (
2617
- {"type": "page", "worker_version": "56785678-5678-5678-5678-567856785678"},
2618
- ("22222222-2222-2222-2222-222222222222",),
2619
- ),
2620
- # Filter on element, manual worker version
2621
- (
2622
- {"worker_version": False},
2623
- (
2624
- "99999999-9999-9999-9999-999999999999",
2625
- "33333333-3333-3333-3333-333333333333",
2626
- ),
2627
- ),
2628
- ],
2629
- )
2630
- def test_list_elements_with_cache_deprecation(
2631
- responses,
2632
- mock_elements_worker_with_cache,
2633
- filters,
2634
- expected_ids,
2635
- ):
2636
- # Check we have 5 elements already present in database
2637
- assert CachedElement.select().count() == 5
2638
-
2639
- with pytest.deprecated_call(
2640
- match="`worker_version` usage is deprecated. Consider using `worker_run` instead."
2641
- ):
2642
- # Query database through cache
2643
- elements = mock_elements_worker_with_cache.list_elements(**filters)
2644
- assert elements.count() == len(expected_ids)
2645
- for child, expected_id in zip(elements.order_by("id"), expected_ids, strict=True):
2646
- assert child.id == UUID(expected_id)
2647
-
2648
- # Check the worker never hits the API for elements
2649
- assert len(responses.calls) == len(BASE_API_CALLS)
2650
- assert [
2651
- (call.request.method, call.request.url) for call in responses.calls
2652
- ] == BASE_API_CALLS
2653
-
2654
-
2655
- def test_list_element_children_wrong_element(mock_elements_worker):
2656
- with pytest.raises(
2657
- AssertionError,
2658
- match="element shouldn't be null and should be an Element or CachedElement",
2659
- ):
2660
- mock_elements_worker.list_element_children(element=None)
2661
-
2662
- with pytest.raises(
2663
- AssertionError,
2664
- match="element shouldn't be null and should be an Element or CachedElement",
2665
- ):
2666
- mock_elements_worker.list_element_children(element="not element type")
2667
-
2668
-
2669
- def test_list_element_children_wrong_folder(mock_elements_worker):
2670
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
2671
-
2672
- with pytest.raises(AssertionError, match="folder should be of type bool"):
2673
- mock_elements_worker.list_element_children(
2674
- element=elt,
2675
- folder="not bool",
2676
- )
2677
-
2678
-
2679
- def test_list_element_children_wrong_name(mock_elements_worker):
2680
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
2681
-
2682
- with pytest.raises(AssertionError, match="name should be of type str"):
2683
- mock_elements_worker.list_element_children(
2684
- element=elt,
2685
- name=1234,
2686
- )
2687
-
2688
-
2689
- def test_list_element_children_wrong_recursive(mock_elements_worker):
2690
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
2691
-
2692
- with pytest.raises(AssertionError, match="recursive should be of type bool"):
2693
- mock_elements_worker.list_element_children(
2694
- element=elt,
2695
- recursive="not bool",
2696
- )
2697
-
2698
-
2699
- def test_list_element_children_wrong_type(mock_elements_worker):
2700
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
2701
-
2702
- with pytest.raises(AssertionError, match="type should be of type str"):
2703
- mock_elements_worker.list_element_children(
2704
- element=elt,
2705
- type=1234,
2706
- )
2707
-
2708
-
2709
- def test_list_element_children_wrong_with_classes(mock_elements_worker):
2710
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
2711
-
2712
- with pytest.raises(AssertionError, match="with_classes should be of type bool"):
2713
- mock_elements_worker.list_element_children(
2714
- element=elt,
2715
- with_classes="not bool",
2716
- )
2717
-
2718
-
2719
- def test_list_element_children_wrong_with_corpus(mock_elements_worker):
2720
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
2721
-
2722
- with pytest.raises(AssertionError, match="with_corpus should be of type bool"):
2723
- mock_elements_worker.list_element_children(
2724
- element=elt,
2725
- with_corpus="not bool",
2726
- )
2727
-
2728
-
2729
- def test_list_element_children_wrong_with_has_children(mock_elements_worker):
2730
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
2731
-
2732
- with pytest.raises(
2733
- AssertionError, match="with_has_children should be of type bool"
2734
- ):
2735
- mock_elements_worker.list_element_children(
2736
- element=elt,
2737
- with_has_children="not bool",
2738
- )
2739
-
2740
-
2741
- def test_list_element_children_wrong_with_zone(mock_elements_worker):
2742
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
2743
-
2744
- with pytest.raises(AssertionError, match="with_zone should be of type bool"):
2745
- mock_elements_worker.list_element_children(
2746
- element=elt,
2747
- with_zone="not bool",
2748
- )
2749
-
2750
-
2751
- def test_list_element_children_wrong_with_metadata(mock_elements_worker):
2752
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
2753
-
2754
- with pytest.raises(AssertionError, match="with_metadata should be of type bool"):
2755
- mock_elements_worker.list_element_children(
2756
- element=elt,
2757
- with_metadata="not bool",
2758
- )
2759
-
2760
-
2761
- @pytest.mark.parametrize(
2762
- ("param", "value"),
2763
- [
2764
- ("worker_run", 1234),
2765
- ("transcription_worker_run", 1234),
2766
- ],
2767
- )
2768
- def test_list_element_children_wrong_worker_run(mock_elements_worker, param, value):
2769
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
2770
-
2771
- with pytest.raises(AssertionError, match=f"{param} should be of type str or bool"):
2772
- mock_elements_worker.list_element_children(
2773
- element=elt,
2774
- **{param: value},
2775
- )
2776
-
2777
-
2778
- @pytest.mark.parametrize(
2779
- ("param", "alternative", "value"),
2780
- [
2781
- ("worker_version", "worker_run", 1234),
2782
- ("transcription_worker_version", "transcription_worker_run", 1234),
2783
- ],
2784
- )
2785
- def test_list_element_children_wrong_worker_version(
2786
- mock_elements_worker, param, alternative, value
2787
- ):
2788
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
2789
-
2790
- # WARNING: pytest.deprecated_call must be placed BEFORE pytest.raises, otherwise `match` argument won't be checked
2791
- with (
2792
- pytest.deprecated_call(
2793
- match=f"`{param}` usage is deprecated. Consider using `{alternative}` instead."
2794
- ),
2795
- pytest.raises(AssertionError, match=f"{param} should be of type str or bool"),
2796
- ):
2797
- mock_elements_worker.list_element_children(
2798
- element=elt,
2799
- **{param: value},
2800
- )
2801
-
2802
-
2803
- @pytest.mark.parametrize(
2804
- "param",
2805
- [
2806
- "worker_run",
2807
- "transcription_worker_run",
2808
- ],
2809
- )
2810
- def test_list_element_children_wrong_bool_worker_run(mock_elements_worker, param):
2811
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
2812
-
2813
- with pytest.raises(
2814
- AssertionError, match=f"if of type bool, {param} can only be set to False"
2815
- ):
2816
- mock_elements_worker.list_element_children(
2817
- element=elt,
2818
- **{param: True},
2819
- )
2820
-
2821
-
2822
- @pytest.mark.parametrize(
2823
- ("param", "alternative"),
2824
- [
2825
- ("worker_version", "worker_run"),
2826
- ("transcription_worker_version", "transcription_worker_run"),
2827
- ],
2828
- )
2829
- def test_list_element_children_wrong_bool_worker_version(
2830
- mock_elements_worker, param, alternative
2831
- ):
2832
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
2833
-
2834
- # WARNING: pytest.deprecated_call must be placed BEFORE pytest.raises, otherwise `match` argument won't be checked
2835
- with (
2836
- pytest.deprecated_call(
2837
- match=f"`{param}` usage is deprecated. Consider using `{alternative}` instead."
2838
- ),
2839
- pytest.raises(
2840
- AssertionError, match=f"if of type bool, {param} can only be set to False"
2841
- ),
2842
- ):
2843
- mock_elements_worker.list_element_children(
2844
- element=elt,
2845
- **{param: True},
2846
- )
2847
-
2848
-
2849
- def test_list_element_children_api_error(responses, mock_elements_worker):
2850
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
2851
- responses.add(
2852
- responses.GET,
2853
- "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/children/",
2854
- status=418,
2855
- )
2856
-
2857
- with pytest.raises(
2858
- Exception, match="Stopping pagination as data will be incomplete"
2859
- ):
2860
- next(mock_elements_worker.list_element_children(element=elt))
2861
-
2862
- assert len(responses.calls) == len(BASE_API_CALLS) + 5
2863
- assert [
2864
- (call.request.method, call.request.url) for call in responses.calls
2865
- ] == BASE_API_CALLS + [
2866
- # We do 5 retries
2867
- (
2868
- "GET",
2869
- "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/children/",
2870
- ),
2871
- (
2872
- "GET",
2873
- "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/children/",
2874
- ),
2875
- (
2876
- "GET",
2877
- "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/children/",
2878
- ),
2879
- (
2880
- "GET",
2881
- "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/children/",
2882
- ),
2883
- (
2884
- "GET",
2885
- "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/children/",
2886
- ),
2887
- ]
2888
-
2889
-
2890
- def test_list_element_children(responses, mock_elements_worker):
2891
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
2892
- expected_children = [
2893
- {
2894
- "id": "0000",
2895
- "type": "page",
2896
- "name": "Test",
2897
- "corpus": {},
2898
- "thumbnail_url": None,
2899
- "zone": {},
2900
- "best_classes": None,
2901
- "has_children": None,
2902
- "worker_version_id": None,
2903
- "worker_run_id": None,
2904
- },
2905
- {
2906
- "id": "1111",
2907
- "type": "page",
2908
- "name": "Test 2",
2909
- "corpus": {},
2910
- "thumbnail_url": None,
2911
- "zone": {},
2912
- "best_classes": None,
2913
- "has_children": None,
2914
- "worker_version_id": None,
2915
- "worker_run_id": None,
2916
- },
2917
- {
2918
- "id": "2222",
2919
- "type": "page",
2920
- "name": "Test 3",
2921
- "corpus": {},
2922
- "thumbnail_url": None,
2923
- "zone": {},
2924
- "best_classes": None,
2925
- "has_children": None,
2926
- "worker_version_id": None,
2927
- "worker_run_id": None,
2928
- },
2929
- ]
2930
- responses.add(
2931
- responses.GET,
2932
- "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/children/",
2933
- status=200,
2934
- json={
2935
- "count": 3,
2936
- "next": None,
2937
- "results": expected_children,
2938
- },
2939
- )
2940
-
2941
- for idx, child in enumerate(
2942
- mock_elements_worker.list_element_children(element=elt)
2943
- ):
2944
- assert child == expected_children[idx]
2945
-
2946
- assert len(responses.calls) == len(BASE_API_CALLS) + 1
2947
- assert [
2948
- (call.request.method, call.request.url) for call in responses.calls
2949
- ] == BASE_API_CALLS + [
2950
- (
2951
- "GET",
2952
- "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/children/",
2953
- ),
2954
- ]
2955
-
2956
-
2957
- def test_list_element_children_manual_worker_version(responses, mock_elements_worker):
2958
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
2959
- expected_children = [
2960
- {
2961
- "id": "0000",
2962
- "type": "page",
2963
- "name": "Test",
2964
- "corpus": {},
2965
- "thumbnail_url": None,
2966
- "zone": {},
2967
- "best_classes": None,
2968
- "has_children": None,
2969
- "worker_version_id": None,
2970
- "worker_run_id": None,
2971
- }
2972
- ]
2973
- responses.add(
2974
- responses.GET,
2975
- "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/children/?worker_version=False",
2976
- status=200,
2977
- json={
2978
- "count": 1,
2979
- "next": None,
2980
- "results": expected_children,
2981
- },
2982
- )
2983
-
2984
- with pytest.deprecated_call(
2985
- match="`worker_version` usage is deprecated. Consider using `worker_run` instead."
2986
- ):
2987
- for idx, child in enumerate(
2988
- mock_elements_worker.list_element_children(
2989
- element=elt, worker_version=False
2990
- )
2991
- ):
2992
- assert child == expected_children[idx]
2993
-
2994
- assert len(responses.calls) == len(BASE_API_CALLS) + 1
2995
- assert [
2996
- (call.request.method, call.request.url) for call in responses.calls
2997
- ] == BASE_API_CALLS + [
2998
- (
2999
- "GET",
3000
- "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/children/?worker_version=False",
3001
- ),
3002
- ]
3003
-
3004
-
3005
- def test_list_element_children_manual_worker_run(responses, mock_elements_worker):
3006
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
3007
- expected_children = [
3008
- {
3009
- "id": "0000",
3010
- "type": "page",
3011
- "name": "Test",
3012
- "corpus": {},
3013
- "thumbnail_url": None,
3014
- "zone": {},
3015
- "best_classes": None,
3016
- "has_children": None,
3017
- "worker_version_id": None,
3018
- "worker_run_id": None,
3019
- }
3020
- ]
3021
- responses.add(
3022
- responses.GET,
3023
- "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/children/?worker_run=False",
3024
- status=200,
3025
- json={
3026
- "count": 1,
3027
- "next": None,
3028
- "results": expected_children,
3029
- },
3030
- )
3031
-
3032
- for idx, child in enumerate(
3033
- mock_elements_worker.list_element_children(element=elt, worker_run=False)
3034
- ):
3035
- assert child == expected_children[idx]
3036
-
3037
- assert len(responses.calls) == len(BASE_API_CALLS) + 1
3038
- assert [
3039
- (call.request.method, call.request.url) for call in responses.calls
3040
- ] == BASE_API_CALLS + [
3041
- (
3042
- "GET",
3043
- "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/children/?worker_run=False",
3044
- ),
3045
- ]
3046
-
3047
-
3048
- def test_list_element_children_with_cache_unhandled_param(
3049
- mock_elements_worker_with_cache,
3050
- ):
3051
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
3052
-
3053
- with pytest.raises(
3054
- AssertionError,
3055
- match="When using the local cache, you can only filter by 'type' and/or 'worker_version' and/or 'worker_run'",
3056
- ):
3057
- mock_elements_worker_with_cache.list_element_children(
3058
- element=elt, with_corpus=True
3059
- )
3060
-
3061
-
3062
- @pytest.mark.usefixtures("_mock_cached_elements")
3063
- @pytest.mark.parametrize(
3064
- ("filters", "expected_ids"),
3065
- [
3066
- # Filter on element should give all elements inserted
3067
- (
3068
- {
3069
- "element": CachedElement(id="12341234-1234-1234-1234-123412341234"),
3070
- },
3071
- (
3072
- "11111111-1111-1111-1111-111111111111",
3073
- "22222222-2222-2222-2222-222222222222",
3074
- "33333333-3333-3333-3333-333333333333",
3075
- ),
3076
- ),
3077
- # Filter on element and page should give the second element
3078
- (
3079
- {
3080
- "element": CachedElement(id="12341234-1234-1234-1234-123412341234"),
3081
- "type": "page",
3082
- },
3083
- ("22222222-2222-2222-2222-222222222222",),
3084
- ),
3085
- # Filter on element and worker run should give second
3086
- (
3087
- {
3088
- "element": CachedElement(id="12341234-1234-1234-1234-123412341234"),
3089
- "worker_run": "56785678-5678-5678-5678-567856785678",
3090
- },
3091
- ("22222222-2222-2222-2222-222222222222",),
3092
- ),
3093
- # Filter on element, manual worker run should give first and third
3094
- (
3095
- {
3096
- "element": CachedElement(id="12341234-1234-1234-1234-123412341234"),
3097
- "worker_run": False,
3098
- },
3099
- (
3100
- "11111111-1111-1111-1111-111111111111",
3101
- "33333333-3333-3333-3333-333333333333",
3102
- ),
3103
- ),
3104
- ],
3105
- )
3106
- def test_list_element_children_with_cache(
3107
- responses,
3108
- mock_elements_worker_with_cache,
3109
- filters,
3110
- expected_ids,
3111
- ):
3112
- # Check we have 5 elements already present in database
3113
- assert CachedElement.select().count() == 5
3114
-
3115
- # Query database through cache
3116
- elements = mock_elements_worker_with_cache.list_element_children(**filters)
3117
- assert elements.count() == len(expected_ids)
3118
- for child, expected_id in zip(elements.order_by("id"), expected_ids, strict=True):
3119
- assert child.id == UUID(expected_id)
3120
-
3121
- # Check the worker never hits the API for elements
3122
- assert len(responses.calls) == len(BASE_API_CALLS)
3123
- assert [
3124
- (call.request.method, call.request.url) for call in responses.calls
3125
- ] == BASE_API_CALLS
3126
-
3127
-
3128
- @pytest.mark.usefixtures("_mock_cached_elements")
3129
- @pytest.mark.parametrize(
3130
- ("filters", "expected_ids"),
3131
- [
3132
- # Filter on element and worker version
3133
- (
3134
- {
3135
- "element": CachedElement(id="12341234-1234-1234-1234-123412341234"),
3136
- "worker_version": "56785678-5678-5678-5678-567856785678",
3137
- },
3138
- (
3139
- "11111111-1111-1111-1111-111111111111",
3140
- "22222222-2222-2222-2222-222222222222",
3141
- ),
3142
- ),
3143
- # Filter on element, type double_page and worker version
3144
- (
3145
- {
3146
- "element": CachedElement(id="12341234-1234-1234-1234-123412341234"),
3147
- "type": "page",
3148
- "worker_version": "56785678-5678-5678-5678-567856785678",
3149
- },
3150
- ("22222222-2222-2222-2222-222222222222",),
3151
- ),
3152
- # Filter on element, manual worker version
3153
- (
3154
- {
3155
- "element": CachedElement(id="12341234-1234-1234-1234-123412341234"),
3156
- "worker_version": False,
3157
- },
3158
- ("33333333-3333-3333-3333-333333333333",),
3159
- ),
3160
- ],
3161
- )
3162
- def test_list_element_children_with_cache_deprecation(
3163
- responses,
3164
- mock_elements_worker_with_cache,
3165
- filters,
3166
- expected_ids,
3167
- ):
3168
- # Check we have 5 elements already present in database
3169
- assert CachedElement.select().count() == 5
3170
-
3171
- with pytest.deprecated_call(
3172
- match="`worker_version` usage is deprecated. Consider using `worker_run` instead."
3173
- ):
3174
- # Query database through cache
3175
- elements = mock_elements_worker_with_cache.list_element_children(**filters)
3176
- assert elements.count() == len(expected_ids)
3177
- for child, expected_id in zip(elements.order_by("id"), expected_ids, strict=True):
3178
- assert child.id == UUID(expected_id)
3179
-
3180
- # Check the worker never hits the API for elements
3181
- assert len(responses.calls) == len(BASE_API_CALLS)
3182
- assert [
3183
- (call.request.method, call.request.url) for call in responses.calls
3184
- ] == BASE_API_CALLS
3185
-
3186
-
3187
- def test_list_element_parents_wrong_element(mock_elements_worker):
3188
- with pytest.raises(
3189
- AssertionError,
3190
- match="element shouldn't be null and should be an Element or CachedElement",
3191
- ):
3192
- mock_elements_worker.list_element_parents(element=None)
3193
-
3194
- with pytest.raises(
3195
- AssertionError,
3196
- match="element shouldn't be null and should be an Element or CachedElement",
3197
- ):
3198
- mock_elements_worker.list_element_parents(element="not element type")
3199
-
3200
-
3201
- def test_list_element_parents_wrong_folder(mock_elements_worker):
3202
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
3203
-
3204
- with pytest.raises(AssertionError, match="folder should be of type bool"):
3205
- mock_elements_worker.list_element_parents(
3206
- element=elt,
3207
- folder="not bool",
3208
- )
3209
-
3210
-
3211
- def test_list_element_parents_wrong_name(mock_elements_worker):
3212
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
3213
-
3214
- with pytest.raises(AssertionError, match="name should be of type str"):
3215
- mock_elements_worker.list_element_parents(
3216
- element=elt,
3217
- name=1234,
3218
- )
3219
-
3220
-
3221
- def test_list_element_parents_wrong_recursive(mock_elements_worker):
3222
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
3223
-
3224
- with pytest.raises(AssertionError, match="recursive should be of type bool"):
3225
- mock_elements_worker.list_element_parents(
3226
- element=elt,
3227
- recursive="not bool",
3228
- )
3229
-
3230
-
3231
- def test_list_element_parents_wrong_type(mock_elements_worker):
3232
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
3233
-
3234
- with pytest.raises(AssertionError, match="type should be of type str"):
3235
- mock_elements_worker.list_element_parents(
3236
- element=elt,
3237
- type=1234,
3238
- )
3239
-
3240
-
3241
- def test_list_element_parents_wrong_with_classes(mock_elements_worker):
3242
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
3243
-
3244
- with pytest.raises(AssertionError, match="with_classes should be of type bool"):
3245
- mock_elements_worker.list_element_parents(
3246
- element=elt,
3247
- with_classes="not bool",
3248
- )
3249
-
3250
-
3251
- def test_list_element_parents_wrong_with_corpus(mock_elements_worker):
3252
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
3253
-
3254
- with pytest.raises(AssertionError, match="with_corpus should be of type bool"):
3255
- mock_elements_worker.list_element_parents(
3256
- element=elt,
3257
- with_corpus="not bool",
3258
- )
3259
-
3260
-
3261
- def test_list_element_parents_wrong_with_has_children(mock_elements_worker):
3262
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
3263
-
3264
- with pytest.raises(
3265
- AssertionError, match="with_has_children should be of type bool"
3266
- ):
3267
- mock_elements_worker.list_element_parents(
3268
- element=elt,
3269
- with_has_children="not bool",
3270
- )
3271
-
3272
-
3273
- def test_list_element_parents_wrong_with_zone(mock_elements_worker):
3274
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
3275
-
3276
- with pytest.raises(AssertionError, match="with_zone should be of type bool"):
3277
- mock_elements_worker.list_element_parents(
3278
- element=elt,
3279
- with_zone="not bool",
3280
- )
3281
-
3282
-
3283
- def test_list_element_parents_wrong_with_metadata(mock_elements_worker):
3284
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
3285
-
3286
- with pytest.raises(AssertionError, match="with_metadata should be of type bool"):
3287
- mock_elements_worker.list_element_parents(
3288
- element=elt,
3289
- with_metadata="not bool",
3290
- )
3291
-
3292
-
3293
- @pytest.mark.parametrize(
3294
- ("param", "value"),
3295
- [
3296
- ("worker_run", 1234),
3297
- ("transcription_worker_run", 1234),
3298
- ],
3299
- )
3300
- def test_list_element_parents_wrong_worker_run(mock_elements_worker, param, value):
3301
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
3302
-
3303
- with pytest.raises(AssertionError, match=f"{param} should be of type str or bool"):
3304
- mock_elements_worker.list_element_parents(
3305
- element=elt,
3306
- **{param: value},
3307
- )
3308
-
3309
-
3310
- @pytest.mark.parametrize(
3311
- ("param", "alternative", "value"),
3312
- [
3313
- ("worker_version", "worker_run", 1234),
3314
- ("transcription_worker_version", "transcription_worker_run", 1234),
3315
- ],
3316
- )
3317
- def test_list_element_parents_wrong_worker_version(
3318
- mock_elements_worker, param, alternative, value
3319
- ):
3320
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
3321
-
3322
- # WARNING: pytest.deprecated_call must be placed BEFORE pytest.raises, otherwise `match` argument won't be checked
3323
- with (
3324
- pytest.deprecated_call(
3325
- match=f"`{param}` usage is deprecated. Consider using `{alternative}` instead."
3326
- ),
3327
- pytest.raises(AssertionError, match=f"{param} should be of type str or bool"),
3328
- ):
3329
- mock_elements_worker.list_element_parents(
3330
- element=elt,
3331
- **{param: value},
3332
- )
3333
-
3334
-
3335
- @pytest.mark.parametrize(
3336
- "param",
3337
- [
3338
- "worker_run",
3339
- "transcription_worker_run",
3340
- ],
3341
- )
3342
- def test_list_element_parents_wrong_bool_worker_run(mock_elements_worker, param):
3343
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
3344
-
3345
- with pytest.raises(
3346
- AssertionError, match=f"if of type bool, {param} can only be set to False"
3347
- ):
3348
- mock_elements_worker.list_element_parents(
3349
- element=elt,
3350
- **{param: True},
3351
- )
3352
-
3353
-
3354
- @pytest.mark.parametrize(
3355
- ("param", "alternative"),
3356
- [
3357
- ("worker_version", "worker_run"),
3358
- ("transcription_worker_version", "transcription_worker_run"),
3359
- ],
3360
- )
3361
- def test_list_element_parents_wrong_bool_worker_version(
3362
- mock_elements_worker, param, alternative
3363
- ):
3364
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
3365
-
3366
- # WARNING: pytest.deprecated_call must be placed BEFORE pytest.raises, otherwise `match` argument won't be checked
3367
- with (
3368
- pytest.deprecated_call(
3369
- match=f"`{param}` usage is deprecated. Consider using `{alternative}` instead."
3370
- ),
3371
- pytest.raises(
3372
- AssertionError, match=f"if of type bool, {param} can only be set to False"
3373
- ),
3374
- ):
3375
- mock_elements_worker.list_element_parents(
3376
- element=elt,
3377
- **{param: True},
3378
- )
3379
-
3380
-
3381
- def test_list_element_parents_api_error(responses, mock_elements_worker):
3382
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
3383
- responses.add(
3384
- responses.GET,
3385
- "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/parents/",
3386
- status=418,
3387
- )
3388
-
3389
- with pytest.raises(
3390
- Exception, match="Stopping pagination as data will be incomplete"
3391
- ):
3392
- next(mock_elements_worker.list_element_parents(element=elt))
3393
-
3394
- assert len(responses.calls) == len(BASE_API_CALLS) + 5
3395
- assert [
3396
- (call.request.method, call.request.url) for call in responses.calls
3397
- ] == BASE_API_CALLS + [
3398
- # We do 5 retries
3399
- (
3400
- "GET",
3401
- "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/parents/",
3402
- ),
3403
- (
3404
- "GET",
3405
- "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/parents/",
3406
- ),
3407
- (
3408
- "GET",
3409
- "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/parents/",
3410
- ),
3411
- (
3412
- "GET",
3413
- "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/parents/",
3414
- ),
3415
- (
3416
- "GET",
3417
- "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/parents/",
3418
- ),
3419
- ]
3420
-
3421
-
3422
- def test_list_element_parents(responses, mock_elements_worker):
3423
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
3424
- expected_parents = [
3425
- {
3426
- "id": "0000",
3427
- "type": "page",
3428
- "name": "Test",
3429
- "corpus": {},
3430
- "thumbnail_url": None,
3431
- "zone": {},
3432
- "best_classes": None,
3433
- "has_children": None,
3434
- "worker_version_id": None,
3435
- "worker_run_id": None,
3436
- },
3437
- {
3438
- "id": "1111",
3439
- "type": "page",
3440
- "name": "Test 2",
3441
- "corpus": {},
3442
- "thumbnail_url": None,
3443
- "zone": {},
3444
- "best_classes": None,
3445
- "has_children": None,
3446
- "worker_version_id": None,
3447
- "worker_run_id": None,
3448
- },
3449
- {
3450
- "id": "2222",
3451
- "type": "page",
3452
- "name": "Test 3",
3453
- "corpus": {},
3454
- "thumbnail_url": None,
3455
- "zone": {},
3456
- "best_classes": None,
3457
- "has_children": None,
3458
- "worker_version_id": None,
3459
- "worker_run_id": None,
3460
- },
3461
- ]
3462
- responses.add(
3463
- responses.GET,
3464
- "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/parents/",
3465
- status=200,
3466
- json={
3467
- "count": 3,
3468
- "next": None,
3469
- "results": expected_parents,
3470
- },
3471
- )
3472
-
3473
- for idx, parent in enumerate(
3474
- mock_elements_worker.list_element_parents(element=elt)
3475
- ):
3476
- assert parent == expected_parents[idx]
3477
-
3478
- assert len(responses.calls) == len(BASE_API_CALLS) + 1
3479
- assert [
3480
- (call.request.method, call.request.url) for call in responses.calls
3481
- ] == BASE_API_CALLS + [
3482
- (
3483
- "GET",
3484
- "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/parents/",
3485
- ),
3486
- ]
3487
-
3488
-
3489
- def test_list_element_parents_manual_worker_version(responses, mock_elements_worker):
3490
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
3491
- expected_parents = [
3492
- {
3493
- "id": "0000",
3494
- "type": "page",
3495
- "name": "Test",
3496
- "corpus": {},
3497
- "thumbnail_url": None,
3498
- "zone": {},
3499
- "best_classes": None,
3500
- "has_children": None,
3501
- "worker_version_id": None,
3502
- "worker_run_id": None,
3503
- }
3504
- ]
3505
- responses.add(
3506
- responses.GET,
3507
- "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/parents/?worker_version=False",
3508
- status=200,
3509
- json={
3510
- "count": 1,
3511
- "next": None,
3512
- "results": expected_parents,
3513
- },
3514
- )
3515
-
3516
- with pytest.deprecated_call(
3517
- match="`worker_version` usage is deprecated. Consider using `worker_run` instead."
3518
- ):
3519
- for idx, parent in enumerate(
3520
- mock_elements_worker.list_element_parents(element=elt, worker_version=False)
3521
- ):
3522
- assert parent == expected_parents[idx]
3523
-
3524
- assert len(responses.calls) == len(BASE_API_CALLS) + 1
3525
- assert [
3526
- (call.request.method, call.request.url) for call in responses.calls
3527
- ] == BASE_API_CALLS + [
3528
- (
3529
- "GET",
3530
- "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/parents/?worker_version=False",
3531
- ),
3532
- ]
3533
-
3534
-
3535
- def test_list_element_parents_manual_worker_run(responses, mock_elements_worker):
3536
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
3537
- expected_parents = [
3538
- {
3539
- "id": "0000",
3540
- "type": "page",
3541
- "name": "Test",
3542
- "corpus": {},
3543
- "thumbnail_url": None,
3544
- "zone": {},
3545
- "best_classes": None,
3546
- "has_children": None,
3547
- "worker_version_id": None,
3548
- "worker_run_id": None,
3549
- }
3550
- ]
3551
- responses.add(
3552
- responses.GET,
3553
- "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/parents/?worker_run=False",
3554
- status=200,
3555
- json={
3556
- "count": 1,
3557
- "next": None,
3558
- "results": expected_parents,
3559
- },
3560
- )
3561
-
3562
- for idx, parent in enumerate(
3563
- mock_elements_worker.list_element_parents(element=elt, worker_run=False)
3564
- ):
3565
- assert parent == expected_parents[idx]
3566
-
3567
- assert len(responses.calls) == len(BASE_API_CALLS) + 1
3568
- assert [
3569
- (call.request.method, call.request.url) for call in responses.calls
3570
- ] == BASE_API_CALLS + [
3571
- (
3572
- "GET",
3573
- "http://testserver/api/v1/elements/12341234-1234-1234-1234-123412341234/parents/?worker_run=False",
3574
- ),
3575
- ]
3576
-
3577
-
3578
- def test_list_element_parents_with_cache_unhandled_param(
3579
- mock_elements_worker_with_cache,
3580
- ):
3581
- elt = Element({"id": "12341234-1234-1234-1234-123412341234"})
3582
-
3583
- with pytest.raises(
3584
- AssertionError,
3585
- match="When using the local cache, you can only filter by 'type' and/or 'worker_version' and/or 'worker_run'",
3586
- ):
3587
- mock_elements_worker_with_cache.list_element_parents(
3588
- element=elt, with_corpus=True
3589
- )
3590
-
3591
-
3592
- @pytest.mark.usefixtures("_mock_cached_elements")
3593
- @pytest.mark.parametrize(
3594
- ("filters", "expected_id"),
3595
- [
3596
- # Filter on element
3597
- (
3598
- {
3599
- "element": CachedElement(id="11111111-1111-1111-1111-111111111111"),
3600
- },
3601
- "12341234-1234-1234-1234-123412341234",
3602
- ),
3603
- # Filter on element and double_page
3604
- (
3605
- {
3606
- "element": CachedElement(id="22222222-2222-2222-2222-222222222222"),
3607
- "type": "double_page",
3608
- },
3609
- "12341234-1234-1234-1234-123412341234",
3610
- ),
3611
- # Filter on element and worker run
3612
- (
3613
- {
3614
- "element": CachedElement(id="22222222-2222-2222-2222-222222222222"),
3615
- "worker_run": "56785678-5678-5678-5678-567856785678",
3616
- },
3617
- "12341234-1234-1234-1234-123412341234",
3618
- ),
3619
- # Filter on element, manual worker run
3620
- (
3621
- {
3622
- "element": CachedElement(id="12341234-1234-1234-1234-123412341234"),
3623
- "worker_run": False,
3624
- },
3625
- "99999999-9999-9999-9999-999999999999",
3626
- ),
3627
- ],
3628
- )
3629
- def test_list_element_parents_with_cache(
3630
- responses,
3631
- mock_elements_worker_with_cache,
3632
- filters,
3633
- expected_id,
3634
- ):
3635
- # Check we have 5 elements already present in database
3636
- assert CachedElement.select().count() == 5
3637
-
3638
- # Query database through cache
3639
- elements = mock_elements_worker_with_cache.list_element_parents(**filters)
3640
- assert elements.count() == 1
3641
- for parent in elements.order_by("id"):
3642
- assert parent.id == UUID(expected_id)
3643
-
3644
- # Check the worker never hits the API for elements
3645
- assert len(responses.calls) == len(BASE_API_CALLS)
3646
- assert [
3647
- (call.request.method, call.request.url) for call in responses.calls
3648
- ] == BASE_API_CALLS
3649
-
3650
-
3651
- @pytest.mark.usefixtures("_mock_cached_elements")
3652
- @pytest.mark.parametrize(
3653
- ("filters", "expected_id"),
3654
- [
3655
- # Filter on element and worker version
3656
- (
3657
- {
3658
- "element": CachedElement(id="33333333-3333-3333-3333-333333333333"),
3659
- "worker_version": "56785678-5678-5678-5678-567856785678",
3660
- },
3661
- "12341234-1234-1234-1234-123412341234",
3662
- ),
3663
- # Filter on element, type double_page and worker version
3664
- (
3665
- {
3666
- "element": CachedElement(id="11111111-1111-1111-1111-111111111111"),
3667
- "type": "double_page",
3668
- "worker_version": "56785678-5678-5678-5678-567856785678",
3669
- },
3670
- "12341234-1234-1234-1234-123412341234",
3671
- ),
3672
- # Filter on element, manual worker version
3673
- (
3674
- {
3675
- "element": CachedElement(id="12341234-1234-1234-1234-123412341234"),
3676
- "worker_version": False,
3677
- },
3678
- "99999999-9999-9999-9999-999999999999",
3679
- ),
3680
- ],
3681
- )
3682
- def test_list_element_parents_with_cache_deprecation(
3683
- responses,
3684
- mock_elements_worker_with_cache,
3685
- filters,
3686
- expected_id,
3687
- ):
3688
- # Check we have 5 elements already present in database
3689
- assert CachedElement.select().count() == 5
3690
-
3691
- with pytest.deprecated_call(
3692
- match="`worker_version` usage is deprecated. Consider using `worker_run` instead."
3693
- ):
3694
- # Query database through cache
3695
- elements = mock_elements_worker_with_cache.list_element_parents(**filters)
3696
- assert elements.count() == 1
3697
- for parent in elements.order_by("id"):
3698
- assert parent.id == UUID(expected_id)
3699
-
3700
- # Check the worker never hits the API for elements
3701
- assert len(responses.calls) == len(BASE_API_CALLS)
3702
- assert [
3703
- (call.request.method, call.request.url) for call in responses.calls
3704
- ] == BASE_API_CALLS