From 97d3e0c2483ea8e159cc4e899215a71fe25fe5f7 Mon Sep 17 00:00:00 2001 From: Jason Madden Date: Fri, 14 Nov 2025 11:17:44 -0600 Subject: [PATCH 1/4] Add Python 3.14; Make ZODB optional. --- .github/workflows/tests.yml | 5 +++-- CHANGES.rst | 5 +++-- setup.py | 9 +++++++-- src/nti/testing/tests/test_base.py | 10 ++++++++-- src/nti/testing/tests/test_main.py | 20 +++++++++++++------- src/nti/testing/tests/test_zodb.py | 28 +++++++++++++++++++++++----- tox.ini | 6 ++++++ 7 files changed, 63 insertions(+), 20 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6f5364d..a259c76 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,9 +12,10 @@ jobs: test: strategy: matrix: - python-version: ["pypy-3.10", "3.10", "3.11", "3.12", "3.13"] + python-version: ["pypy-3.11", "3.10", "3.11", "3.12", "3.13", "3.14"] extras: - "[test,docs]" + - "[test,docs,zodb,test-zodb]" runs-on: ubuntu-latest steps: @@ -37,7 +38,7 @@ jobs: coverage combine || true coverage report -i || true - name: Lint - if: matrix.python-version == '3.12' + if: matrix.python-version == '3.14' run: | python -m pip install -U pylint pylint src diff --git a/CHANGES.rst b/CHANGES.rst index bcdbc17..381e153 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,10 +2,11 @@ Changes ========= -4.3.1 (unreleased) +4.4.0 (unreleased) ================== -- Nothing changed yet. +- Move ZODB and related dependencies to the optional 'zodb' extra. +- Add support for Python 3.14. 4.3.0 (2025-04-22) diff --git a/setup.py b/setup.py index 0042769..75bcaa8 100755 --- a/setup.py +++ b/setup.py @@ -13,7 +13,6 @@ TESTS_REQUIRE = [ 'Acquisition', - 'zope.site', 'zope.testrunner', 'testgres >= 1.11', 'psycopg2-binary; python_implementation != "PyPy"', @@ -47,6 +46,7 @@ def _read(fname): 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: 3.13', + 'Programming Language :: Python :: 3.14', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Software Development :: Testing', @@ -56,7 +56,6 @@ def _read(fname): packages=find_namespace_packages(where='src'), package_dir={'': 'src'}, install_requires=[ - 'ZODB >= 5.6.0', # Error messages changed in 5.1, reprs changed <= 5.4 'zope.interface >= 5.4.0', 'pyhamcrest', @@ -72,7 +71,13 @@ def _read(fname): entry_points=entry_points, include_package_data=True, extras_require={ + 'zodb': [ + 'ZODB >= 5.6.0', + ], 'test': TESTS_REQUIRE, + 'test-zodb': [ + 'zope.site', + ], 'docs': [ 'Sphinx', 'furo', diff --git a/src/nti/testing/tests/test_base.py b/src/nti/testing/tests/test_base.py index fb25d01..29d9b6b 100644 --- a/src/nti/testing/tests/test_base.py +++ b/src/nti/testing/tests/test_base.py @@ -89,7 +89,10 @@ def test_thing(self): def test_configuring_base(self): - import zope.traversing.tests.test_traverser + try: + import zope.traversing.tests.test_traverser + except ModuleNotFoundError: + self.skipTest('zope.traversing not installed') class MyTest(base.ConfiguringTestBase): set_up_packages = ('zope.component', ('configure.zcml', 'zope.component'), @@ -104,7 +107,10 @@ def test_thing(self): mt.tearDown() # pylint:disable=no-value-for-parameter def test_shared_configuring_base(self): - import zope.traversing.tests.test_traverser + try: + import zope.traversing.tests.test_traverser + except ModuleNotFoundError: + self.skipTest('zope.traversing not installed') class MyTest(base.SharedConfiguringTestBase): layer = None # replaced by metaclass set_up_packages = ('zope.component', diff --git a/src/nti/testing/tests/test_main.py b/src/nti/testing/tests/test_main.py index d1327ad..3c53073 100644 --- a/src/nti/testing/tests/test_main.py +++ b/src/nti/testing/tests/test_main.py @@ -32,16 +32,22 @@ def test_suite(): here = os.path.dirname(__file__) suite = unittest.defaultTestLoader.loadTestsFromName(__name__) - suite.addTest(doctest.DocFileSuite( - 'test_component_cleanup_broken.txt')) + try: + import zope.site as has_zope_site + except ModuleNotFoundError: + has_zope_site = None + else: + suite.addTest(doctest.DocFileSuite( + 'test_component_cleanup_broken.txt')) readmedir = here while not os.path.exists(os.path.join(readmedir, 'setup.py')): readmedir = os.path.dirname(readmedir) readme = os.path.join(readmedir, 'README.rst') - suite.addTest(doctest.DocFileSuite( - readme, - module_relative=False, - optionflags=doctest.ELLIPSIS, - )) + if has_zope_site: + suite.addTest(doctest.DocFileSuite( + readme, + module_relative=False, + optionflags=doctest.ELLIPSIS, + )) return suite diff --git a/src/nti/testing/tests/test_zodb.py b/src/nti/testing/tests/test_zodb.py index 2a77698..abda355 100644 --- a/src/nti/testing/tests/test_zodb.py +++ b/src/nti/testing/tests/test_zodb.py @@ -14,7 +14,13 @@ import transaction from transaction.interfaces import NoTransaction from zope import interface -from nti.testing import zodb +try: + from nti.testing import zodb + base_mock_db_trans = zodb.mock_db_trans +except ModuleNotFoundError as ex: + assert ex.name == 'ZODB' + zodb = None + base_mock_db_trans = object # pylint:disable=protected-access,pointless-string-statement @@ -41,7 +47,7 @@ def cacheMinimize(self): self.minimized = True -class MockDBTrans(zodb.mock_db_trans): +class MockDBTrans(base_mock_db_trans): def __init__(self, db=None): if db is None: @@ -52,6 +58,8 @@ def __init__(self, db=None): class TestMockDBTrans(unittest.TestCase): def setUp(self): + if zodb is None: + self.skipTest("ZODB not installed") self._was_explicit = transaction.manager.explicit transaction.manager.explicit = False @@ -226,7 +234,7 @@ def __bool__(self): class MyMock(MockDBTrans): seen_tx = None aborted = False - def on_connection_opened(self, conn): + def on_connection_opened(self, _conn): # pylint:disable=no-member self.seen_tx = self._mock_db_trans__current_transaction abort = self.seen_tx.abort @@ -255,7 +263,13 @@ def _abort(): class TestZODBLayer(unittest.TestCase): - layer = zodb.ZODBLayer + if zodb is not None: + layer = zodb.ZODBLayer + + def setUp(self): + super().setUp() + if zodb is None: + self.skipTest("ZODB not installed") def test_registration(self): from ZODB.interfaces import IDatabase @@ -288,10 +302,14 @@ def __init__(self, *args): pass class TestResetDbCaches(unittest.TestCase): - layer = zodb.ZODBLayer + + if zodb is not None: + layer = zodb.ZODBLayer def setUp(self): super().setUp() + if zodb is None: + self.skipTest("ZODB not installed") gc.disable() def tearDown(self): diff --git a/tox.ini b/tox.ini index 67f3847..fb7253a 100644 --- a/tox.ini +++ b/tox.ini @@ -4,6 +4,8 @@ envlist = py38,py39,py310,py311,py312,pypy3,coverage,docs [testenv] extras = test + zodb + test-zodb commands = zope-testrunner --test-path=src --auto-color --auto-progress [] # substitute with tox positional args setenv = @@ -20,6 +22,10 @@ commands = deps = coverage +[testenv:py314] +extras = + test + [testenv:docs] commands = sphinx-build -b html -d docs/_build/doctrees docs docs/_build/html From a90a6321a8c06b4fd6d578bb01ccaea9ae7f5456 Mon Sep 17 00:00:00 2001 From: Jason Madden Date: Fri, 14 Nov 2025 11:22:00 -0600 Subject: [PATCH 2/4] We need the zodb extra to run the doctests --- .github/workflows/tests.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a259c76..56aae67 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -14,7 +14,6 @@ jobs: matrix: python-version: ["pypy-3.11", "3.10", "3.11", "3.12", "3.13", "3.14"] extras: - - "[test,docs]" - "[test,docs,zodb,test-zodb]" runs-on: ubuntu-latest From 2df2ed24aa8623b50cee021d911418a9ddc1872e Mon Sep 17 00:00:00 2001 From: Jason Madden Date: Fri, 14 Nov 2025 11:25:16 -0600 Subject: [PATCH 3/4] Add tests without zodb. --- .github/workflows/tests.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 56aae67..06679fb 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -36,6 +36,10 @@ jobs: coverage run -a -m sphinx -b doctest -d docs/_build/doctrees docs docs/_build/doctests coverage combine || true coverage report -i || true + - name: Test No ZODB + run: | + python -m pip uninstall -y ZODB zope.site persistent + python -m zope.testrunner --test-path=src --auto-color --auto-progress - name: Lint if: matrix.python-version == '3.14' run: | From 589ffc39ff0edba05dc9ef76e509142672cd6f0b Mon Sep 17 00:00:00 2001 From: Jason Madden Date: Fri, 14 Nov 2025 11:26:41 -0600 Subject: [PATCH 4/4] Linting needs deps installed. --- .github/workflows/tests.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 06679fb..f529e74 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -36,15 +36,15 @@ jobs: coverage run -a -m sphinx -b doctest -d docs/_build/doctrees docs docs/_build/doctests coverage combine || true coverage report -i || true - - name: Test No ZODB - run: | - python -m pip uninstall -y ZODB zope.site persistent - python -m zope.testrunner --test-path=src --auto-color --auto-progress - name: Lint if: matrix.python-version == '3.14' run: | python -m pip install -U pylint pylint src + - name: Test No ZODB + run: | + python -m pip uninstall -y ZODB zope.site persistent + python -m zope.testrunner --test-path=src --auto-color --auto-progress - name: Submit to Coveralls # This is a container action, which only runs on Linux. uses: AndreMiras/coveralls-python-action@develop