Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-lazr.config for 
openSUSE:Factory checked in at 2026-09-28 10:38:53
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-lazr.config (Old)
 and      /work/SRC/openSUSE:Factory/.python-lazr.config.new.383539 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-lazr.config"

Mon Sep 28 10:38:53 2026 rev:8 rq:1380280 version:4.0.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-lazr.config/python-lazr.config.changes    
2026-06-15 19:46:13.194394128 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-lazr.config.new.383539/python-lazr.config.changes
        2026-09-28 10:40:08.478086469 +0200
@@ -1,0 +2,8 @@
+Thu Sep 24 05:31:05 UTC 2026 - Steve Kowalik <[email protected]>
+
+- Update to 4.0.0:
+  * Replace pkg_resources namespace with a PEP 420 native namespace.
+  * Consolidate packaging into a single pyproject.toml (remove setup.py,
+    setup.cfg, and _version.py).
+
+-------------------------------------------------------------------

Old:
----
  lazr_config-3.1.tar.gz

New:
----
  lazr_config-4.0.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-lazr.config.spec ++++++
--- /var/tmp/diff_new_pack.aUFhlc/_old  2026-09-28 10:40:09.692137377 +0200
+++ /var/tmp/diff_new_pack.aUFhlc/_new  2026-09-28 10:40:09.694137461 +0200
@@ -18,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-lazr.config
-Version:        3.1
+Version:        4.0.0
 Release:        0
 Summary:        Create configuration schemas, and process and validate 
configurations
 License:        LGPL-3.0-only
@@ -68,6 +68,5 @@
 %license COPYING.txt
 %dir %{python_sitelib}/lazr
 %{python_sitelib}/lazr/config
-%{python_sitelib}/lazr[._]config-%{version}*-info
-%{python_sitelib}/lazr[._]config-%{version}*-nspkg.pth
+%{python_sitelib}/lazr[._]config-%{version}.dist-info
 

++++++ lazr_config-3.1.tar.gz -> lazr_config-4.0.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lazr_config-3.1/.flake8 new/lazr_config-4.0.0/.flake8
--- old/lazr_config-3.1/.flake8 1970-01-01 01:00:00.000000000 +0100
+++ new/lazr_config-4.0.0/.flake8       2026-08-01 20:49:35.000000000 +0200
@@ -0,0 +1,5 @@
+[flake8]
+ignore =
+    # Incompatible with Black.
+    E203,
+    W503
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lazr_config-3.1/.launchpad.yaml 
new/lazr_config-4.0.0/.launchpad.yaml
--- old/lazr_config-3.1/.launchpad.yaml 1970-01-01 01:00:00.000000000 +0100
+++ new/lazr_config-4.0.0/.launchpad.yaml       2026-08-01 20:49:35.000000000 
+0200
@@ -0,0 +1,66 @@
+pipeline:
+  - test-focal
+  - test-jammy
+  - test-noble
+  # - test-resolute
+  - lint
+  - docs
+  - audit
+
+jobs:
+  # focal's apt tox (3.13.2) cannot build a pyproject-only sdist
+  # ("error: option --formats not recognized"), so install a modern tox in a
+  # throwaway venv. skip_install envs (lint/docs/audit on noble) are 
unaffected.
+  test-focal:
+    series: focal
+    architectures: amd64
+    packages: [git, python3-venv, python3.9]
+    run: |
+      python3 -m venv /tmp/tox
+      /tmp/tox/bin/pip install --upgrade pip
+      # 4.26.0 dropped Python 3.8 (which runs this venv); 4.25.0 is the newest
+      # tox that still runs on 3.8. focal ships both 3.8 (default) and 3.9.
+      /tmp/tox/bin/pip install "tox<4.26"
+      /tmp/tox/bin/tox -e py38,py39
+
+  test-jammy:
+    series: jammy
+    architectures: amd64
+    packages: [git, python3-venv, python3.11]
+    # jammy's apt tox (3.x) also cannot build a pyproject-only sdist, so use a
+    # throwaway venv with a modern tox. jammy ships both 3.10 (default) and 
3.11.
+    run: |
+      python3 -m venv /tmp/tox
+      /tmp/tox/bin/pip install --upgrade pip
+      /tmp/tox/bin/pip install tox
+      /tmp/tox/bin/tox -e py310,py311
+
+  test-noble:
+    series: noble
+    architectures: amd64
+    packages: [git, tox]
+    run: tox -e py312
+
+  test-resolute:
+    series: resolute
+    architectures: amd64
+    packages: [git, tox]
+    run: tox -e py314
+
+  lint:
+    series: noble  # align with Python versions used in tox configuration
+    architectures: amd64
+    packages: [tox, git]
+    run: tox -e lint
+
+  docs:
+    series: noble  # align with Python versions used in tox configuration
+    architectures: amd64
+    packages: [tox, git]
+    run: tox -e docs
+
+  audit:
+    series: noble  # align with Python versions used in tox configuration
+    architectures: amd64
+    packages: [tox, git]
+    run: tox -e audit
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lazr_config-3.1/.pre-commit-config.yaml 
new/lazr_config-4.0.0/.pre-commit-config.yaml
--- old/lazr_config-3.1/.pre-commit-config.yaml 2025-01-27 10:15:56.000000000 
+0100
+++ new/lazr_config-4.0.0/.pre-commit-config.yaml       2026-08-01 
20:49:35.000000000 +0200
@@ -2,35 +2,40 @@
 # See https://pre-commit.com/hooks.html for more hooks
 repos:
 -   repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v5.0.0
+    rev: v6.0.0
     hooks:
     -   id: check-added-large-files
-    -   id: check-ast
-    -   id: end-of-file-fixer
-    -   id: check-json
     -   id: check-merge-conflict
     -   id: check-xml
     -   id: check-yaml
     -   id: debug-statements
--   repo: https://github.com/psf/black
-    rev: 24.10.0
-    hooks:
-    -   id: black
-        # skip namespace package declaration
-        exclude: ^src/lazr/__init__\.py$
--   repo: https://github.com/asottile/pyupgrade
-    rev: v3.19.0
-    hooks:
-    -   id: pyupgrade
 -   repo: https://github.com/PyCQA/isort
-    rev: 5.13.2
+    rev: 9.0.0a3
     hooks:
     -   id: isort
 -   repo: https://github.com/PyCQA/flake8
-    rev: 7.1.1
+    rev: 7.3.0
     hooks:
     -   id: flake8
--   repo: https://github.com/get-woke/woke
-    rev: v0.19.0
+-   repo: https://github.com/asottile/pyupgrade
+    rev: v3.21.2
+    hooks:
+    -   id: pyupgrade
+-   repo: https://github.com/mgedmin/check-manifest
+    rev: "0.51"
+    hooks:
+    -   id: check-manifest
+-   repo: https://github.com/psf/black
+    rev: 26.5.1
+    hooks:
+    -   id: black
+-   repo: https://github.com/PyCQA/bandit
+    rev: 1.9.4
+    hooks:
+    -   id: bandit
+        args: ["--severity-level", "high"]
+-   repo: https://github.com/pypa/pip-audit
+    rev: v2.10.1
     hooks:
