arkindex-base-worker 0.4.0b3__py3-none-any.whl → 0.4.0rc1__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.
@@ -6,7 +6,6 @@ from apistar.exceptions import ErrorResponse
6
6
 
7
7
  from arkindex_worker.cache import CachedElement
8
8
  from arkindex_worker.worker import ActivityState, ElementsWorker
9
- from tests import CORPUS_ID
10
9
 
11
10
  from . import BASE_API_CALLS
12
11
 
@@ -313,202 +312,3 @@ def test_start_activity_error(
313
312
  assert logger.error.call_args_list == [
314
313
  mocker.call("Ran on 1 element: 0 completed, 1 failed")
315
314
  ]
316
-
317
-
318
- @pytest.mark.parametrize(
319
- (
320
- "wk_version_config",
321
- "wk_version_user_config",
322
- "frontend_user_config",
323
- "model_config",
324
- "expected_config",
325
- ),
326
- [
327
- ({}, {}, {}, {}, {}),
328
- # Keep parameters from worker version configuration
329
- ({"parameter": 0}, {}, {}, {}, {"parameter": 0}),
330
- # Keep parameters from worker version configuration + user_config defaults
331
- (
332
- {"parameter": 0},
333
- {
334
- "parameter2": {
335
- "type": "int",
336
- "title": "Lambda",
337
- "default": 0,
338
- "required": False,
339
- }
340
- },
341
- {},
342
- {},
343
- {"parameter": 0, "parameter2": 0},
344
- ),
345
- # Keep parameters from worker version configuration + user_config no defaults
346
- (
347
- {"parameter": 0},
348
- {
349
- "parameter2": {
350
- "type": "int",
351
- "title": "Lambda",
352
- "required": False,
353
- }
354
- },
355
- {},
356
- {},
357
- {"parameter": 0},
358
- ),
359
- # Keep parameters from worker version configuration but user_config defaults overrides
360
- (
361
- {"parameter": 0},
362
- {
363
- "parameter": {
364
- "type": "int",
365
- "title": "Lambda",
366
- "default": 1,
367
- "required": False,
368
- }
369
- },
370
- {},
371
- {},
372
- {"parameter": 1},
373
- ),
374
- # Keep parameters from worker version configuration + frontend config
375
- (
376
- {"parameter": 0},
377
- {},
378
- {"parameter2": 0},
379
- {},
380
- {"parameter": 0, "parameter2": 0},
381
- ),
382
- # Keep parameters from worker version configuration + frontend config overrides
383
- ({"parameter": 0}, {}, {"parameter": 1}, {}, {"parameter": 1}),
384
- # Keep parameters from worker version configuration + model config
385
- (
386
- {"parameter": 0},
387
- {},
388
- {},
389
- {"parameter2": 0},
390
- {"parameter": 0, "parameter2": 0},
391
- ),
392
- # Keep parameters from worker version configuration + model config overrides
393
- ({"parameter": 0}, {}, {}, {"parameter": 1}, {"parameter": 1}),
394
- # Keep parameters from worker version configuration + user_config default + model config overrides
395
- (
396
- {"parameter": 0},
397
- {
398
- "parameter": {
399
- "type": "int",
400
- "title": "Lambda",
401
- "default": 1,
402
- "required": False,
403
- }
404
- },
405
- {},
406
- {"parameter": 2},
407
- {"parameter": 2},
408
- ),
409
- # Keep parameters from worker version configuration + model config + frontend config overrides
410
- ({"parameter": 0}, {}, {"parameter": 2}, {"parameter": 1}, {"parameter": 2}),
411
- # Keep parameters from worker version configuration + user_config default + model config + frontend config overrides all
412
- (
413
- {"parameter": 0},
414
- {
415
- "parameter": {
416
- "type": "int",
417
- "title": "Lambda",
418
- "default": 1,
419
- "required": False,
420
- }
421
- },
422
- {"parameter": 3},
423
- {"parameter": 2},
424
- {"parameter": 3},
425
- ),
426
- ],
427
- )
428
- def test_worker_config_multiple_source(
429
- monkeypatch,
430
- responses,
431
- wk_version_config,
432
- wk_version_user_config,
433
- frontend_user_config,
434
- model_config,
435
- expected_config,
436
- ):
437
- # Compute WorkerRun info
438
- payload = {
439
- "id": "56785678-5678-5678-5678-567856785678",
440
- "parents": [],
441
- "worker_version": {
442
- "id": "12341234-1234-1234-1234-123412341234",
443
- "configuration": {
444
- "docker": {"image": "python:3"},
445
- "configuration": wk_version_config,
446
- "secrets": [],
447
- "user_configuration": wk_version_user_config,
448
- },
449
- "revision": {
450
- "hash": "deadbeef1234",
451
- "name": "some git revision",
452
- },
453
- "docker_image": "python:3",
454
- "docker_image_name": "python:3",
455
- "state": "created",
456
- "worker": {
457
- "id": "deadbeef-1234-5678-1234-worker",
458
- "name": "Fake worker",
459
- "slug": "fake_worker",
460
- "type": "classifier",
461
- },
462
- },
463
- "configuration": {
464
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
465
- "name": "Configuration entered by user",
466
- "configuration": frontend_user_config,
467
- },
468
- "model_version": {
469
- "id": "12341234-1234-1234-1234-123412341234",
470
- "name": "Model version 1337",
471
- "configuration": model_config,
472
- "model": {
473
- "id": "hahahaha-haha-haha-haha-hahahahahaha",
474
- "name": "My model",
475
- },
476
- },
477
- "process": {
478
- "name": None,
479
- "id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeffff",
480
- "state": "running",
481
- "mode": "workers",
482
- "corpus": CORPUS_ID,
483
- "use_cache": False,
484
- "activity_state": "ready",
485
- "model_id": None,
486
- "train_folder_id": None,
487
- "validation_folder_id": None,
488
- "test_folder_id": None,
489
- },
490
- "summary": "Worker Fake worker @ 123412",
491
- }
492
-
493
- responses.add(
494
- responses.GET,
495
- "http://testserver/api/v1/process/workers/56785678-5678-5678-5678-567856785678/",
496
- status=200,
497
- body=json.dumps(payload),
498
- content_type="application/json",
499
- )
500
-
501
- # Create and configure a worker
502
- monkeypatch.setattr(sys, "argv", ["worker"])
503
- worker = ElementsWorker()
504
- worker.configure()
505
-
506
- # Do what people do with a model configuration
507
- if worker.model_configuration:
508
- worker.config.update(worker.model_configuration)
509
-
510
- if worker.user_configuration:
511
- worker.config.update(worker.user_configuration)
512
-
513
- # Check final config
514
- assert worker.config == expected_config
tests/test_image.py CHANGED
@@ -1,3 +1,4 @@
1
+ import logging
1
2
  import math
2
3
  import unittest
3
4
  import uuid
@@ -18,21 +19,52 @@ from arkindex_worker.image import (
18
19
  download_tiles,
19
20
  open_image,
20
21
  polygon_bounding_box,
22
+ resized_images,
21
23
  revert_orientation,
22
24
  trim_polygon,
25
+ update_pillow_image_size_limit,
23
26
  upload_image,
24
27
  )
25
28
  from arkindex_worker.models import Element
29
+ from tests import FIXTURES_DIR
26
30
 
27
- FIXTURES = Path(__file__).absolute().parent / "data"
28
- TILE = FIXTURES / "test_image.jpg"
29
- FULL_IMAGE = FIXTURES / "tiled_image.jpg"
30
- ROTATED_IMAGE = FIXTURES / "rotated_image.jpg"
31
- MIRRORED_IMAGE = FIXTURES / "mirrored_image.jpg"
32
- ROTATED_MIRRORED_IMAGE = FIXTURES / "rotated_mirrored_image.jpg"
31
+ TILE = FIXTURES_DIR / "test_image.jpg"
32
+ FULL_IMAGE = FIXTURES_DIR / "tiled_image.jpg"
33
+ ROTATED_IMAGE = FIXTURES_DIR / "rotated_image.jpg"
34
+ MIRRORED_IMAGE = FIXTURES_DIR / "mirrored_image.jpg"
35
+ ROTATED_MIRRORED_IMAGE = FIXTURES_DIR / "rotated_mirrored_image.jpg"
33
36
  TEST_IMAGE = {"width": 800, "height": 300}
34
37
 
35
38
 
39
+ @pytest.fixture()
40
+ def mock_page():
41
+ class Page(Element):
42
+ def open_image(
43
+ self,
44
+ *args,
45
+ max_width: int | None = None,
46
+ max_height: int | None = None,
47
+ use_full_image: bool | None = False,
48
+ **kwargs,
49
+ ) -> Image.Image:
50
+ # Image from Socface (https://socface.site.ined.fr/) project (AD026)
51
+ image = Image.open(FIXTURES_DIR / "AD026_6M_00505_0001_0373.jpg")
52
+ image.thumbnail(size=(max_width or image.width, max_height or image.height))
53
+
54
+ return image
55
+
56
+ return Page(
57
+ id="page_id",
58
+ name="1",
59
+ zone={
60
+ "polygon": [[0, 0], [1000, 0], [1000, 3000], [0, 3000], [0, 0]],
61
+ "image": {"width": 1000, "height": 3000},
62
+ },
63
+ rotation_angle=0,
64
+ mirrored=False,
65
+ )
66
+
67
+
36
68
  def _root_mean_square(img_a, img_b):
37
69
  """
38
70
  Get the root-mean-square difference between two images for fuzzy matching
@@ -45,6 +77,30 @@ def _root_mean_square(img_a, img_b):
45
77
  )
46
78
 
47
79
 
80
+ @pytest.mark.parametrize(
81
+ ("max_image_pixels", "expected_image_pixels"),
82
+ [
83
+ # Pillow Image size limit not updated
84
+ (None, Image.MAX_IMAGE_PIXELS),
85
+ # Pillow Image size limit set to None
86
+ ("0", None),
87
+ (0, None),
88
+ # Update Pillow Image size limit
89
+ ("1", 1),
90
+ (1, 1),
91
+ ],
92
+ )
93
+ def test_update_pillow_image_size_limit(max_image_pixels, expected_image_pixels):
94
+ MAX_IMAGE_PIXELS = Image.MAX_IMAGE_PIXELS
95
+
96
+ @update_pillow_image_size_limit
97
+ def function() -> int | None:
98
+ return Image.MAX_IMAGE_PIXELS
99
+
100
+ assert function(max_image_pixels=max_image_pixels) == expected_image_pixels
101
+ assert Image.MAX_IMAGE_PIXELS == MAX_IMAGE_PIXELS
102
+
103
+
48
104
  def test_download_tiles(responses):
49
105
  expected = Image.open(FULL_IMAGE).convert("RGB")
50
106
  tile_bytes = TILE.read_bytes()
@@ -582,3 +638,189 @@ def test_upload_image(responses):
582
638
 
583
639
  assert len(responses.calls) == 1
584
640
  assert list(map(attrgetter("request.url"), responses.calls)) == [dest_url]
641
+
642
+
643
+ @pytest.mark.parametrize(
644
+ ("max_pixels", "max_bytes", "expected_sizes", "expected_logs"),
645
+ [
646
+ # No limits
647
+ (
648
+ None,
649
+ None,
650
+ [
651
+ (1992, 3000),
652
+ (1793, 2700),
653
+ (1694, 2550),
654
+ (1594, 2400),
655
+ (1494, 2250),
656
+ (1395, 2100),
657
+ (1195, 1800),
658
+ (996, 1500),
659
+ (797, 1200),
660
+ (598, 900),
661
+ ],
662
+ [
663
+ (logging.WARNING, "The image was resized to (1992 x 3000)."),
664
+ (logging.WARNING, "The image was resized to (1793 x 2700)."),
665
+ (logging.WARNING, "The image was resized to (1694 x 2550)."),
666
+ (logging.WARNING, "The image was resized to (1594 x 2400)."),
667
+ (logging.WARNING, "The image was resized to (1494 x 2250)."),
668
+ (logging.WARNING, "The image was resized to (1395 x 2100)."),
669
+ (logging.WARNING, "The image was resized to (1195 x 1800)."),
670
+ (logging.WARNING, "The image was resized to (996 x 1500)."),
671
+ (logging.WARNING, "The image was resized to (797 x 1200)."),
672
+ (logging.WARNING, "The image was resized to (598 x 900)."),
673
+ ],
674
+ ),
675
+ # Image already under the limits
676
+ (
677
+ 10000,
678
+ 4000000, # 4MB
679
+ [
680
+ (1992, 3000),
681
+ (1793, 2700),
682
+ (1694, 2550),
683
+ (1594, 2400),
684
+ (1494, 2250),
685
+ (1395, 2100),
686
+ (1195, 1800),
687
+ (996, 1500),
688
+ (797, 1200),
689
+ (598, 900),
690
+ ],
691
+ [
692
+ (logging.WARNING, "The image was resized to (1992 x 3000)."),
693
+ (logging.WARNING, "The image was resized to (1793 x 2700)."),
694
+ (logging.WARNING, "The image was resized to (1694 x 2550)."),
695
+ (logging.WARNING, "The image was resized to (1594 x 2400)."),
696
+ (logging.WARNING, "The image was resized to (1494 x 2250)."),
697
+ (logging.WARNING, "The image was resized to (1395 x 2100)."),
698
+ (logging.WARNING, "The image was resized to (1195 x 1800)."),
699
+ (logging.WARNING, "The image was resized to (996 x 1500)."),
700
+ (logging.WARNING, "The image was resized to (797 x 1200)."),
701
+ (logging.WARNING, "The image was resized to (598 x 900)."),
702
+ ],
703
+ ),
704
+ # Image above the limits
705
+ (
706
+ None,
707
+ 100000, # 100kB
708
+ [(598, 900)],
709
+ [
710
+ (logging.WARNING, "The image was resized to (1992 x 3000)."),
711
+ (logging.WARNING, "The image size is 773.4 kB."),
712
+ (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
713
+ (logging.WARNING, "The image will be resized."),
714
+ (logging.WARNING, "The image was resized to (1793 x 2700)."),
715
+ (logging.WARNING, "The image size is 616.0 kB."),
716
+ (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
717
+ (logging.WARNING, "The image will be resized."),
718
+ (logging.WARNING, "The image was resized to (1694 x 2550)."),
719
+ (logging.WARNING, "The image size is 546.4 kB."),
720
+ (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
721
+ (logging.WARNING, "The image will be resized."),
722
+ (logging.WARNING, "The image was resized to (1594 x 2400)."),
723
+ (logging.WARNING, "The image size is 479.4 kB."),
724
+ (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
725
+ (logging.WARNING, "The image will be resized."),
726
+ (logging.WARNING, "The image was resized to (1494 x 2250)."),
727
+ (logging.WARNING, "The image size is 416.1 kB."),
728
+ (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
729
+ (logging.WARNING, "The image will be resized."),
730
+ (logging.WARNING, "The image was resized to (1395 x 2100)."),
731
+ (logging.WARNING, "The image size is 360.5 kB."),
732
+ (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
733
+ (logging.WARNING, "The image will be resized."),
734
+ (logging.WARNING, "The image was resized to (1195 x 1800)."),
735
+ (logging.WARNING, "The image size is 258.6 kB."),
736
+ (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
737
+ (logging.WARNING, "The image will be resized."),
738
+ (logging.WARNING, "The image was resized to (996 x 1500)."),
739
+ (logging.WARNING, "The image size is 179.0 kB."),
740
+ (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
741
+ (logging.WARNING, "The image will be resized."),
742
+ (logging.WARNING, "The image was resized to (797 x 1200)."),
743
+ (logging.WARNING, "The image size is 115.7 kB."),
744
+ (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
745
+ (logging.WARNING, "The image will be resized."),
746
+ (logging.WARNING, "The image was resized to (598 x 900)."),
747
+ ],
748
+ ),
749
+ # Image above the limits
750
+ (
751
+ 2000,
752
+ None,
753
+ [(1328, 2000), (1195, 1800), (996, 1500), (797, 1200), (598, 900)],
754
+ [
755
+ (
756
+ logging.WARNING,
757
+ "Maximum image input size supported is (2000 x 2000).",
758
+ ),
759
+ (logging.WARNING, "The image will be resized."),
760
+ (logging.WARNING, "The image was resized to (1328 x 2000)."),
761
+ (logging.WARNING, "The image was resized to (1195 x 1800)."),
762
+ (logging.WARNING, "The image was resized to (996 x 1500)."),
763
+ (logging.WARNING, "The image was resized to (797 x 1200)."),
764
+ (logging.WARNING, "The image was resized to (598 x 900)."),
765
+ ],
766
+ ),
767
+ # Image above the limits
768
+ (
769
+ 2000,
770
+ 100000, # 100kB
771
+ [(598, 900)],
772
+ [
773
+ (
774
+ logging.WARNING,
775
+ "Maximum image input size supported is (2000 x 2000).",
776
+ ),
777
+ (logging.WARNING, "The image will be resized."),
778
+ (logging.WARNING, "The image was resized to (1328 x 2000)."),
779
+ (logging.WARNING, "The image size is 325.5 kB."),
780
+ (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
781
+ (logging.WARNING, "The image will be resized."),
782
+ (logging.WARNING, "The image was resized to (1195 x 1800)."),
783
+ (logging.WARNING, "The image size is 258.6 kB."),
784
+ (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
785
+ (logging.WARNING, "The image will be resized."),
786
+ (logging.WARNING, "The image was resized to (996 x 1500)."),
787
+ (logging.WARNING, "The image size is 179.0 kB."),
788
+ (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
789
+ (logging.WARNING, "The image will be resized."),
790
+ (logging.WARNING, "The image was resized to (797 x 1200)."),
791
+ (logging.WARNING, "The image size is 115.7 kB."),
792
+ (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
793
+ (logging.WARNING, "The image will be resized."),
794
+ (logging.WARNING, "The image was resized to (598 x 900)."),
795
+ ],
796
+ ),
797
+ # Image always above the limits
798
+ (
799
+ 50,
800
+ 50, # 50B
801
+ [],
802
+ [
803
+ (logging.WARNING, "Maximum image input size supported is (50 x 50)."),
804
+ (logging.WARNING, "The image will be resized."),
805
+ (logging.WARNING, "The image was resized to (33 x 50)."),
806
+ (logging.WARNING, "The image size is 1.0 kB."),
807
+ (logging.WARNING, "Maximum image input size supported is 50 Bytes."),
808
+ (logging.WARNING, "The image will be resized."),
809
+ ],
810
+ ),
811
+ ],
812
+ )
813
+ def test_resized_images(
814
+ max_pixels, max_bytes, expected_sizes, expected_logs, mock_page, caplog
815
+ ):
816
+ caplog.set_level(logging.WARNING)
817
+
818
+ assert [
819
+ Image.open(image).size
820
+ for image in resized_images(
821
+ element=mock_page, max_pixels=max_pixels, max_bytes=max_bytes
822
+ )
823
+ ] == expected_sizes
824
+ assert [
825
+ (record.levelno, record.message) for record in caplog.records
826
+ ] == expected_logs
tests/test_merge.py CHANGED
@@ -181,7 +181,6 @@ def test_merge_from_worker(
181
181
  (tmp_path / "my_task").mkdir()
182
182
  mock_base_worker_with_cache.args = mock_base_worker_with_cache.parser.parse_args()
183
183
  mock_base_worker_with_cache.configure()
184
- mock_base_worker_with_cache.configure_cache()
185
184
  # Store parent tasks IDs as attribute
186
185
  assert mock_base_worker_with_cache.task_parents == ["first", "second"]
187
186
 
tests/test_utils.py CHANGED
@@ -1,5 +1,3 @@
1
- from pathlib import Path
2
-
3
1
  import pytest
4
2
 
5
3
  from arkindex_worker.utils import (
@@ -9,9 +7,9 @@ from arkindex_worker.utils import (
9
7
  extract_tar_zst_archive,
10
8
  parse_source_id,
11
9
  )
10
+ from tests import FIXTURES_DIR
12
11
 
13
- FIXTURES = Path(__file__).absolute().parent / "data"
14
- ARCHIVE = FIXTURES / "archive.tar.zst"
12
+ ARCHIVE = FIXTURES_DIR / "archive.tar.zst"
15
13
 
16
14
 
17
15
  @pytest.mark.parametrize(