[packages/python3-blockdiag] - apply fixes for Pillow 10+ and pytest instead of nose; release 2
qboosh
qboosh at pld-linux.org
Sun Jul 13 09:21:30 CEST 2025
commit 3dd34b69204cdde79ba5b74366ab4bf1217bd154
Author: Jakub Bogusz <qboosh at pld-linux.org>
Date: Sun Jul 13 09:23:02 2025 +0200
- apply fixes for Pillow 10+ and pytest instead of nose; release 2
blockdiag-pillow10-setup.patch | 12 +++
blockdiag-pillow10.patch | 117 +++++++++++++++++++++++++
blockdiag-pytest.patch | 195 +++++++++++++++++++++++++++++++++++++++++
python3-blockdiag.spec | 50 +++++++----
4 files changed, 355 insertions(+), 19 deletions(-)
---
diff --git a/python3-blockdiag.spec b/python3-blockdiag.spec
index 90d4fa6..90a2fec 100644
--- a/python3-blockdiag.spec
+++ b/python3-blockdiag.spec
@@ -1,33 +1,39 @@
#
# Conditional build:
-%bcond_with tests # unit tests
+%bcond_without tests # unit tests
%define module blockdiag
Summary: Blockdiag generate block-diagram image file from spec-text file
Summary(pl.UTF-8): Generowanie obrazków diagramów blokowych z opisu tekstowego
Name: python3-%{module}
Version: 3.0.0
-Release: 1
+Release: 2
License: Apache v2.0
Group: Libraries/Python
#Source0Download: https://pypi.org/simple/blockdiag/
Source0: https://files.pythonhosted.org/packages/source/b/blockdiag/%{module}-%{version}.tar.gz
# Source0-md5: e1bfc69b83254ad3565c572ff4b3ad97
-URL: http://blockdiag.com/en/blockdiag/index.html
-BuildRequires: python3-modules >= 1:3.5
+# https://github.com/blockdiag/blockdiag/pull/175.patch
+Patch0: blockdiag-pytest.patch
+# https://github.com/blockdiag/blockdiag/pull/179.patch
+Patch1: blockdiag-pillow10.patch
+Patch2: blockdiag-pillow10-setup.patch
+URL: http://blockdiag.com/
+BuildRequires: python3-build
+BuildRequires: python3-installer
+BuildRequires: python3-modules >= 1:3.7
BuildRequires: python3-setuptools
%if %{with tests}
BuildRequires: python3-docutils
-BuildRequires: python3-funcparserlib
-#BuildRequires: python3-nose
-#BuildRequires: python3-nose_exclude
-BuildRequires: python3-pillow >= 3.0
+BuildRequires: python3-funcparserlib >= 1.0.0
+BuildRequires: python3-pillow >= 3.1.0
+BuildRequires: python3-pytest
BuildRequires: python3-reportlab
BuildRequires: python3-webcolors
%endif
BuildRequires: rpmbuild(macros) >= 1.714
BuildRequires: sed >= 4.0
-Requires: python3-modules >= 1:3.5
+Requires: python3-modules >= 1:3.7
BuildArch: noarch
BuildRoot: %{tmpdir}/%{name}-%{version}-root-%(id -u -n)
@@ -48,25 +54,31 @@ Funkcje:
%prep
%setup -q -n %{module}-%{version}
+%patch -P0 -p1
+%patch -P1 -p1
+%patch -P2 -p1
+
+# contains Pillow<10 dependency
+%{__rm} -r src/blockdiag.egg-info
%build
-%py3_build
+# although project uses just setup.py, use PEP-517 build in order to get metadata for tests
+%py3_build_pyproject
%if %{with tests}
-# disable tests requiring network: test_command.TestBlockdiagApp.test_app_cleans_up_images, test_generate_diagram.test_generate, test_generate_diagram.ghostscript_not_found_test
-# test_setup_inline_svg_is_true_with_multibytes fails on utf-8 vs latin-1 inconsistency
-#nosetests-%{py3_ver} src/blockdiag/tests -e 'test_app_cleans_up_images|test_generate|ghostscript_not_found_test|test_setup_inline_svg_is_true_with_multibytes'
-# use explicit plugins list for reliable builds (delete PYTEST_PLUGINS if empty)
-PYTHONPATH=$(pwd)/src \
+%{__python3} -m zipfile -e build-3/*.whl build-3-test
+# disable tests requiring network:
+# test_command.py::TestBlockdiagApp::test_app_cleans_up_images
+# test_generate_diagram.py::test_generate_with_separate[.../diagrams/node_icon.diag-svg-options260]
+PYTHONPATH=$(pwd)/build-3-test \
PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 \
-PYTEST_PLUGINS= \
-%{__python3} -m pytest src/blockdiag/tests
+%{__python3} -m pytest src/blockdiag/tests -k 'not test_app_cleans_up_images and not test_generate_with_separate'
%endif
%install
rm -rf $RPM_BUILD_ROOT
-%py3_install
+%py3_install_pyproject
%{__rm} -r $RPM_BUILD_ROOT%{py3_sitescriptdir}/blockdiag/tests
@@ -85,6 +97,6 @@ rm -rf $RPM_BUILD_ROOT
%attr(755,root,root) %{_bindir}/blockdiag
%attr(755,root,root) %{_bindir}/blockdiag-3
%{py3_sitescriptdir}/blockdiag
-%{py3_sitescriptdir}/%{module}-%{version}-py*.egg-info
+%{py3_sitescriptdir}/blockdiag-%{version}.dist-info
%{_mandir}/man1/blockdiag.1*
%{_mandir}/man1/blockdiag-3.1*
diff --git a/blockdiag-pillow10-setup.patch b/blockdiag-pillow10-setup.patch
new file mode 100644
index 0000000..175519d
--- /dev/null
+++ b/blockdiag-pillow10-setup.patch
@@ -0,0 +1,12 @@
+--- blockdiag-3.0.0/setup.py.orig 2025-07-13 08:33:43.082657681 +0200
++++ blockdiag-3.0.0/setup.py 2025-07-13 08:35:30.948739986 +0200
+@@ -54,7 +54,7 @@ setup(
+ install_requires=[
+ 'setuptools',
+ 'funcparserlib>=1.0.0a0',
+- 'Pillow > 3.0, < 10.0',
++ 'Pillow > 3.0',
+ 'webcolors',
+ ],
+ extras_require={
+
diff --git a/blockdiag-pillow10.patch b/blockdiag-pillow10.patch
new file mode 100644
index 0000000..e45c96b
--- /dev/null
+++ b/blockdiag-pillow10.patch
@@ -0,0 +1,117 @@
+From 20d780cad84e7b010066cb55f848477957870165 Mon Sep 17 00:00:00 2001
+From: Theodore Ni <3806110+tjni at users.noreply.github.com>
+Date: Sat, 5 Aug 2023 10:43:46 -0700
+Subject: [PATCH] Add support for Pillow 10
+
+Fix a bunch of breaking changes in a backwards compatible way.
+---
+ src/blockdiag/imagedraw/png.py | 47 ++++++++++++++++++++++++++++------
+ 1 file changed, 39 insertions(+), 8 deletions(-)
+
+diff --git a/src/blockdiag/imagedraw/png.py b/src/blockdiag/imagedraw/png.py
+index 3cac05a..12f0514 100644
+--- a/src/blockdiag/imagedraw/png.py
++++ b/src/blockdiag/imagedraw/png.py
+@@ -30,6 +30,21 @@
+ from blockdiag.utils.myitertools import istep, stepslice
+
+
++# to support pillow < 9.1.0
++if not hasattr(Image, 'Resampling'):
++ from enum import IntEnum
++
++ class Resampling(IntEnum):
++ NEAREST = 0
++ BOX = 4
++ BILINEAR = 2
++ HAMMING = 5
++ BICUBIC = 3
++ LANCZOS = 1
++
++ Image.Resampling = Resampling
++
++
+ def point_pairs(xylist):
+ iterable = iter(xylist)
+ for pt in iterable:
+@@ -147,7 +162,7 @@ def set_canvas_size(self, size):
+ self.draw = ImageDraw.Draw(self._image)
+
+ def resizeCanvas(self, size):
+- self._image = self._image.resize(size, Image.ANTIALIAS)
++ self._image = self._image.resize(size, Image.Resampling.LANCZOS)
+ self.draw = ImageDraw.Draw(self._image)
+
+ def arc(self, box, start, end, **kwargs):
+@@ -273,13 +288,21 @@ def textfolder(self):
+ def textlinesize(self, string, font):
+ ttfont = ttfont_for(font)
+ if ttfont is None:
+- size = self.draw.textsize(string, font=None)
++ if hasattr(self.draw, 'textbbox'):
++ left, top, right, bottom = self.draw.textbbox((0, 0), string)
++ size = (right - left, bottom - top)
++ else:
++ size = self.draw.textsize(string, font=None)
+
+ font_ratio = font.size * 1.0 / FontMap.BASE_FONTSIZE
+ size = Size(int(size[0] * font_ratio),
+ int(size[1] * font_ratio))
+ else:
+- size = Size(*ttfont.getsize(string))
++ if hasattr(ttfont, 'getbbox'):
++ left, top, right, bottom = ttfont.getbbox(string)
++ size = Size(right - left, bottom - top)
++ else:
++ size = Size(*ttfont.getsize(string))
+
+ return size
+
+@@ -291,7 +314,11 @@ def text(self, xy, string, font, **kwargs):
+ if self.scale_ratio == 1 and font.size == FontMap.BASE_FONTSIZE:
+ self.draw.text(xy, string, fill=fill)
+ else:
+- size = self.draw.textsize(string)
++ if hasattr(self.draw, 'textbbox'):
++ left, top, right, bottom = self.draw.textbbox((0, 0), string)
++ size = (right - left, bottom - top)
++ else:
++ size = self.draw.textsize(string)
+ image = Image.new('RGBA', size)
+ draw = ImageDraw.Draw(image)
+ draw.text((0, 0), string, fill=fill)
+@@ -299,10 +326,14 @@ def text(self, xy, string, font, **kwargs):
+
+ basesize = (size[0] * self.scale_ratio,
+ size[1] * self.scale_ratio)
+- text_image = image.resize(basesize, Image.ANTIALIAS)
++ text_image = image.resize(basesize, Image.Resampling.LANCZOS)
+ self.paste(text_image, xy, text_image)
+ else:
+- size = ttfont.getsize(string)
++ if hasattr(ttfont, 'getbbox'):
++ left, top, right, bottom = ttfont.getbbox(string)
++ size = (right - left, bottom - top)
++ else:
++ size = ttfont.getsize(string)
+
+ # Generate mask to support BDF(bitmap font)
+ mask = Image.new('1', size)
+@@ -370,7 +401,7 @@ def image(self, box, url):
+ # resize image.
+ w = min([box.width, image.size[0] * self.scale_ratio])
+ h = min([box.height, image.size[1] * self.scale_ratio])
+- image.thumbnail((w, h), Image.ANTIALIAS)
++ image.thumbnail((w, h), Image.Resampling.LANCZOS)
+
+ # centering image.
+ w, h = image.size
+@@ -404,7 +435,7 @@ def save(self, filename, size, _format):
+ y = int(self._image.size[1] / self.scale_ratio)
+ size = (x, y)
+
+- self._image.thumbnail(size, Image.ANTIALIAS)
++ self._image.thumbnail(size, Image.Resampling.LANCZOS)
+
+ if self.filename:
+ self._image.save(self.filename, _format)
diff --git a/blockdiag-pytest.patch b/blockdiag-pytest.patch
new file mode 100644
index 0000000..6061779
--- /dev/null
+++ b/blockdiag-pytest.patch
@@ -0,0 +1,195 @@
+From c1dd1a4427f6158dd653cdfaa9368a2746b02747 Mon Sep 17 00:00:00 2001
+From: Guillaume Grossetie <ggrossetie at yuzutech.fr>
+Date: Sun, 9 Jul 2023 23:31:11 +0200
+Subject: [PATCH 1/2] Blockdiag is incompatible with Pillow 3.10
+
+---
+ setup.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/setup.py b/setup.py
+index ece3ae4..27ef5f2 100644
+--- a/setup.py
++++ b/setup.py
+@@ -54,7 +54,7 @@ def get_version():
+ install_requires=[
+ 'setuptools',
+ 'funcparserlib>=1.0.0a0',
+- 'Pillow > 3.0',
++ 'Pillow > 3.0, < 10.0',
+ 'webcolors',
+ ],
+ extras_require={
+
+From 4f4f726252084f17ecc6c524592222af09d37da4 Mon Sep 17 00:00:00 2001
+From: Guillaume Grossetie <ggrossetie at yuzutech.fr>
+Date: Mon, 10 Jul 2023 00:31:37 +0200
+Subject: [PATCH 2/2] Switch to pytest (nose is unmaintained and does not work
+ on Python3.10)
+
+---
+ setup.py | 3 +-
+ src/blockdiag/tests/test_generate_diagram.py | 95 ++++++++++----------
+ tox.ini | 2 +-
+ 3 files changed, 49 insertions(+), 51 deletions(-)
+
+diff --git a/setup.py b/setup.py
+index 27ef5f2..33f6e26 100644
+--- a/setup.py
++++ b/setup.py
+@@ -65,7 +65,7 @@ def get_version():
+ 'docutils'
+ ],
+ 'testing': [
+- 'nose',
++ 'pytest',
+ 'flake8',
+ 'flake8-coding',
+ 'flake8-copyright',
+@@ -74,7 +74,6 @@ def get_version():
+ 'docutils',
+ ],
+ },
+- test_suite='nose.collector',
+ entry_points="""
+ [console_scripts]
+ blockdiag = blockdiag.command:main
+diff --git a/src/blockdiag/tests/test_generate_diagram.py b/src/blockdiag/tests/test_generate_diagram.py
+index a212d89..cc22896 100644
+--- a/src/blockdiag/tests/test_generate_diagram.py
++++ b/src/blockdiag/tests/test_generate_diagram.py
+@@ -19,7 +19,7 @@
+ import unittest
+ from xml.etree import ElementTree
+
+-from nose.tools import nottest
++import pytest
+
+ import blockdiag
+ import blockdiag.command
+@@ -46,66 +46,65 @@ def get_diagram_files(testdir):
+ yield os.path.join(diagramsdir, file)
+
+
+-def test_generate():
+- mainfunc = blockdiag.command.main
+- basepath = os.path.dirname(__file__)
+- files = get_diagram_files(basepath)
+- options = []
++base_path = os.path.dirname(__file__)
++files = get_diagram_files(base_path)
++generate_testdata = []
++generate_with_separate_testdata = []
++for file_source in files:
++ generate_testdata.append((file_source, 'svg', []))
++ generate_testdata.append((file_source, 'png', []))
++ generate_testdata.append((file_source, 'png', ['--antialias']))
++ generate_testdata.append((file_source, 'pdf', []))
++ if re.search('separate', file_source):
++ generate_with_separate_testdata.append((file_source, 'svg', ['--separate']))
++ generate_with_separate_testdata.append((file_source, 'png', ['--separate']))
++ generate_with_separate_testdata.append((file_source, 'png', ['--separate', '--antialias']))
++ generate_with_separate_testdata.append((file_source, 'pdf', ['--separate']))
+
+- for testcase in testcase_generator(basepath, mainfunc, files, options):
+- yield testcase
+
++ at pytest.mark.parametrize("source,file_type,options", generate_with_separate_testdata)
++def test_generate_with_separate_option(source, file_type, options):
++ generate(source, file_type, options)
+
+-def test_generate_with_separate():
+- mainfunc = blockdiag.command.main
+- basepath = os.path.dirname(__file__)
+- files = get_diagram_files(basepath)
+- filtered = (f for f in files if re.search('separate', f))
+- options = ['--separate']
+
+- for testcase in testcase_generator(basepath, mainfunc, filtered, options):
+- yield testcase
++ at pytest.mark.parametrize("source,file_type,options", generate_testdata)
++def test_generate_with_separate(source, file_type, options):
++ generate(source, file_type, options)
+
+
+- at nottest
+-def testcase_generator(basepath, mainfunc, files, options):
+- fontpath = get_fontpath(basepath)
+- options = options + ['-f', fontpath]
+-
+- for source in files:
+- yield generate, mainfunc, 'svg', source, options
+-
++ at capture_stderr
++def generate(source, file_type, options):
++ if file_type == 'png':
+ if not supported_pil():
+- yield unittest.skip("Pillow is not available")(generate)
+- yield unittest.skip("Pillow is not available")(generate)
+- elif os.environ.get('ALL_TESTS') is None:
+- message = "Skipped by default. To enable it, specify $ALL_TESTS=1"
+- yield unittest.skip(message)(generate)
+- yield unittest.skip(message)(generate)
+- else:
+- yield generate, mainfunc, 'png', source, options
+- yield generate, mainfunc, 'png', source, options + ['--antialias']
+-
++ unittest.skip('Pillow is not available')
++ return
++ if os.environ.get('ALL_TESTS') is None:
++ unittest.skip('Skipped by default. To enable it, specify $ALL_TESTS=1')
++ return
++ elif file_type == 'pdf':
+ if not supported_pdf():
+- yield unittest.skip("reportlab is not available")(generate)
+- elif os.environ.get('ALL_TESTS') is None:
+- message = "Skipped by default. To enable it, specify $ALL_TESTS=1"
+- yield unittest.skip(message)(generate)
+- else:
+- yield generate, mainfunc, 'pdf', source, options
++ unittest.skip('reportlab is not available')
++ return
++ if os.environ.get('ALL_TESTS') is None:
++ unittest.skip('Skipped by default. To enable it, specify $ALL_TESTS=1')
++ return
+
+-
+- at capture_stderr
+-def generate(mainfunc, filetype, source, options):
++ tmpdir = None
+ try:
+ tmpdir = TemporaryDirectory()
+- fd, tmpfile = tmpdir.mkstemp()
++ fd, tmp_file = tmpdir.mkstemp()
+ os.close(fd)
+-
+- mainfunc(['--debug', '-T', filetype, '-o', tmpfile, source] +
+- list(options))
++ blockdiag.command.main(
++ [
++ '--debug',
++ '-T',
++ file_type,
++ '-o', tmp_file, source
++ ] + list(options)
++ )
+ finally:
+- tmpdir.clean()
++ if tmpdir is not None:
++ tmpdir.clean()
+
+
+ def not_exist_font_config_option_test():
+diff --git a/tox.ini b/tox.ini
+index 0aafed8..aec660a 100644
+--- a/tox.ini
++++ b/tox.ini
+@@ -18,7 +18,7 @@ deps =
+ passenv =
+ ALL_TESTS
+ commands =
+- nosetests
++ pytest
+
+ [testenv:flake8]
+ description =
================================================================
---- gitweb:
http://git.pld-linux.org/gitweb.cgi/packages/python3-blockdiag.git/commitdiff/3dd34b69204cdde79ba5b74366ab4bf1217bd154
More information about the pld-cvs-commit
mailing list