Repository: SmileyChris/easy-thumbnails

Issue:
svglib dependency is missing
After updating my project with `pip-compile` and `pip-sync` ` easy-thumbnails` is bumped to 2.8.2 and `svglib` removed:

```
diff --git a/requirements.txt b/requirements.txt
[…]
-easy-thumbnails==2.8.1
+easy-thumbnails==2.8.2
     # via
     #   -r requirements.in
     #   aldryn-people
[…]
-svglib==1.3.0
-    # via easy-thumbnails
[…]
```

This leads to an error because in `VIL/Image.py`  there’s an import from `svglib`:

```
  File "/home/jens/.virtualenvs/djangocms3.9/lib/python3.9/site-packages/easy_thumbnails/VIL/Image.py", line 10, in <module>
    from svglib.svglib import svg2rlg
ModuleNotFoundError: No module named 'svglib'
```

Adding `svglib` to `requirements.in` and running `pip-compile && pip-sync` fixes the problem, but the dependencies in `easy-thumbnails` should be fixed.


Discussion:

Patch:
diff --git a/easy_thumbnails/VIL/__init__.py b/easy_thumbnails/VIL/__init__.py
index e69de29..f924c82 100644
--- a/easy_thumbnails/VIL/__init__.py
+++ b/easy_thumbnails/VIL/__init__.py
@@ -0,0 +1,9 @@
+def is_available() -> bool:
+    """
+    Returns True if SVG support should be available.
+    """
+    try:
+        import easy_thumbnails.VIL.Image
+        return True
+    except ImportError:
+        return False
\ No newline at end of file
diff --git a/easy_thumbnails/files.py b/easy_thumbnails/files.py
index 6519783..4925319 100644
--- a/easy_thumbnails/files.py
+++ b/easy_thumbnails/files.py
@@ -14,7 +14,6 @@ from easy_thumbnails import engine, exceptions, models, utils, signals, storage
 from easy_thumbnails.alias import aliases
 from easy_thumbnails.conf import settings
 from easy_thumbnails.options import ThumbnailOptions
-from easy_thumbnails.VIL.Image import load
 
 
 def get_thumbnailer(obj, relative_name=None):
@@ -118,6 +117,7 @@ def database_get_image_dimensions(file, close=False, dimensions=None):
         if dimensions_cache:
             return dimensions_cache.width, dimensions_cache.height
     if os.path.splitext(file.file.name)[1] == '.svg':
+        from easy_thumbnails.VIL.Image import load
         dimensions = load(file.path).size
     else:
         dimensions = get_image_dimensions(file, close=close)
diff --git a/tox.ini b/tox.ini
index dc15d41..7dcdfab 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,9 +1,8 @@
 [tox]
 distribute = False
 envlist =
-    py{36,37,38,39}-django{22,30,31,32}
-    py310-django32
-    py310-django40
+    py{36,37,38,39}-django{22,30,31,32}{-svg,}
+    py310-django{32,40}{-svg,}
 skip_missing_interpreters = True
 
 [gh-actions]
@@ -18,7 +17,8 @@ python =
 setenv =
     DJANGO_SETTINGS_MODULE=easy_thumbnails.tests.settings
 usedevelop = True
-extras = svg
+extras =
+    svg: svg
 deps =
     django22: Django<2.3
     django30: Django<3.1


Test patch:
diff --git a/easy_thumbnails/tests/test_svg_processors.py b/easy_thumbnails/tests/test_svg_processors.py
index 6d9e46f..bfafc66 100644
--- a/easy_thumbnails/tests/test_svg_processors.py
+++ b/easy_thumbnails/tests/test_svg_processors.py
@@ -1,10 +1,11 @@
-from easy_thumbnails.VIL import Image, ImageDraw
-from easy_thumbnails import processors
-from reportlab.lib.colors import Color
-from unittest import TestCase
+import unittest
+from easy_thumbnails import processors, VIL
 
 
 def create_image(mode='RGB', size=(800, 600)):
+    from easy_thumbnails.VIL import Image, ImageDraw
+    from reportlab.lib.colors import Color
+
     image = Image.new(mode, size, (255, 255, 255))
     draw = ImageDraw.Draw(image)
     x_bit, y_bit = size[0] // 10, size[1] // 10
@@ -13,7 +14,8 @@ def create_image(mode='RGB', size=(800, 600)):
     return image
 
 
-class ScaleAndCropTest(TestCase):
+@unittest.skipUnless(VIL.is_available(), "SVG support not available")
+class ScaleAndCropTest(unittest.TestCase):
     def test_scale(self):
         image = create_image()
 
diff --git a/easy_thumbnails/tests/test_templatetags.py b/easy_thumbnails/tests/test_templatetags.py
index 9fb30c2..2f375bf 100644
--- a/easy_thumbnails/tests/test_templatetags.py
+++ b/easy_thumbnails/tests/test_templatetags.py
@@ -1,4 +1,5 @@
 import tempfile
+import unittest
 from pathlib import Path
 
 from django.template import Template, Context, TemplateSyntaxError
@@ -9,6 +10,7 @@ from easy_thumbnails import alias, storage
 from easy_thumbnails.conf import settings
 from easy_thumbnails.files import get_thumbnailer
 from easy_thumbnails.tests import utils as test
+from easy_thumbnails import VIL
 
 
 class Base(test.BaseTest):
@@ -368,6 +370,7 @@ class ThumbnailerDataUriTest(ThumbnailerBase):
         self.assertEqual(output, startswith)
 
 
+@unittest.skipUnless(VIL.is_available(), "SVG support not available")
 class ThumbnailSVGImage(test.BaseTest):
 
     def setUp(self):
diff --git a/easy_thumbnails/tests/utils.py b/easy_thumbnails/tests/utils.py
index 2430645..1cf5d82 100644
--- a/easy_thumbnails/tests/utils.py
+++ b/easy_thumbnails/tests/utils.py
@@ -119,10 +119,10 @@ class BaseTest(TestCase):
         will be passed instead.
         """
         if image_format == 'SVG':
-            Image = import_string('easy_thumbnails.VIL.Image')
+            from easy_thumbnails.VIL import Image
             data = StringIO()
         else:
-            Image = import_string('PIL.Image')
+            from PIL import Image
             data = BytesIO()
         with Image.new(image_mode, size) as img:
             img.save(data, image_format)