From fe98ad09ff30f1b6cc5fd5dcc0769f9505c09166 Mon Sep 17 00:00:00 2001 From: Jim Easterbrook Date: Wed, 22 Oct 2025 08:44:03 +0100 Subject: [PATCH 1/2] Disable some refcount tests if Python >= 3.14 --- tests/test_basicio.py | 2 ++ tests/test_exif.py | 2 ++ tests/test_image.py | 4 +++- tests/test_iptc.py | 2 ++ tests/test_preview.py | 2 ++ tests/test_xmp.py | 2 ++ 6 files changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/test_basicio.py b/tests/test_basicio.py index e9232ee1..b8563d80 100644 --- a/tests/test_basicio.py +++ b/tests/test_basicio.py @@ -224,6 +224,8 @@ def test_MemIo(self): with self.assertWarns(DeprecationWarning): self.assertEqual(memoryview(io), self.data + b'+fred+jim') + @unittest.skipIf(sys.version_info >= (3, 14), + 'cannot test optimised ref counts') def test_ref_counts(self): # MemIo keeps a reference to the data buffer count = sys.getrefcount(self.data) diff --git a/tests/test_exif.py b/tests/test_exif.py index 958ff6e8..7af59870 100644 --- a/tests/test_exif.py +++ b/tests/test_exif.py @@ -310,6 +310,8 @@ def test_pointers(self): self.assertEqual(datum_pointer, datum) self.assertEqual(datum_pointer, datum_iter) + @unittest.skipIf(sys.version_info >= (3, 14), + 'cannot test optimised ref counts') def test_ref_counts(self): self.image.readMetadata() # exifData keeps a reference to image diff --git a/tests/test_image.py b/tests/test_image.py index 61bca8ab..691a400a 100644 --- a/tests/test_image.py +++ b/tests/test_image.py @@ -1,6 +1,6 @@ ## python-exiv2 - Python interface to libexiv2 ## http://github.com/jim-easterbrook/python-exiv2 -## Copyright (C) 2023-24 Jim Easterbrook jim@jim-easterbrook.me.uk +## Copyright (C) 2023-25 Jim Easterbrook jim@jim-easterbrook.me.uk ## ## This program is free software: you can redistribute it and/or ## modify it under the terms of the GNU General Public License as @@ -183,6 +183,8 @@ def test_ImageFactory(self): exiv2.ImageType, exiv2.ImageType.jpeg) self.assertIsInstance(factory.open(self.image_path), exiv2.Image) + @unittest.skipIf(sys.version_info >= (3, 14), + 'cannot test optimised ref counts') def test_ref_counts(self): # opening from data keeps reference to buffer self.assertEqual(sys.getrefcount(self.image_data), 2) diff --git a/tests/test_iptc.py b/tests/test_iptc.py index 04ed5e92..35b4723c 100644 --- a/tests/test_iptc.py +++ b/tests/test_iptc.py @@ -204,6 +204,8 @@ def test_IptcDatum(self): del datum2 self._test_datum(datum) + @unittest.skipIf(sys.version_info >= (3, 14), + 'cannot test optimised ref counts') def test_ref_counts(self): self.image.readMetadata() # iptcData keeps a reference to image diff --git a/tests/test_preview.py b/tests/test_preview.py index c1f7900c..476abbf4 100644 --- a/tests/test_preview.py +++ b/tests/test_preview.py @@ -116,6 +116,8 @@ def test_PreviewProperties(self): with self.assertRaises(TypeError): properties['fred'] = 123 + @unittest.skipIf(sys.version_info >= (3, 14), + 'cannot test optimised ref counts') def test_ref_counts(self): # manager keeps reference to image self.assertEqual(sys.getrefcount(self.image), 2) diff --git a/tests/test_xmp.py b/tests/test_xmp.py index 81857aae..6ce2b88b 100644 --- a/tests/test_xmp.py +++ b/tests/test_xmp.py @@ -246,6 +246,8 @@ def test_pointers(self): self.assertEqual(datum_pointer, datum) self.assertEqual(datum_pointer, datum_iter) + @unittest.skipIf(sys.version_info >= (3, 14), + 'cannot test optimised ref counts') def test_ref_counts(self): self.image.readMetadata() # xmpData keeps a reference to image From e0a5284620e8d020771bf8c1fa73d6113e662ebf Mon Sep 17 00:00:00 2001 From: Jim Easterbrook Date: Wed, 22 Oct 2025 09:04:45 +0100 Subject: [PATCH 2/2] Skip more refcount tests if Python >= 3.14 Python 3.14 introduced optimisation of refcounts so they aren't incremented if Python knows the object is not going to be deleted. Disabling these tests is temporary until I have a Python 3.14 installation on which to develop better tests. --- tests/test_image.py | 12 ++++++++---- tests/test_preview.py | 6 ++++-- tests/test_types.py | 6 ++++-- tests/test_value.py | 12 ++++++++---- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/tests/test_image.py b/tests/test_image.py index 691a400a..7b2dbd66 100644 --- a/tests/test_image.py +++ b/tests/test_image.py @@ -121,17 +121,21 @@ def test_Image(self): self.check_result(image.iccProfileDefined(), bool, False) # test data access image.readMetadata() - self.assertEqual(sys.getrefcount(image), 2) + if sys.version_info < (3, 14): + self.assertEqual(sys.getrefcount(image), 2) view = image.data() - self.assertEqual(sys.getrefcount(image), 3) + if sys.version_info < (3, 14): + self.assertEqual(sys.getrefcount(image), 3) self.check_result(view, memoryview, self.image_data) self.assertEqual(view.readonly, True) image.writeMetadata() - self.assertEqual(sys.getrefcount(image), 2) + if sys.version_info < (3, 14): + self.assertEqual(sys.getrefcount(image), 2) with self.assertRaises(ValueError): view[0] del view - self.assertEqual(sys.getrefcount(image), 2) + if sys.version_info < (3, 14): + self.assertEqual(sys.getrefcount(image), 2) # test other methods image.readMetadata() self.check_result(image.byteOrder(), diff --git a/tests/test_preview.py b/tests/test_preview.py index 476abbf4..f05f2b75 100644 --- a/tests/test_preview.py +++ b/tests/test_preview.py @@ -54,9 +54,11 @@ def test_PreviewImage(self): with preview.data() as data: self.check_result(data, memoryview, copy.data()) self.assertEqual(data[:10], b'\xff\xd8\xff\xe0\x00\x10JFIF') - self.assertEqual(sys.getrefcount(preview), 3) + if sys.version_info < (3, 14): + self.assertEqual(sys.getrefcount(preview), 3) del data - self.assertEqual(sys.getrefcount(preview), 2) + if sys.version_info < (3, 14): + self.assertEqual(sys.getrefcount(preview), 2) with self.assertWarns(DeprecationWarning): self.assertEqual(memoryview(preview), copy.data()) self.check_result(preview.extension(), str, '.jpg') diff --git a/tests/test_types.py b/tests/test_types.py index 5db5143e..cd365dcb 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -84,9 +84,11 @@ def test_DataBuf(self): with self.assertRaises(ValueError): view[0] view = buf.data() - self.assertEqual(sys.getrefcount(buf), 3) + if sys.version_info < (3, 14): + self.assertEqual(sys.getrefcount(buf), 3) del view - self.assertEqual(sys.getrefcount(buf), 2) + if sys.version_info < (3, 14): + self.assertEqual(sys.getrefcount(buf), 2) def test_Rational(self): for type_ in (exiv2.Rational, exiv2.URational): diff --git a/tests/test_value.py b/tests/test_value.py index 8661f7dc..d891ac44 100644 --- a/tests/test_value.py +++ b/tests/test_value.py @@ -131,9 +131,11 @@ def do_common_string_tests(self, value, data): view = copy.data() self.assertIsInstance(view, memoryview) self.assertEqual(view[0], data[0]) - self.assertEqual(sys.getrefcount(copy), 3) + if sys.version_info < (3, 14): + self.assertEqual(sys.getrefcount(copy), 3) del view - self.assertEqual(sys.getrefcount(copy), 2) + if sys.version_info < (3, 14): + self.assertEqual(sys.getrefcount(copy), 2) def do_common_xmp_tests(self, value): with self.assertWarns(DeprecationWarning): @@ -355,9 +357,11 @@ def check_data(value, data): self.assertEqual(view, data) with self.assertRaises(ValueError): self.assertEqual(view[0], data[0]) - self.assertEqual(sys.getrefcount(value), 3) + if sys.version_info < (3, 14): + self.assertEqual(sys.getrefcount(value), 3) del view - self.assertEqual(sys.getrefcount(value), 2) + if sys.version_info < (3, 14): + self.assertEqual(sys.getrefcount(value), 2) else: copy = value.data() self.assertIsInstance(copy, bytearray)