arkindex-base-worker 0.4.0rc6__py3-none-any.whl → 0.5.0a2__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.
tests/test_image.py CHANGED
@@ -9,6 +9,7 @@ import pytest
9
9
  from PIL import Image, ImageChops, ImageOps
10
10
  from requests import HTTPError
11
11
 
12
+ import arkindex_worker.image
12
13
  from arkindex_worker.cache import CachedElement, create_tables, init_cache_db
13
14
  from arkindex_worker.image import (
14
15
  IIIF_FULL,
@@ -35,9 +36,18 @@ ROTATED_MIRRORED_IMAGE = FIXTURES_DIR / "rotated_mirrored_image.jpg"
35
36
  TEST_IMAGE = {"width": 800, "height": 300}
36
37
 
37
38
 
38
- @pytest.fixture()
39
+ @pytest.fixture
39
40
  def mock_page():
40
41
  class Page(Element):
42
+ @property
43
+ def crop(self):
44
+ # Image from Socface (https://socface.site.ined.fr/) project (AD026)
45
+ image = Image.open(FIXTURES_DIR / "AD026_6M_00505_0001_0373.jpg")
46
+ x, y, element_width, element_height = polygon_bounding_box(
47
+ self.zone.polygon
48
+ )
49
+ return image.crop(box=(x, y, x + element_width, y + element_height))
50
+
41
51
  def open_image(
42
52
  self,
43
53
  *args,
@@ -46,18 +56,21 @@ def mock_page():
46
56
  use_full_image: bool | None = False,
47
57
  **kwargs,
48
58
  ) -> Image.Image:
49
- # Image from Socface (https://socface.site.ined.fr/) project (AD026)
50
- image = Image.open(FIXTURES_DIR / "AD026_6M_00505_0001_0373.jpg")
51
- image.thumbnail(size=(max_width or image.width, max_height or image.height))
52
-
53
- return image
59
+ crop = self.crop.copy()
60
+ crop.thumbnail(
61
+ size=(
62
+ max_width or self.zone.image.width,
63
+ max_height or self.zone.image.height,
64
+ )
65
+ )
66
+ return crop
54
67
 
55
68
  return Page(
56
69
  id="page_id",
57
70
  name="1",
58
71
  zone={
59
- "polygon": [[0, 0], [1000, 0], [1000, 3000], [0, 3000], [0, 0]],
60
- "image": {"width": 1000, "height": 3000},
72
+ "polygon": [[0, 0], [2000, 0], [2000, 3000], [0, 3000], [0, 0]],
73
+ "image": {"width": 2000, "height": 3000},
61
74
  },
62
75
  rotation_angle=0,
63
76
  mirrored=False,
@@ -624,186 +637,283 @@ def test_upload_image(responses):
624
637
 
625
638
 
626
639
  @pytest.mark.parametrize(
627
- ("max_pixels", "max_bytes", "expected_sizes", "expected_logs"),
640
+ (
641
+ "max_pixels_short",
642
+ "max_pixels_long",
643
+ "max_bytes",
644
+ "expected_sizes",
645
+ "expected_logs",
646
+ ),
628
647
  [
629
- # No limits
648
+ # No limits provided
630
649
  (
631
650
  None,
632
651
  None,
652
+ None,
653
+ [(2000, 3000), (1000, 1500), (200, 300)],
633
654
  [
634
- (1992, 3000),
635
- (1793, 2700),
636
- (1694, 2550),
637
- (1594, 2400),
638
- (1494, 2250),
639
- (1395, 2100),
640
- (1195, 1800),
641
- (996, 1500),
642
- (797, 1200),
643
- (598, 900),
644
- ],
645
- [
646
- (logging.WARNING, "The image was resized to (1992 x 3000)."),
647
- (logging.WARNING, "The image was resized to (1793 x 2700)."),
648
- (logging.WARNING, "The image was resized to (1694 x 2550)."),
649
- (logging.WARNING, "The image was resized to (1594 x 2400)."),
650
- (logging.WARNING, "The image was resized to (1494 x 2250)."),
651
- (logging.WARNING, "The image was resized to (1395 x 2100)."),
652
- (logging.WARNING, "The image was resized to (1195 x 1800)."),
653
- (logging.WARNING, "The image was resized to (996 x 1500)."),
654
- (logging.WARNING, "The image was resized to (797 x 1200)."),
655
- (logging.WARNING, "The image was resized to (598 x 900)."),
655
+ (logging.INFO, "This element's image dimensions are (2000 x 3000)."),
656
+ (logging.WARNING, "The image was resized to (1000 x 1500)."),
657
+ (logging.WARNING, "The image was resized to (200 x 300)."),
656
658
  ],
657
659
  ),
658
- # Image already under the limits
660
+ # Image already under all three limits
659
661
  (
662
+ 10000,
660
663
  10000,
661
664
  4000000, # 4MB
665
+ [(2000, 3000), (1000, 1500), (200, 300)],
662
666
  [
663
- (1992, 3000),
664
- (1793, 2700),
665
- (1694, 2550),
666
- (1594, 2400),
667
- (1494, 2250),
668
- (1395, 2100),
669
- (1195, 1800),
670
- (996, 1500),
671
- (797, 1200),
672
- (598, 900),
667
+ (logging.INFO, "This element's image dimensions are (2000 x 3000)."),
668
+ (logging.WARNING, "The image was resized to (1000 x 1500)."),
669
+ (logging.WARNING, "The image was resized to (200 x 300)."),
673
670
  ],
671
+ ),
672
+ # Image above the "short side in pixels" limit
673
+ (
674
+ 1000,
675
+ None,
676
+ None,
677
+ [(1000, 1500), (500, 750), (100, 150)],
674
678
  [
675
- (logging.WARNING, "The image was resized to (1992 x 3000)."),
676
- (logging.WARNING, "The image was resized to (1793 x 2700)."),
677
- (logging.WARNING, "The image was resized to (1694 x 2550)."),
678
- (logging.WARNING, "The image was resized to (1594 x 2400)."),
679
- (logging.WARNING, "The image was resized to (1494 x 2250)."),
680
- (logging.WARNING, "The image was resized to (1395 x 2100)."),
681
- (logging.WARNING, "The image was resized to (1195 x 1800)."),
682
- (logging.WARNING, "The image was resized to (996 x 1500)."),
683
- (logging.WARNING, "The image was resized to (797 x 1200)."),
684
- (logging.WARNING, "The image was resized to (598 x 900)."),
679
+ (logging.INFO, "This element's image dimensions are (2000 x 3000)."),
680
+ (
681
+ logging.WARNING,
682
+ "Maximum image dimensions supported are (1000 x 3000).",
683
+ ),
684
+ (logging.WARNING, "The image will be resized."),
685
+ (logging.WARNING, "The image was resized to (1000 x 1500)."),
686
+ (logging.WARNING, "The image was resized to (500 x 750)."),
687
+ (logging.WARNING, "The image was resized to (100 x 150)."),
685
688
  ],
686
689
  ),
687
- # Image above the limits
690
+ # Image above the "long side in pixels" limit
688
691
  (
689
692
  None,
690
- 100000, # 100kB
691
- [(598, 900)],
693
+ 2000,
694
+ None,
695
+ [(1333, 2000), (667, 1000), (133, 200)],
692
696
  [
693
- (logging.WARNING, "The image was resized to (1992 x 3000)."),
694
- (logging.WARNING, "The image size is 773.4 kB."),
695
- (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
697
+ (logging.INFO, "This element's image dimensions are (2000 x 3000)."),
698
+ (
699
+ logging.WARNING,
700
+ "Maximum image dimensions supported are (2000 x 2000).",
701
+ ),
696
702
  (logging.WARNING, "The image will be resized."),
697
- (logging.WARNING, "The image was resized to (1793 x 2700)."),
698
- (logging.WARNING, "The image size is 616.0 kB."),
703
+ (logging.WARNING, "The image was resized to (1333 x 2000)."),
704
+ (logging.WARNING, "The image was resized to (667 x 1000)."),
705
+ (logging.WARNING, "The image was resized to (133 x 200)."),
706
+ ],
707
+ ),
708
+ # Image above the "size in bytes" limit
709
+ (
710
+ None,
711
+ None,
712
+ 100000, # 100kB
713
+ [(200, 300)],
714
+ [
715
+ (logging.INFO, "This element's image dimensions are (2000 x 3000)."),
716
+ (logging.WARNING, "The image size is 1.3 MB."),
699
717
  (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
700
718
  (logging.WARNING, "The image will be resized."),
701
- (logging.WARNING, "The image was resized to (1694 x 2550)."),
702
- (logging.WARNING, "The image size is 546.4 kB."),
719
+ (logging.WARNING, "The image was resized to (1000 x 1500)."),
720
+ (logging.WARNING, "The image size is 214.2 kB."),
703
721
  (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
704
722
  (logging.WARNING, "The image will be resized."),
705
- (logging.WARNING, "The image was resized to (1594 x 2400)."),
706
- (logging.WARNING, "The image size is 479.4 kB."),
707
- (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
723
+ (logging.WARNING, "The image was resized to (200 x 300)."),
724
+ ],
725
+ ),
726
+ # Image above all three limits
727
+ (
728
+ 1000,
729
+ 2000,
730
+ 100000, # 100kB
731
+ [(500, 750), (100, 150)],
732
+ [
733
+ (logging.INFO, "This element's image dimensions are (2000 x 3000)."),
734
+ (
735
+ logging.WARNING,
736
+ "Maximum image dimensions supported are (1000 x 2000).",
737
+ ),
708
738
  (logging.WARNING, "The image will be resized."),
709
- (logging.WARNING, "The image was resized to (1494 x 2250)."),
710
- (logging.WARNING, "The image size is 416.1 kB."),
739
+ (logging.WARNING, "The image was resized to (1000 x 1500)."),
740
+ (logging.WARNING, "The image size is 214.2 kB."),
711
741
  (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
712
742
  (logging.WARNING, "The image will be resized."),
713
- (logging.WARNING, "The image was resized to (1395 x 2100)."),
714
- (logging.WARNING, "The image size is 360.5 kB."),
715
- (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
743
+ (logging.WARNING, "The image was resized to (500 x 750)."),
744
+ (logging.WARNING, "The image was resized to (100 x 150)."),
745
+ ],
746
+ ),
747
+ # Image always above all three limits
748
+ (
749
+ 50,
750
+ 50,
751
+ 50, # 50B
752
+ [],
753
+ [
754
+ (logging.INFO, "This element's image dimensions are (2000 x 3000)."),
755
+ (logging.WARNING, "Maximum image dimensions supported are (50 x 50)."),
716
756
  (logging.WARNING, "The image will be resized."),
717
- (logging.WARNING, "The image was resized to (1195 x 1800)."),
718
- (logging.WARNING, "The image size is 258.6 kB."),
719
- (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
757
+ (logging.WARNING, "The image was resized to (33 x 50)."),
758
+ (logging.WARNING, "The image size is 1.0 kB."),
759
+ (logging.WARNING, "Maximum image input size supported is 50 Bytes."),
720
760
  (logging.WARNING, "The image will be resized."),
721
- (logging.WARNING, "The image was resized to (996 x 1500)."),
722
- (logging.WARNING, "The image size is 179.0 kB."),
723
- (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
761
+ (logging.WARNING, "The image was resized to (17 x 25)."),
762
+ (logging.WARNING, "The image size is 785 Bytes."),
763
+ (logging.WARNING, "Maximum image input size supported is 50 Bytes."),
724
764
  (logging.WARNING, "The image will be resized."),
725
- (logging.WARNING, "The image was resized to (797 x 1200)."),
726
- (logging.WARNING, "The image size is 115.7 kB."),
727
- (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
765
+ (logging.WARNING, "The image was resized to (3 x 5)."),
766
+ (logging.WARNING, "The image size is 689 Bytes."),
767
+ (logging.WARNING, "Maximum image input size supported is 50 Bytes."),
728
768
  (logging.WARNING, "The image will be resized."),
729
- (logging.WARNING, "The image was resized to (598 x 900)."),
730
769
  ],
731
770
  ),
732
- # Image above the limits
771
+ ],
772
+ )
773
+ def test_resized_images_portrait_format(
774
+ monkeypatch,
775
+ max_pixels_short,
776
+ max_pixels_long,
777
+ max_bytes,
778
+ expected_sizes,
779
+ expected_logs,
780
+ mock_page,
781
+ caplog,
782
+ ):
783
+ monkeypatch.setattr(arkindex_worker.image, "IMAGE_RATIOS", [1.0, 0.5, 0.1])
784
+
785
+ # Short side is the width, long side is the height
786
+ assert mock_page.zone.image.width < mock_page.zone.image.height
787
+
788
+ assert [
789
+ Image.open(image).size
790
+ for image in resized_images(
791
+ element=mock_page,
792
+ max_pixels_short=max_pixels_short,
793
+ max_pixels_long=max_pixels_long,
794
+ max_bytes=max_bytes,
795
+ )
796
+ ] == expected_sizes
797
+
798
+ assert [
799
+ (record.levelno, record.message) for record in caplog.records
800
+ ] == expected_logs
801
+
802
+
803
+ @pytest.mark.parametrize(
804
+ ("max_pixels_short", "max_pixels_long", "expected_sizes", "expected_logs"),
805
+ [
806
+ # Image above the "short side in pixels" limit
733
807
  (
734
- 2000,
808
+ 1000,
735
809
  None,
736
- [(1328, 2000), (1195, 1800), (996, 1500), (797, 1200), (598, 900)],
810
+ [(1500, 1000), (750, 500), (150, 100)],
737
811
  [
812
+ (logging.INFO, "This element's image dimensions are (3000 x 2000)."),
738
813
  (
739
814
  logging.WARNING,
740
- "Maximum image input size supported is (2000 x 2000).",
815
+ "Maximum image dimensions supported are (3000 x 1000).",
741
816
  ),
742
817
  (logging.WARNING, "The image will be resized."),
743
- (logging.WARNING, "The image was resized to (1328 x 2000)."),
744
- (logging.WARNING, "The image was resized to (1195 x 1800)."),
745
- (logging.WARNING, "The image was resized to (996 x 1500)."),
746
- (logging.WARNING, "The image was resized to (797 x 1200)."),
747
- (logging.WARNING, "The image was resized to (598 x 900)."),
818
+ (logging.WARNING, "The image was resized to (1500 x 1000)."),
819
+ (logging.WARNING, "The image was resized to (750 x 500)."),
820
+ (logging.WARNING, "The image was resized to (150 x 100)."),
748
821
  ],
749
822
  ),
750
- # Image above the limits
823
+ # Image above the "long side in pixels" limit
751
824
  (
825
+ None,
752
826
  2000,
753
- 100000, # 100kB
754
- [(598, 900)],
827
+ [(2000, 1333), (1000, 667), (200, 133)],
755
828
  [
829
+ (logging.INFO, "This element's image dimensions are (3000 x 2000)."),
756
830
  (
757
831
  logging.WARNING,
758
- "Maximum image input size supported is (2000 x 2000).",
832
+ "Maximum image dimensions supported are (2000 x 2000).",
759
833
  ),
760
834
  (logging.WARNING, "The image will be resized."),
761
- (logging.WARNING, "The image was resized to (1328 x 2000)."),
762
- (logging.WARNING, "The image size is 325.5 kB."),
763
- (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
764
- (logging.WARNING, "The image will be resized."),
765
- (logging.WARNING, "The image was resized to (1195 x 1800)."),
766
- (logging.WARNING, "The image size is 258.6 kB."),
767
- (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
768
- (logging.WARNING, "The image will be resized."),
769
- (logging.WARNING, "The image was resized to (996 x 1500)."),
770
- (logging.WARNING, "The image size is 179.0 kB."),
771
- (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
772
- (logging.WARNING, "The image will be resized."),
773
- (logging.WARNING, "The image was resized to (797 x 1200)."),
774
- (logging.WARNING, "The image size is 115.7 kB."),
775
- (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
776
- (logging.WARNING, "The image will be resized."),
777
- (logging.WARNING, "The image was resized to (598 x 900)."),
835
+ (logging.WARNING, "The image was resized to (2000 x 1333)."),
836
+ (logging.WARNING, "The image was resized to (1000 x 667)."),
837
+ (logging.WARNING, "The image was resized to (200 x 133)."),
778
838
  ],
779
839
  ),
780
- # Image always above the limits
840
+ # Image above the two pixels limits
781
841
  (
782
- 50,
783
- 50, # 50B
784
- [],
842
+ 1000,
843
+ 2000,
844
+ [(1500, 1000), (750, 500), (150, 100)],
785
845
  [
786
- (logging.WARNING, "Maximum image input size supported is (50 x 50)."),
787
- (logging.WARNING, "The image will be resized."),
788
- (logging.WARNING, "The image was resized to (33 x 50)."),
789
- (logging.WARNING, "The image size is 1.0 kB."),
790
- (logging.WARNING, "Maximum image input size supported is 50 Bytes."),
846
+ (logging.INFO, "This element's image dimensions are (3000 x 2000)."),
847
+ (
848
+ logging.WARNING,
849
+ "Maximum image dimensions supported are (2000 x 1000).",
850
+ ),
791
851
  (logging.WARNING, "The image will be resized."),
852
+ (logging.WARNING, "The image was resized to (1500 x 1000)."),
853
+ (logging.WARNING, "The image was resized to (750 x 500)."),
854
+ (logging.WARNING, "The image was resized to (150 x 100)."),
792
855
  ],
793
856
  ),
794
857
  ],
795
858
  )
796
- def test_resized_images(
797
- max_pixels, max_bytes, expected_sizes, expected_logs, mock_page, caplog
859
+ def test_resized_images_landscape_format(
860
+ monkeypatch,
861
+ max_pixels_short,
862
+ max_pixels_long,
863
+ expected_sizes,
864
+ expected_logs,
865
+ mock_page,
866
+ caplog,
798
867
  ):
799
- caplog.set_level(logging.WARNING)
868
+ monkeypatch.setattr(arkindex_worker.image, "IMAGE_RATIOS", [1.0, 0.5, 0.1])
869
+
870
+ # Short side is the height, long side is the width
871
+ mock_page.zone = {
872
+ "polygon": [[0, 0], [3000, 0], [3000, 2000], [0, 2000], [0, 0]],
873
+ "image": {"width": 3000, "height": 2000},
874
+ }
875
+ assert mock_page.zone.image.height < mock_page.zone.image.width
800
876
 
801
877
  assert [
802
878
  Image.open(image).size
803
879
  for image in resized_images(
804
- element=mock_page, max_pixels=max_pixels, max_bytes=max_bytes
880
+ element=mock_page,
881
+ max_pixels_short=max_pixels_short,
882
+ max_pixels_long=max_pixels_long,
883
+ max_bytes=None,
805
884
  )
806
885
  ] == expected_sizes
886
+
807
887
  assert [
808
888
  (record.levelno, record.message) for record in caplog.records
809
889
  ] == expected_logs
890
+
891
+
892
+ def test_resized_images_use_base64(monkeypatch, mock_page, caplog):
893
+ monkeypatch.setattr(arkindex_worker.image, "IMAGE_RATIOS", [1.0, 0.5, 0.25, 0.1])
894
+
895
+ assert list(
896
+ map(
897
+ len,
898
+ resized_images(
899
+ element=mock_page,
900
+ max_pixels_short=None,
901
+ max_pixels_long=None,
902
+ max_bytes=100000,
903
+ use_base64=True,
904
+ ),
905
+ )
906
+ ) == [65280, 11892]
907
+
908
+ assert [(record.levelno, record.message) for record in caplog.records] == [
909
+ (logging.INFO, "This element's image dimensions are (2000 x 3000)."),
910
+ (logging.WARNING, "The image size is 1.7 MB."),
911
+ (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
912
+ (logging.WARNING, "The image will be resized."),
913
+ (logging.WARNING, "The image was resized to (1000 x 1500)."),
914
+ (logging.WARNING, "The image size is 285.6 kB."),
915
+ (logging.WARNING, "Maximum image input size supported is 100.0 kB."),
916
+ (logging.WARNING, "The image will be resized."),
917
+ (logging.WARNING, "The image was resized to (500 x 750)."),
918
+ (logging.WARNING, "The image was resized to (200 x 300)."),
919
+ ]
tests/test_utils.py CHANGED
@@ -1,5 +1,8 @@
1
+ import logging
2
+
1
3
  import pytest
2
4
 
5
+ from arkindex_worker.cache import unsupported_cache
3
6
  from arkindex_worker.utils import (
4
7
  DEFAULT_BATCH_SIZE,
5
8
  batch_publication,
@@ -58,10 +61,24 @@ def test_close_delete_file(tmp_path):
58
61
 
59
62
 
60
63
  class TestMixin:
64
+ def __init__(self, use_cache: bool = False):
65
+ """
66
+ Args:
67
+ use_cache (bool, optional): To mock BaseWorker.use_cache attribute. Defaults to False.
68
+ """
69
+ self.use_cache = use_cache
70
+
61
71
  @batch_publication
62
72
  def custom_publication_in_batches(self, batch_size: int = DEFAULT_BATCH_SIZE):
63
73
  return batch_size
64
74
 
75
+ @unsupported_cache
76
+ @batch_publication
77
+ def custom_publication_in_batches_without_cache(
78
+ self, batch_size: int = DEFAULT_BATCH_SIZE
79
+ ):
80
+ return batch_size
81
+
65
82
 
66
83
  def test_batch_publication_decorator_no_parameter():
67
84
  assert TestMixin().custom_publication_in_batches() == DEFAULT_BATCH_SIZE
@@ -81,3 +98,23 @@ def test_batch_publication_decorator_right_parameter(batch_size):
81
98
  assert (
82
99
  TestMixin().custom_publication_in_batches(batch_size=batch_size) == batch_size
83
100
  )
101
+
102
+
103
+ def test_batch_publication_decorator_alongside_unsupported_cache(caplog):
104
+ # Capture log messages
105
+ caplog.clear()
106
+ with caplog.at_level(logging.WARNING):
107
+ # Call the helper
108
+ assert (
109
+ TestMixin(use_cache=True).custom_publication_in_batches_without_cache()
110
+ == DEFAULT_BATCH_SIZE
111
+ )
112
+
113
+ # Check logs
114
+ assert caplog.record_tuples == [
115
+ (
116
+ "arkindex_worker",
117
+ logging.WARNING,
118
+ "This API helper `custom_publication_in_batches_without_cache` did not update the cache database",
119
+ ),
120
+ ]