-    -   id: woke-from-source
+    -   id: pip-audit
+        additional_dependencies: ["pip>=26.1.2"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lazr_config-3.1/.woke.yaml 
new/lazr_config-4.0.0/.woke.yaml
--- old/lazr_config-3.1/.woke.yaml      2022-04-21 16:28:37.000000000 +0200
+++ new/lazr_config-4.0.0/.woke.yaml    1970-01-01 01:00:00.000000000 +0100
@@ -1,228 +0,0 @@
-
-# Based on Canonical's Guidelines
-# 
https://docs.google.com/document/d/1mJUa1VJHOMWa723dmKmNjSKGW-nlBv9xktzGZZwacVo/edit#heading=h.5efudb237qdb
-rules:
-  - name: whitelist
-    terms:
-      - whitelist
-      - white-list
-      - whitelisted
-      - white-listed
-    alternatives:
-      - allowlist
-      - inclusion list
-    severity: warning
-    note: "The underlying assumption of the whitelist/blacklist metaphor is 
that white = good and black = bad. Because colors in and of themselves have no 
predetermined meaning, any meaning we assign to them is cultural: for example, 
the color red in many Southeast Asian countries is lucky, and is often 
associated with events like marriages, whereas the color white carries the same 
connotations in many European countries. In the case of whitelist/blacklist, 
the terms originate in the publishing industry – one dominated by the USA and 
England, two countries which participated in slavery and which grapple with 
their racist legacies to this day."
-
-  - name: blacklist
-    terms:
-      - blacklist
-      - black-list
-      - blacklisted
-      - black-listed
-    alternatives:
-      - denylist
-      - blocklist
-      - exclusion list
-    severity: warning
-    note: "The underlying assumption of the whitelist/blacklist metaphor is 
that white = good and black = bad. Because colors in and of themselves have no 
predetermined meaning, any meaning we assign to them is cultural: for example, 
the color red in many Southeast Asian countries is lucky, and is often 
associated with events like marriages, whereas the color white carries the same 
connotations in many European countries. In the case of whitelist/blacklist, 
the terms originate in the publishing industry – one dominated by the USA and 
England, two countries which participated in slavery and which grapple with 
their racist legacies to this day."
-
-  - name: master-slave
-    terms:
-      - master-slave
-      - master/slave
-    alternatives:
-      - leader/follower
-      - main/replica
-      - primary/replica
-      - primary/standby
-      - primary/secondary
-
-  - name: slave
-    terms:
-      - slave
-    alternatives:
-      - follower
-      - replica
-      - standby
-
-  - name: grandfathered
-    terms:
-      - grandfathered
-    alternatives:
-      - legacy status
-      - legacied
-      - exempted
-      - carried
-      - brought forward
-      - rolled over
-
-  - name: man-hours
-    terms:
-      - man hours
-      - man-hours
-    alternatives:
-      - person hours
-      - engineer hours
-
-  - name: sanity
-    terms:
-      - sanity
-    alternatives:
-      - confidence
-      - quick check
-      - coherence check
-
-  - name: dummy
-    terms:
-      - dummy
-    alternatives:
-      - placeholder
-      - sample
-
-  - name: guys
-    terms:
-      - guys
-    alternatives:
-      - folks
-      - people
-      - you all
-      - y'all
-      - yinz
-
-  - name: whitebox
-    terms:
-      - white-box
-      - whitebox
-      - white box
-    alternatives:
-      - open-box
-
-  - name: blackbox
-    terms:
-      - black-box
-      - blackbox
-      - black box
-    alternatives:
-      - closed-box
-
-  - name: blackhat
-    terms:
-      - blackhat
-      - black-hat
-      - black hat
-    alternatives:
-      - attacker
-      - malicious actor
-
-  - name: whitehat
-    terms:
-      - whitehat
-      - white-hat
-      - white hat
-    alternatives:
-      - researcher
-      - security specialist
-
-  - name: illegal characters
-    terms:
-      - illegal characters
-    alternatives:
-      - invalid characters
-      - unsupported characters
-      - special characters
-
-  - name: native feature
-    terms:
-      - native feature
-    alternatives:
-      - core feature
-      - built-in feature
-
-  - name: native feature
-    terms:
-      - native feature
-    alternatives:
-      - core feature
-      - built-in feature
-
-  - name: chairman/foreman
-    terms:
-      - chairman
-      - foreman
-    alternatives:
-      - chair
-      - foreperson
-
-  - name: man in the middle
-    terms:
-      - man in the middle
-      - man-in-the-middle
-    alternatives:
-      - machine-in-the-middle
-      - person-in-the-middle
-      - system-in-the-middle
-      - intermediary attack
-
-  - name: middleman
-    terms:
-      - middleman
-    alternatives:
-      - middleperson
-      - intermediary
-
-  - name: manned
-    terms:
-      - manned
-    alternatives:
-      - crewed
-      - staffed
-      - monitored
-      - human operated
-
-  - name: mom test / girlfriend test
-    terms:
-      - mom test
-      - girlfriend test
-    alternatives:
-      - user test
-      - user friendly
-
-  - name: crazy
-    terms:
-      - crazy
-    alternatives:
-      - baffling
-      - unexplained
-      - errant
-
-  - name: cripples
-    terms:
-      - cripples
-    alternatives:
-      - slows down
-      - hinders
-      - obstructs
-
-  - name: crippling 
-    terms:
-      - crippling
-    alternatives:
-      - attenuating
-      - incapacitating
-
-  - name: stonith/stomith 
-    terms:
-      - stonith
-      - stomith
-    alternatives:
-      - fence failed nodes
-      - machines
-
-  - name: demilitarized zone 
-    terms:
-      - demilitarized zone
-      - dmz
-    alternatives:
-      - perimeter network
-      - passthrough network
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lazr_config-3.1/CONTRIBUTING.rst 
new/lazr_config-4.0.0/CONTRIBUTING.rst
--- old/lazr_config-3.1/CONTRIBUTING.rst        2021-11-09 16:34:08.000000000 
+0100
+++ new/lazr_config-4.0.0/CONTRIBUTING.rst      2026-08-01 20:49:35.000000000 
+0200
@@ -13,38 +13,45 @@
     You should have received a copy of the GNU Lesser General Public License
     along with lazr.config.  If not, see <http://www.gnu.org/licenses/>.
 
-======================
-Hacking on lazr.config
-======================
+============
+Contributing
+============
+
+Getting the code
+----------------
+
+The source is maintained in git::
+
+    git clone https://git.launchpad.net/lazr.config
+
+Running the tests
+-----------------
+
+Use `tox <https://tox.readthedocs.io/en/latest/>`_::
+
+    tox
 
-These are guidelines for hacking on the lazr.config project.  But first,
-please see the common hacking guidelines at:
+This runs the linters, the test suite across supported Python versions, the
+documentation build, and a dependency audit.
 
-    http://dev.launchpad.net/Hacking
+Documentation
+-------------
 
+To update the `project's documentation
+<https://lazrconfig.readthedocs.io/en/latest/>`_ trigger a manual build on the
+project's dashboard at https://readthedocs.org.
 
 Getting help
 ------------
 
-If you find bugs in this package, you can report them here:
+If you find bugs in this package, report them at:
 
     https://launchpad.net/lazr.config
 
-If you want to discuss this package, join the team and mailing list here:
+To discuss this package, join the team and mailing list at:
 
     https://launchpad.net/~lazr-developers
 
-or send a message to:
+or email:
 
     [email protected]
-
-
-============
-Contributing
-============
-
-To run this project's tests, use `tox 
<https://tox.readthedocs.io/en/latest/>`_.
-
-To update the `project's documentation
-<https://lazrconfig.readthedocs.io/en/latest/>`_ you need to trigger a manual
-build on the project's dashboard on https://readthedocs.org.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lazr_config-3.1/MANIFEST.in 
new/lazr_config-4.0.0/MANIFEST.in
--- old/lazr_config-3.1/MANIFEST.in     2023-04-08 19:16:39.000000000 +0200
+++ new/lazr_config-4.0.0/MANIFEST.in   2026-08-01 20:49:35.000000000 +0200
@@ -1,4 +1,6 @@
-include *.py *.txt *.rst MANIFEST.in *.ini
+include *.rst *.md *.txt MANIFEST.in *.ini
+include .flake8
 recursive-include src/lazr *.rst *.conf
 exclude .bzrignore
+exclude .git-blame-ignore-revs
 include *.yaml
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lazr_config-3.1/NEWS.rst 
new/lazr_config-4.0.0/NEWS.rst
--- old/lazr_config-3.1/NEWS.rst        2025-02-05 10:02:52.000000000 +0100
+++ new/lazr_config-4.0.0/NEWS.rst      2026-08-01 20:49:35.000000000 +0200
@@ -2,6 +2,14 @@
 NEWS for lazr.config
 ====================
 
+4.0.0 (unreleased)
+==================
+
+- Replace ``pkg_resources`` namespace with a PEP 420 native namespace.
+- Consolidate packaging into a single ``pyproject.toml`` (remove ``setup.py``,
+  ``setup.cfg``, and ``_version.py``).
+- Standardize tox, Launchpad CI, pre-commit, and contributor documentation.
+
 3.1 (2024-12-09)
 ==================
 - Add support for Python 3.12 and 3.13.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lazr_config-3.1/PKG-INFO 
new/lazr_config-4.0.0/PKG-INFO
--- old/lazr_config-3.1/PKG-INFO        2025-02-05 10:04:13.434197200 +0100
+++ new/lazr_config-4.0.0/PKG-INFO      2026-08-01 20:56:21.188968200 +0200
@@ -1,40 +1,42 @@
-Metadata-Version: 2.1
+Metadata-Version: 2.4
 Name: lazr.config
-Version: 3.1
+Version: 4.0.0
 Summary: Create configuration schemas, and process and validate configurations.
-Home-page: https://launchpad.net/lazr.config
-Download-URL: https://launchpad.net/lazr.config/+download
 Maintainer: LAZR Developers
-Maintainer-email: [email protected]
 License: LGPL v3
+Project-URL: Homepage, https://launchpad.net/lazr.config
 Project-URL: Source, https://code.launchpad.net/lazr.config
 Project-URL: Issue Tracker, https://bugs.launchpad.net/lazr.config
 Project-URL: Documentation, https://lazrconfig.readthedocs.io/en/latest/
+Project-URL: Download, https://launchpad.net/lazr.config/+download
 Classifier: Development Status :: 5 - Production/Stable
 Classifier: Intended Audience :: Developers
 Classifier: License :: OSI Approved :: GNU Library or Lesser General Public 
License (LGPL)
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3 :: Only
 Classifier: Programming Language :: Python :: 3.8
 Classifier: Programming Language :: Python :: 3.9
 Classifier: Programming Language :: Python :: 3.10
 Classifier: Programming Language :: Python :: 3.11
 Classifier: Programming Language :: Python :: 3.12
 Classifier: Programming Language :: Python :: 3.13
+Classifier: Programming Language :: Python :: 3.14
 Requires-Python: >=3.8
+Description-Content-Type: text/x-rst
 License-File: COPYING.txt
-Requires-Dist: setuptools
 Requires-Dist: zope.interface
 Requires-Dist: lazr.delegates
 Provides-Extra: docs
 Requires-Dist: Sphinx; extra == "docs"
+Provides-Extra: test
+Requires-Dist: zope.testing>=4.6.0; extra == "test"
+Requires-Dist: zope.testrunner>=6.6.1; extra == "test"
+Dynamic: license-file
 
+======================
+Welcome to lazr.config
+======================
 
-The LAZR config system is typically used to manage process configuration.
-Process configuration is for saying how things change when we run systems on
-different machines, or under different circumstances.
-
-This system uses ini-like file format of section, keys, and values.  The
-config file supports inheritance to minimize duplication of information across
-files. The format supports schema validation.
+Create configuration schemas, and process and validate configurations.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lazr_config-3.1/README.rst 
new/lazr_config-4.0.0/README.rst
--- old/lazr_config-3.1/README.rst      2021-11-05 14:00:38.000000000 +0100
+++ new/lazr_config-4.0.0/README.rst    2026-08-01 20:56:18.000000000 +0200
@@ -1,3 +1,5 @@
 ======================
 Welcome to lazr.config
 ======================
+
+Create configuration schemas, and process and validate configurations.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lazr_config-3.1/SECURITY.md 
new/lazr_config-4.0.0/SECURITY.md
--- old/lazr_config-3.1/SECURITY.md     1970-01-01 01:00:00.000000000 +0100
+++ new/lazr_config-4.0.0/SECURITY.md   2026-07-03 13:08:40.000000000 +0200
@@ -0,0 +1,15 @@
+# Launchpad Security Policy
+
+If you discover a security vulnerability, please follow the steps outlined 
below to report it:
+
+1. **Do not** publicly disclose the vulnerability before discussing it with us.
+2. Contact us via email at 
[[email protected]](mailto:[email protected]).
+3. Provide detailed information about the vulnerability, including:
+   - A description of the vulnerability.
+   - Steps to reproduce the issue.
+   - Potential impact and affected versions.
+   - Suggested mitigations, if possible.
+
+The [Ubuntu Security disclosure and embargo 
policy](https://ubuntu.com/security/disclosure-policy) contains more 
information about what you can expect when you contact us and what we expect 
from you.
+
+The Launchpad team will be notified of the issue and review the vulnerability. 
We may reach out to you for further information or clarification if needed. If 
the issue is confirmed as a valid security vulnerability, we will assign a CVE 
and coordinate the release of the fix.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lazr_config-3.1/pyproject.toml 
new/lazr_config-4.0.0/pyproject.toml
--- old/lazr_config-3.1/pyproject.toml  2025-01-27 10:15:56.000000000 +0100
+++ new/lazr_config-4.0.0/pyproject.toml        2026-08-01 20:49:35.000000000 
+0200
@@ -1,3 +1,71 @@
+[build-system]
+requires = ["setuptools>=61.0"]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "lazr.config"
+version = "4.0.0"
+description = "Create configuration schemas, and process and validate 
configurations."
+readme = "README.rst"
+requires-python = ">=3.8"
+license = { text = "LGPL v3" }
+maintainers = [
+    { name = "LAZR Developers" },
+]
+classifiers = [
+    "Development Status :: 5 - Production/Stable",
+    "Intended Audience :: Developers",
+    "License :: OSI Approved :: GNU Library or Lesser General Public License 
(LGPL)",
+    "Operating System :: OS Independent",
+    "Programming Language :: Python",
+    "Programming Language :: Python :: 3",
+    "Programming Language :: Python :: 3 :: Only",
+    "Programming Language :: Python :: 3.8",
+    "Programming Language :: Python :: 3.9",
+    "Programming Language :: Python :: 3.10",
+    "Programming Language :: Python :: 3.11",
+    "Programming Language :: Python :: 3.12",
+    "Programming Language :: Python :: 3.13",
+    "Programming Language :: Python :: 3.14",
+]
+dependencies = [
+    "zope.interface",
+    "lazr.delegates",
+]
+
+[project.optional-dependencies]
+docs = ["Sphinx"]
+test = [
+    "zope.testing>=4.6.0",
+    "zope.testrunner>=6.6.1",
+]
+
+[project.urls]
+Homepage = "https://launchpad.net/lazr.config";
+Source = "https://code.launchpad.net/lazr.config";
+"Issue Tracker" = "https://bugs.launchpad.net/lazr.config";
+Documentation = "https://lazrconfig.readthedocs.io/en/latest/";
+Download = "https://launchpad.net/lazr.config/+download";
+
+[tool.setuptools]
+include-package-data = true
+
+[tool.setuptools.packages.find]
+where = ["src"]
+namespaces = true
+
 [tool.black]
 line-length = 79
-target-version = ["py311"]
+target-version = ["py38"]
+
+[tool.isort]
+known_first_party = "lazr.config"
+line_length = 79
+profile = "black"
+
+[tool.coverage.run]
+source = ["lazr.config"]
+omit = ["*/docs/conf.py"]
+
+[tool.coverage.paths]
+source = ["src", ".tox/*/site-packages"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lazr_config-3.1/setup.cfg 
new/lazr_config-4.0.0/setup.cfg
--- old/lazr_config-3.1/setup.cfg       2025-02-05 10:04:13.434197200 +0100
+++ new/lazr_config-4.0.0/setup.cfg     2026-08-01 20:56:21.189108100 +0200
@@ -1,13 +1,3 @@
-[flake8]
-ignore = 
-       E203,
-       W503
-
-[isort]
-known_first_party = lazr.config
-line_length = 79
-profile = black
-
 [egg_info]
 tag_build = 
 tag_date = 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lazr_config-3.1/setup.py 
new/lazr_config-4.0.0/setup.py
--- old/lazr_config-3.1/setup.py        2025-01-27 10:15:56.000000000 +0100
+++ new/lazr_config-4.0.0/setup.py      1970-01-01 01:00:00.000000000 +0100
@@ -1,76 +0,0 @@
-# Copyright 2008-2015 Canonical Ltd.  All rights reserved.
-#
-# This file is part of lazr.config.
-#
-# lazr.config is free software: you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation, version 3 of the License.
-#
-# lazr.config is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-# License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with lazr.config.  If not, see <http://www.gnu.org/licenses/>.
-
-from setuptools import find_packages, setup
-
-with open("src/lazr/config/_version.py") as version_file:
-    exec(version_file.read())  # sets __version__
-
-setup(
-    name="lazr.config",
-    version=__version__,  # noqa: F821
-    namespace_packages=["lazr"],
-    packages=find_packages("src"),
-    package_dir={"": "src"},
-    include_package_data=True,
-    zip_safe=False,
-    maintainer="LAZR Developers",
-    maintainer_email="[email protected]",
-    description=(
-        "Create configuration schemas, and process and "
-        "validate configurations."
-    ),
-    long_description="""
-The LAZR config system is typically used to manage process configuration.
-Process configuration is for saying how things change when we run systems on
-different machines, or under different circumstances.
-
-This system uses ini-like file format of section, keys, and values.  The
-config file supports inheritance to minimize duplication of information across
-files. The format supports schema validation.
-""",
-    license="LGPL v3",
-    install_requires=[
-        "setuptools",
-        "zope.interface",
-        "lazr.delegates",
-    ],
-    url="https://launchpad.net/lazr.config";,
-    project_urls={
-        "Source": "https://code.launchpad.net/lazr.config";,
-        "Issue Tracker": "https://bugs.launchpad.net/lazr.config";,
-        "Documentation": "https://lazrconfig.readthedocs.io/en/latest/";,
-    },
-    download_url="https://launchpad.net/lazr.config/+download";,
-    classifiers=[
-        "Development Status :: 5 - Production/Stable",
-        "Intended Audience :: Developers",
-        "License :: OSI Approved :: GNU Library or Lesser General Public 
License (LGPL)",  # noqa
-        "Operating System :: OS Independent",
-        "Programming Language :: Python",
-        "Programming Language :: Python :: 3",
-        "Programming Language :: Python :: 3.8",
-        "Programming Language :: Python :: 3.9",
-        "Programming Language :: Python :: 3.10",
-        "Programming Language :: Python :: 3.11",
-        "Programming Language :: Python :: 3.12",
-        "Programming Language :: Python :: 3.13",
-    ],
-    extras_require=dict(
-        docs=["Sphinx"],
-    ),
-    python_requires=">=3.8",
-)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lazr_config-3.1/src/lazr/__init__.py 
new/lazr_config-4.0.0/src/lazr/__init__.py
--- old/lazr_config-3.1/src/lazr/__init__.py    2021-11-05 12:54:41.000000000 
+0100
+++ new/lazr_config-4.0.0/src/lazr/__init__.py  1970-01-01 01:00:00.000000000 
+0100
@@ -1,23 +0,0 @@
-# Copyright 2008-2015 Canonical Ltd.  All rights reserved.
-#
-# This file is part of lazr.config.
-#
-# lazr.config is free software: you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation, version 3 of the License.
-#
-# lazr.config is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-# License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with lazr.config.  If not, see <http://www.gnu.org/licenses/>.
-
-# This is a namespace package.
-try:
-    import pkg_resources
-    pkg_resources.declare_namespace(__name__)
-except ImportError:
-    import pkgutil
-    __path__ = pkgutil.extend_path(__path__, __name__)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lazr_config-3.1/src/lazr/config/__init__.py 
new/lazr_config-4.0.0/src/lazr/config/__init__.py
--- old/lazr_config-3.1/src/lazr/config/__init__.py     2023-04-08 
18:39:40.000000000 +0200
+++ new/lazr_config-4.0.0/src/lazr/config/__init__.py   2026-08-01 
20:49:35.000000000 +0200
@@ -21,6 +21,13 @@
 # exported.
 from lazr.config._config import *  # noqa: F401, F403
 from lazr.config._config import __all__  # noqa: F401, F402
-from lazr.config._version import __version__
 
-__version__
+try:
+    import importlib.metadata as importlib_metadata
+except ImportError:  # pragma: no cover
+    import importlib_metadata
+
+try:
+    __version__ = importlib_metadata.version("lazr.config")
+except importlib_metadata.PackageNotFoundError:  # pragma: no cover
+    __version__ = importlib_metadata.version("lazr-config")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lazr_config-3.1/src/lazr/config/_config.py 
new/lazr_config-4.0.0/src/lazr/config/_config.py
--- old/lazr_config-3.1/src/lazr/config/_config.py      2023-04-08 
18:39:40.000000000 +0200
+++ new/lazr_config-4.0.0/src/lazr/config/_config.py    2026-08-01 
20:49:35.000000000 +0200
@@ -57,6 +57,7 @@
         parser.readfp(f, source)
 
 
+from lazr.delegates import delegate_to
 from zope.interface import implementer
 
 from lazr.config.interfaces import (
@@ -75,7 +76,6 @@
     UnknownKeyError,
     UnknownSectionError,
 )
-from lazr.delegates import delegate_to
 
 _missing = object()
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lazr_config-3.1/src/lazr/config/_version.py 
new/lazr_config-4.0.0/src/lazr/config/_version.py
--- old/lazr_config-3.1/src/lazr/config/_version.py     2025-02-05 
10:02:52.000000000 +0100
+++ new/lazr_config-4.0.0/src/lazr/config/_version.py   1970-01-01 
01:00:00.000000000 +0100
@@ -1 +0,0 @@
-__version__ = "3.1"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lazr_config-3.1/src/lazr/config/docs/conf.py 
new/lazr_config-4.0.0/src/lazr/config/docs/conf.py
--- old/lazr_config-3.1/src/lazr/config/docs/conf.py    2023-04-08 
18:39:40.000000000 +0200
+++ new/lazr_config-4.0.0/src/lazr/config/docs/conf.py  2026-08-01 
20:49:35.000000000 +0200
@@ -1,239 +1,36 @@
-# lazr.config documentation build configuration file, created by
-# sphinx-quickstart on Mon Jan  7 10:37:37 2013.
+#!/usr/bin/env python3
 #
-# This file is execfile()d with the current directory set to its containing
-# dir.
-#
-# Note that not all possible configuration values are present in this
-# autogenerated file.
-#
-# All configuration values have a default; values that are commented out
-# serve to show the default.
-
-# If extensions (or modules to document with autodoc) are in another directory,
-# add these directories to sys.path here. If the directory is relative to the
-# documentation root, use os.path.abspath to make it absolute, like shown here.
-# sys.path.insert(0, os.path.abspath('.'))
-
-# -- General configuration ----------------------------------------------------
+# lazr.config documentation build configuration file.
 
 from lazr.config import __version__
 
-# If your documentation needs a minimal Sphinx version, state it here.
-# needs_sphinx = '1.0'
+# -- General configuration ------------------------------------------------
 
-# Add any Sphinx extension module names here, as strings. They can be
-# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
 extensions = []
-
-# Add any paths that contain templates here, relative to this directory.
 templates_path = ["_templates"]
-
-# The suffix of source filenames.
 source_suffix = ".rst"
-
-# The encoding of source files.
-# source_encoding = 'utf-8-sig'
-
-# The master toctree document.
 master_doc = "index"
 
-# General information about the project.
 project = "lazr.config"
-copyright = "2013-2021, LAZR developers"
+copyright = "2008-2024, Canonical Ltd."
+author = "LAZR Developers <[email protected]>"
 
-# The version info for the project you're documenting, acts as replacement for
-# |version| and |release|, also used in various other places throughout the
-# built documents.
-#
-# The short X.Y version.
 version = __version__
-# The full version, including alpha/beta/rc tags.
-release = version
-
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-# language = None
-
-# There are two options for replacing |today|: either, you set today to some
-# non-false value, then it is used:
-# today = ''
-# Else, today_fmt is used as the format for a strftime call.
-# today_fmt = '%B %d, %Y'
+release = __version__
 
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
+language = "en"
 exclude_patterns = ["_build", "eggs"]
-
-# The reST default role (used for this markup: `text`) to use for all
-# documents.
-# default_role = None
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-# add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
-# add_module_names = True
-
-# If true, sectionauthor and moduleauthor directives will be shown in the
-# output. They are ignored by default.
-# show_authors = False
-
-# The name of the Pygments (syntax highlighting) style to use.
 pygments_style = "sphinx"
 
-# A list of ignored prefixes for module index sorting.
-# modindex_common_prefix = []
-
+# -- Options for HTML output ----------------------------------------------
 
-# -- Options for HTML output --------------------------------------------------
-
-# The theme to use for HTML and HTML Help pages.  See the documentation for
-# a list of builtin themes.
 html_theme = "alabaster"
-
-# Theme options are theme-specific and customize the look and feel of a theme
-# further.  For a list of options available for each theme, see the
-# documentation.
-# html_theme_options = {}
-
-# Add any paths that contain custom themes here, relative to this directory.
-# html_theme_path = []
-
-# The name for this set of Sphinx documents.  If None, it defaults to
-# "<project> v<release> documentation".
-# html_title = None
-
-# A shorter title for the navigation bar.  Default is the same as html_title.
-# html_short_title = None
-
-# The name of an image file (relative to this directory) to place at the top
-# of the sidebar.
-# html_logo = None
-
-# The name of an image file (within the static path) to use as favicon of the
-# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
-# pixels large.
-# html_favicon = None
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
 html_static_path = []
-
-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
-# using the given strftime format.
-# html_last_updated_fmt = '%b %d, %Y'
-
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-# html_use_smartypants = True
-
-# Custom sidebar templates, maps document names to template names.
-
-# This is required for the alabaster theme
-# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
 html_sidebars = {
     "**": [
-        "globaltoc.html",
-        "relations.html",  # needs 'show_related': True theme option to display
+        "relations.html",
         "searchbox.html",
     ]
 }
 
-# Additional templates that should be rendered to pages, maps page names to
-# template names.
-# html_additional_pages = {}
-
-# If false, no module index is generated.
-# html_domain_indices = True
-
-# If false, no index is generated.
-# html_use_index = True
-
-# If true, the index is split into individual pages for each letter.
-# html_split_index = False
-
-# If true, links to the reST sources are added to the pages.
-# html_show_sourcelink = True
-
-# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-# html_show_sphinx = True
-
-# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-# html_show_copyright = True
-
-# If true, an OpenSearch description file will be output, and all pages will
-# contain a <link> tag referring to it.  The value of this option must be the
-# base URL from which the finished HTML is served.
-# html_use_opensearch = ''
-
-# This is the file name suffix for HTML files (e.g. ".xhtml").
-# html_file_suffix = None
-
-# Output file base name for HTML help builder.
 htmlhelp_basename = "lazrconfigdoc"
-
-
-# -- Options for LaTeX output -------------------------------------------------
-
-# latex_elements = {
-# The paper size ('letterpaper' or 'a4paper').
-# 'papersize': 'letterpaper',
-
-# The font size ('10pt', '11pt' or '12pt').
-# 'pointsize': '10pt',
-
-# Additional stuff for the LaTeX preamble.
-# 'preamble': '',
-# }
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title, author, documentclass
-# [howto/manual]).
-
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-# latex_logo = None
-
-# For "manual" documents, if this is true, then toplevel headings are parts,
-# not chapters.
-# latex_use_parts = False
-
-# If true, show page references after internal links.
-# latex_show_pagerefs = False
-
-# If true, show URL addresses after external links.
-# latex_show_urls = False
-
-# Documents to append as an appendix to all manuals.
-# latex_appendices = []
-
-# If false, no module index is generated.
-# latex_domain_indices = True
-
-
-# -- Options for manual page output -------------------------------------------
-
-# One entry per manual page. List of tuples
-# (source start file, name, description, authors, manual section).
-
-# If true, show URL addresses after external links.
-# man_show_urls = False
-
-
-# -- Options for Texinfo output -----------------------------------------------
-
-# Grouping the document tree into Texinfo files. List of tuples
-# (source start file, target name, title, author,
-#  dir menu entry, description, category)
-
-# Documents to append as an appendix to all manuals.
-# texinfo_appendices = []
-
-# If false, no module index is generated.
-# texinfo_domain_indices = True
-
-# How to display URL addresses: 'footnote', 'no', or 'inline'.
-# texinfo_show_urls = 'footnote'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lazr_config-3.1/src/lazr/config/docs/index.rst 
new/lazr_config-4.0.0/src/lazr/config/docs/index.rst
--- old/lazr_config-3.1/src/lazr/config/docs/index.rst  2021-11-05 
14:00:38.000000000 +0100
+++ new/lazr_config-4.0.0/src/lazr/config/docs/index.rst        2026-08-01 
20:49:35.000000000 +0200
@@ -18,8 +18,10 @@
 configuration file. The schema is explicitly derived from the information in
 the configuration file.
 
-    >>> from pkg_resources import resource_string
-    >>> raw_schema = resource_string('lazr.config.tests.testdata', 'base.conf')
+    >>> import importlib.util
+    >>> from pathlib import Path
+    >>> _spec = importlib.util.find_spec('lazr.config.tests.testdata')
+    >>> raw_schema = (Path(_spec.origin).parent / 'base.conf').read_bytes()
 
 The config file contains sections enclosed in square brackets
 (e.g. ``[section]``).  The section name may be divided into major and minor
@@ -32,8 +34,7 @@
 A section with ``.optional`` suffix is not required.  Lines that start with a
 hash (``#``) are comments.
 
-    >>> from pkg_resources import resource_string
-    >>> raw_schema = resource_string('lazr.config.tests.testdata', 'base.conf')
+    >>> raw_schema = (Path(_spec.origin).parent / 'base.conf').read_bytes()
     >>> print(raw_schema.decode('utf-8'))
     # This section defines required keys and default values.
     [section_1]
@@ -70,10 +71,8 @@
 
     >>> from lazr.config import ConfigSchema
     >>> from lazr.config.interfaces import IConfigSchema
-    >>> from pkg_resources import resource_filename
     >>> from zope.interface.verify import verifyObject
-    >>> base_conf = resource_filename(
-    ...     'lazr.config.tests.testdata', 'base.conf')
+    >>> base_conf = str(Path(_spec.origin).parent / 'base.conf')
     >>> schema = ConfigSchema(base_conf)
     >>> verifyObject(IConfigSchema, schema)
     True
@@ -279,8 +278,7 @@
 
 The ``load()`` method accepts a filename.
 
-    >>> local_conf = resource_filename(
-    ...     'lazr.config.tests.testdata', 'local.conf')
+    >>> local_conf = str(Path(_spec.origin).parent / 'local.conf')
     >>> config = schema.load(local_conf)
 
 The ``loadFile()`` method accepts a file-like object and an optional filename
@@ -350,10 +348,8 @@
 These are like categories with templates except that the section names
 extending ``.master`` need not be named in the schema file.
 
-    >>> master_schema_conf = resource_filename(
-    ...     'lazr.config.tests.testdata', 'master.conf')
-    >>> master_local_conf = resource_filename(
-    ...     'lazr.config.tests.testdata', 'master-local.conf')
+    >>> master_schema_conf = str(Path(_spec.origin).parent / 'master.conf')
+    >>> master_local_conf = str(Path(_spec.origin).parent / 
'master-local.conf')
     >>> master_schema = ConfigSchema(master_schema_conf)
     >>> sections = master_schema.getByCategory('thing')
     >>> for name in sorted(section.name for section in sections):
@@ -376,8 +372,7 @@
 This config was loaded before ``local.conf`` because its sections and values
 are required to be in place before ``local.conf`` applies its changes.
 
-    >>> shared_config = resource_filename(
-    ...     'lazr.config.tests.testdata', 'shared.conf')
+    >>> shared_config = str(Path(_spec.origin).parent / 'shared.conf')
     >>> with open(shared_config, 'rt') as shared_file:
     ...     raw_conf = shared_file.read()
     >>> print(raw_conf)
@@ -722,8 +717,7 @@
 config to the schema).  The schema can also be pushed to reset the values in
 the config to the schema's default values.
 
-    >>> extender_conf_name = resource_filename(
-    ...     'lazr.config.tests.testdata', 'extender.conf')
+    >>> extender_conf_name = str(Path(_spec.origin).parent / 'extender.conf')
     >>> extender_conf_data = ("""
     ...     [meta]
     ...     extends: base.conf""")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lazr_config-3.1/src/lazr/config/tests/test_config.py 
new/lazr_config-4.0.0/src/lazr/config/tests/test_config.py
--- old/lazr_config-3.1/src/lazr/config/tests/test_config.py    2023-04-08 
18:39:40.000000000 +0200
+++ new/lazr_config-4.0.0/src/lazr/config/tests/test_config.py  2026-08-01 
20:49:35.000000000 +0200
@@ -21,22 +21,12 @@
 ]
 
 
+import importlib.util
 import unittest
-
-import pkg_resources
-
-try:
-    from configparser import MissingSectionHeaderError, NoSectionError
-except ImportError:
-    # Python 2
-    from ConfigParser import MissingSectionHeaderError, NoSectionError
-try:
-    from io import StringIO
-except ImportError:
-    # Python 2
-    from StringIO import StringIO
-
+from configparser import MissingSectionHeaderError, NoSectionError
+from io import StringIO
 from operator import attrgetter
+from pathlib import Path
 
 from zope.interface.exceptions import DoesNotImplement
 from zope.interface.verify import verifyObject
@@ -56,9 +46,8 @@
 
 class TestConfig(unittest.TestCase):
     def _testfile(self, conf_file):
-        return pkg_resources.resource_filename(
-            "lazr.config.tests.testdata", conf_file
-        )
+        spec = importlib.util.find_spec("lazr.config.tests.testdata")
+        return str(Path(spec.origin).parent / conf_file)
 
     def test_missing_category(self):
         schema = ConfigSchema(self._testfile("base.conf"))
@@ -146,8 +135,7 @@
     def test_all_config_errors(self):
         schema = ConfigSchema(self._testfile("base.conf"))
         config = schema.loadFile(
-            StringIO(
-                """
+            StringIO("""
 [meta]
 metakey: unsupported
 [unknown-section]
@@ -157,8 +145,7 @@
 key1: bad character in caf\xc3)
 [section_3.template]
 key1: schema suffixes are not permitted
-"""
-            ),
+"""),
             "bad config",
         )
         try:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lazr_config-3.1/src/lazr/config/tests/test_docs.py 
new/lazr_config-4.0.0/src/lazr/config/tests/test_docs.py
--- old/lazr_config-3.1/src/lazr/config/tests/test_docs.py      2023-04-08 
18:39:40.000000000 +0200
+++ new/lazr_config-4.0.0/src/lazr/config/tests/test_docs.py    2026-08-01 
20:49:35.000000000 +0200
@@ -1,33 +1,25 @@
-# Copyright 2009-2021 Canonical Ltd.  All rights reserved.
+# Copyright 2012 Canonical Ltd.  All rights reserved.
 #
-# This file is part of lazr.config.
+# This file is part of lazr.json
 #
-# lazr.config is free software: you can redistribute it and/or modify it
+# lazr.json is free software: you can redistribute it and/or modify it
 # under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, version 3 of the License.
 #
-# lazr.config is distributed in the hope that it will be useful, but WITHOUT
+# lazr.json is distributed in the hope that it will be useful, but WITHOUT
 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 # License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
-# along with lazr.config.  If not, see <http://www.gnu.org/licenses/>.
-
+# along with lazr.json.  If not, see <http://www.gnu.org/licenses/>.
 """Test harness for doctests."""
 
 __all__ = []
 
-import atexit
 import doctest
-import os
-
-from pkg_resources import (
-    cleanup_resources,
-    resource_exists,
-    resource_filename,
-    resource_listdir,
-)
+import importlib.util
+from pathlib import Path
 
 DOCTEST_FLAGS = (
     doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE | doctest.REPORT_NDIFF
@@ -37,15 +29,13 @@
 def load_tests(loader, tests, pattern):
     """Load the doc tests (docs/*, if any exist)."""
     doctest_files = []
-    if resource_exists("lazr.config", "docs"):
-        for name in resource_listdir("lazr.config", "docs"):
-            if name.endswith(".rst"):
-                doctest_files.append(
-                    os.path.abspath(
-                        resource_filename("lazr.config", "docs/%s" % name)
-                    )
-                )
-    atexit.register(cleanup_resources)
+    spec = importlib.util.find_spec("lazr.config")
+    if spec and spec.submodule_search_locations:
+        docs_path = Path(list(spec.submodule_search_locations)[0]) / "docs"
+        if docs_path.is_dir():
+            for path in docs_path.iterdir():
+                if path.name.endswith(".rst"):
+                    doctest_files.append(str(path.resolve()))
     tests.addTest(
         doctest.DocFileSuite(
             *doctest_files,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lazr_config-3.1/src/lazr.config.egg-info/PKG-INFO 
new/lazr_config-4.0.0/src/lazr.config.egg-info/PKG-INFO
--- old/lazr_config-3.1/src/lazr.config.egg-info/PKG-INFO       2025-02-05 
10:04:13.000000000 +0100
+++ new/lazr_config-4.0.0/src/lazr.config.egg-info/PKG-INFO     2026-08-01 
20:56:21.000000000 +0200
@@ -1,40 +1,42 @@
-Metadata-Version: 2.1
+Metadata-Version: 2.4
 Name: lazr.config
-Version: 3.1
+Version: 4.0.0
 Summary: Create configuration schemas, and process and validate configurations.
-Home-page: https://launchpad.net/lazr.config
-Download-URL: https://launchpad.net/lazr.config/+download
 Maintainer: LAZR Developers
-Maintainer-email: [email protected]
 License: LGPL v3
+Project-URL: Homepage, https://launchpad.net/lazr.config
 Project-URL: Source, https://code.launchpad.net/lazr.config
 Project-URL: Issue Tracker, https://bugs.launchpad.net/lazr.config
 Project-URL: Documentation, https://lazrconfig.readthedocs.io/en/latest/
+Project-URL: Download, https://launchpad.net/lazr.config/+download
 Classifier: Development Status :: 5 - Production/Stable
 Classifier: Intended Audience :: Developers
 Classifier: License :: OSI Approved :: GNU Library or Lesser General Public 
License (LGPL)
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3 :: Only
 Classifier: Programming Language :: Python :: 3.8
 Classifier: Programming Language :: Python :: 3.9
 Classifier: Programming Language :: Python :: 3.10
 Classifier: Programming Language :: Python :: 3.11
 Classifier: Programming Language :: Python :: 3.12
 Classifier: Programming Language :: Python :: 3.13
+Classifier: Programming Language :: Python :: 3.14
 Requires-Python: >=3.8
+Description-Content-Type: text/x-rst
 License-File: COPYING.txt
-Requires-Dist: setuptools
 Requires-Dist: zope.interface
 Requires-Dist: lazr.delegates
 Provides-Extra: docs
 Requires-Dist: Sphinx; extra == "docs"
+Provides-Extra: test
+Requires-Dist: zope.testing>=4.6.0; extra == "test"
+Requires-Dist: zope.testrunner>=6.6.1; extra == "test"
+Dynamic: license-file
 
+======================
+Welcome to lazr.config
+======================
 
-The LAZR config system is typically used to manage process configuration.
-Process configuration is for saying how things change when we run systems on
-different machines, or under different circumstances.
-
-This system uses ini-like file format of section, keys, and values.  The
-config file supports inheritance to minimize duplication of information across
-files. The format supports schema validation.
+Create configuration schemas, and process and validate configurations.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lazr_config-3.1/src/lazr.config.egg-info/SOURCES.txt 
new/lazr_config-4.0.0/src/lazr.config.egg-info/SOURCES.txt
--- old/lazr_config-3.1/src/lazr.config.egg-info/SOURCES.txt    2025-02-05 
10:04:13.000000000 +0100
+++ new/lazr_config-4.0.0/src/lazr.config.egg-info/SOURCES.txt  2026-08-01 
20:56:21.000000000 +0200
@@ -1,26 +1,22 @@
+.flake8
+.launchpad.yaml
 .pre-commit-config.yaml
 .readthedocs.yaml
-.woke.yaml
 CONTRIBUTING.rst
 COPYING.txt
 MANIFEST.in
 NEWS.rst
 README.rst
+SECURITY.md
 pyproject.toml
-setup.cfg
-setup.py
 tox.ini
-src/lazr/__init__.py
 src/lazr.config.egg-info/PKG-INFO
 src/lazr.config.egg-info/SOURCES.txt
 src/lazr.config.egg-info/dependency_links.txt
-src/lazr.config.egg-info/namespace_packages.txt
-src/lazr.config.egg-info/not-zip-safe
 src/lazr.config.egg-info/requires.txt
 src/lazr.config.egg-info/top_level.txt
 src/lazr/config/__init__.py
 src/lazr/config/_config.py
-src/lazr/config/_version.py
 src/lazr/config/interfaces.py
 src/lazr/config/docs/CONTRIBUTING.rst
 src/lazr/config/docs/NEWS.rst
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/lazr_config-3.1/src/lazr.config.egg-info/namespace_packages.txt 
new/lazr_config-4.0.0/src/lazr.config.egg-info/namespace_packages.txt
--- old/lazr_config-3.1/src/lazr.config.egg-info/namespace_packages.txt 
2025-02-05 10:04:13.000000000 +0100
+++ new/lazr_config-4.0.0/src/lazr.config.egg-info/namespace_packages.txt       
1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-lazr
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/lazr_config-3.1/src/lazr.config.egg-info/not-zip-safe 
new/lazr_config-4.0.0/src/lazr.config.egg-info/not-zip-safe
--- old/lazr_config-3.1/src/lazr.config.egg-info/not-zip-safe   2021-11-05 
12:58:52.000000000 +0100
+++ new/lazr_config-4.0.0/src/lazr.config.egg-info/not-zip-safe 1970-01-01 
01:00:00.000000000 +0100
@@ -1 +0,0 @@
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/lazr_config-3.1/src/lazr.config.egg-info/requires.txt 
new/lazr_config-4.0.0/src/lazr.config.egg-info/requires.txt
--- old/lazr_config-3.1/src/lazr.config.egg-info/requires.txt   2025-02-05 
10:04:13.000000000 +0100
+++ new/lazr_config-4.0.0/src/lazr.config.egg-info/requires.txt 2026-08-01 
20:56:21.000000000 +0200
@@ -1,6 +1,9 @@
-setuptools
 zope.interface
 lazr.delegates
 
 [docs]
 Sphinx
+
+[test]
+zope.testing>=4.6.0
+zope.testrunner>=6.6.1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lazr_config-3.1/tox.ini new/lazr_config-4.0.0/tox.ini
--- old/lazr_config-3.1/tox.ini 2025-01-27 10:15:56.000000000 +0100
+++ new/lazr_config-4.0.0/tox.ini       2026-08-01 20:49:35.000000000 +0200
@@ -1,60 +1,61 @@
 [tox]
+isolated_build = True
 envlist =
-    pre-commit
-    py38
-    py39
-    py310
-    py311
-    py312
-    py313
+    lint
+    py38,py39,py310,py311,py312,py313,py314
     coverage
     docs
-skip_missing_interpreters = True
+    audit
 
 [testenv]
+# Python 3.8 only: modern virtualenv seeds pip 26 / setuptools 82 into the env,
+# but pip 26 refuses to run on 3.8 and setuptools 82 dropped pkg_resources
+# (which zope.testrunner 6.6.1 -- the last 3.8-compatible release -- imports).
+# Pin the seeded pip and cap setuptools on 3.8 so pkg_resources stays 
available.
+# 3.9+ need neither: pip 26 runs there and zope.testrunner 8.x drops 
pkg_resources.
+# These are no-ops under tox-uv and on CI (focal ships compatible tooling).
+set_env =
+    py38: VIRTUALENV_PIP = 24.3.1
 deps =
+    .[test]
+    py38: setuptools < 81
     zope.testrunner
 commands =
     zope-testrunner --test-path src --tests-pattern ^tests {posargs}
 
-[testenv:pre-commit]
-# necessary to build the woke linter
-passenv = HOME
-commands =
-     pre-commit run --all-files
+[testenv:lint]
+# align with .launchpad.yaml
+basepython = python3.12
+skip_install = true
 deps =
-     pre-commit
+    pre-commit
+commands =
+    pre-commit run --all-files
 
-[flake8]
-ignore =
-     # flake8 errors from the E category will be mostly gone after
-     # applying black
-     E
-     # line break before/after binary operator
-     # mutually exclusive
-     W503
-     W504
+[testenv:coverage]
+basepython = python3.12
+deps =
+    .[test]
+    zope.testrunner
+    coverage
+commands =
+    coverage run --source lazr.config -m zope.testrunner \
+        --test-path src --tests-pattern ^tests {posargs}
+    coverage report --show-missing --fail-under=96
 
 [testenv:docs]
-basepython =
-    python3.11
-commands =
-    sphinx-build -b html -d src/lazr/config/docs/_build/doctrees 
src/lazr/config/docs src/lazr/config/docs/_build/html
+# align with .launchpad.yaml
+basepython = python3.12
 deps =
     .[docs]
+commands =
+    sphinx-build -b html -d src/lazr/config/docs/_build/doctrees 
src/lazr/config/docs src/lazr/config/docs/_build/html
 
-[testenv:coverage]
-basepython =
-    python3
+[testenv:audit]
+# align with .launchpad.yaml
+basepython = python3.12
 deps =
-    coverage
-    zope.testrunner
+    pip>=26.0
+    pip-audit
 commands =
-    coverage erase
-    coverage run -m zope.testrunner --test-path src --tests-pattern ^tests 
{posargs}
-    coverage html
-    coverage report -m  --fail-under=96
-
-[coverage:run]
-source = lazr.config
-omit = */docs/conf.py
+    pip-audit

Reply via email to