Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-xmldiff for openSUSE:Factory 
checked in at 2026-06-15 19:44:57
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-xmldiff (Old)
 and      /work/SRC/openSUSE:Factory/.python-xmldiff.new.1981 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-xmldiff"

Mon Jun 15 19:44:57 2026 rev:25 rq:1359310 version:3.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-xmldiff/python-xmldiff.changes    
2025-08-05 14:22:30.004280582 +0200
+++ /work/SRC/openSUSE:Factory/.python-xmldiff.new.1981/python-xmldiff.changes  
2026-06-15 19:48:19.783706034 +0200
@@ -1,0 +2,16 @@
+Sun Jun 14 20:10:27 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 3.0:
+  * Updated Python versions. 3.8 and 3.9 still works, but is
+    officially unsupported, added 3.13, 3.14 and 3.15 to the
+    supported versions.
+  * Speeding up diffing by using dequeue [barucden]
+  * Support namespace-prefixed move nodes [barucden]
+  * Improved matching in certain cases [barucden]
+  * UpdateTextIn() and UpdateTextAfter() now also has optional
+    parameters "oldtext" which contains the text before update,
+    or None, if there was no text.
+  * Fixed a bug in the parsing of diff files.
+- drop fix-error-type.patch (upstream)
+
+-------------------------------------------------------------------

Old:
----
  fix-error-type.patch
  xmldiff-2.7.0.tar.gz

New:
----
  xmldiff-3.0.tar.gz

----------(Old B)----------
  Old:  * Fixed a bug in the parsing of diff files.
- drop fix-error-type.patch (upstream)
----------(Old E)----------

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

Other differences:
------------------
++++++ python-xmldiff.spec ++++++
--- /var/tmp/diff_new_pack.rYveh2/_old  2026-06-15 19:48:20.379731079 +0200
+++ /var/tmp/diff_new_pack.rYveh2/_new  2026-06-15 19:48:20.383731248 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-xmldiff
 #
-# Copyright (c) 2025 SUSE LLC
+# Copyright (c) 2026 SUSE LLC and contributors
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,21 +18,18 @@
 
 %define oldpython python
 Name:           python-xmldiff
-Version:        2.7.0
+Version:        3.0
 Release:        0
 Summary:        Tree to tree correction between XML documents
 License:        MIT
 URL:            https://github.com/Shoobx/xmldiff
 Source:         
https://files.pythonhosted.org/packages/source/x/xmldiff/xmldiff-%{version}.tar.gz
-# PATCH-FIX-UPSTREAM fix-error-type.patch taken from 
https://github.com/Shoobx/xmldiff/commit/57e16ce3d92067c6246c3de04f2d4b9803f6f25b
-Patch0:         fix-error-type.patch
 BuildRequires:  %{python_module pip}
-BuildRequires:  %{python_module setuptools}
+BuildRequires:  %{python_module setuptools >= 61.2}
 BuildRequires:  %{python_module wheel}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
 Requires:       python-lxml >= 3.1.0
-Requires:       python-setuptools
 Requires(post): update-alternatives
 Requires(postun): update-alternatives
 Conflicts:      %{oldpython}-xmldiff < %{version}

++++++ xmldiff-2.7.0.tar.gz -> xmldiff-3.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/.pre-commit-config.yaml 
new/xmldiff-3.0/.pre-commit-config.yaml
--- old/xmldiff-2.7.0/.pre-commit-config.yaml   1970-01-01 01:00:00.000000000 
+0100
+++ new/xmldiff-3.0/.pre-commit-config.yaml     2026-06-11 17:00:00.000000000 
+0200
@@ -0,0 +1,18 @@
+repos:
+-   repo: https://github.com/pre-commit/pre-commit-hooks
+    rev: v4.5.0
+    hooks:
+    -   id: check-yaml
+    -   id: trailing-whitespace
+- repo: https://github.com/astral-sh/ruff-pre-commit
+  # Ruff version.
+  rev: v0.12.2
+  hooks:
+    # Run the linter.
+    - id: ruff-check
+    # Run the formatter.
+    - id: ruff-format
+-   repo: https://github.com/regebro/pyroma
+    rev: '5.0b2'
+    hooks:
+    -   id: pyroma
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/CHANGES.rst new/xmldiff-3.0/CHANGES.rst
--- old/xmldiff-2.7.0/CHANGES.rst       2024-05-13 14:15:38.000000000 +0200
+++ new/xmldiff-3.0/CHANGES.rst 2026-06-11 17:00:00.000000000 +0200
@@ -1,6 +1,28 @@
 Changes
 =======
 
+3.0 (2026-06-11)
+----------------
+
+- Updated Python versions. 3.8 and 3.9 still works, but is officially 
unsupported,
+  added 3.13, 3.14 and 3.15 to the supported versions.
+
+- Speeding up diffing by using dequeue [barucden]
+
+- Support namespace-prefixed move nodes [barucden]
+
+- Improved matching in certain cases [barucden]
+
+
+3.0b1 (2025-07-14)
+------------------
+
+- UpdateTextIn() and UpdateTextAfter() now also has optional parameters 
"oldtext"
+  which contains the text before update, or None, if there was no text.
+
+- Fixed a bug in the parsing of diff files.
+
+
 2.7.0 (2024-05-13)
 ------------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/CHANGES.txt new/xmldiff-3.0/CHANGES.txt
--- old/xmldiff-2.7.0/CHANGES.txt       2024-05-13 14:15:38.000000000 +0200
+++ new/xmldiff-3.0/CHANGES.txt 1970-01-01 01:00:00.000000000 +0100
@@ -1,7 +0,0 @@
-- Added option to XMLFormatter to use replace tags
-
-- in _make_diff_tags after diffing, neighboring delete/insert diffs are joined 
to a replace tag
-
-- the deleted text is added as an attribute ("old-text")
-
-- the inserted text is the element's text
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/MANIFEST.in new/xmldiff-3.0/MANIFEST.in
--- old/xmldiff-2.7.0/MANIFEST.in       2024-05-13 14:15:38.000000000 +0200
+++ new/xmldiff-3.0/MANIFEST.in 2026-06-11 17:00:00.000000000 +0200
@@ -14,3 +14,6 @@
 recursive-include docs *.xslt
 recursive-include docs Makefile
 recursive-exclude docs/build *
+
+# added by check-manifest
+include *.yaml
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/Makefile new/xmldiff-3.0/Makefile
--- old/xmldiff-2.7.0/Makefile  2024-05-13 14:15:38.000000000 +0200
+++ new/xmldiff-3.0/Makefile    2026-06-11 17:00:00.000000000 +0200
@@ -14,8 +14,7 @@
        $(bin_dir)/pip install -e .[devenv]
 
 check: devenv
-       $(bin_dir)/black xmldiff tests
-       $(bin_dir)/flake8 xmldiff tests
+       $(bin_dir)/ruff check xmldiff tests
        $(bin_dir)/pyroma -d .
 
 coverage: devenv
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/PKG-INFO new/xmldiff-3.0/PKG-INFO
--- old/xmldiff-2.7.0/PKG-INFO  2024-05-13 14:15:38.185385700 +0200
+++ new/xmldiff-3.0/PKG-INFO    2026-06-11 17:00:01.086637300 +0200
@@ -1,36 +1,35 @@
 Metadata-Version: 2.1
 Name: xmldiff
-Version: 2.7.0
+Version: 3.0
 Summary: Creates diffs of XML files
-Home-page: https://github.com/Shoobx/xmldiff
-Author: Lennart Regebro
-Author-email: [email protected]
+Author-email: Lennart Regebro <[email protected]>
 License: MIT
+Project-URL: Homepage, https://github.com/Shoobx/xmldiff
 Project-URL: Source Code, https://github.com/Shoobx/xmldiff
-Keywords: xml,html,diff
+Keywords: diff,html,xml
 Classifier: Development Status :: 4 - Beta
 Classifier: Intended Audience :: Developers
 Classifier: Intended Audience :: End Users/Desktop
-Classifier: Topic :: Text Processing :: Markup :: XML
-Classifier: License :: OSI Approved :: MIT License
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3 :: Only
+Classifier: Programming Language :: Python :: Implementation :: PyPy
 Classifier: Programming Language :: Python :: 3.10
 Classifier: Programming Language :: Python :: 3.11
 Classifier: Programming Language :: Python :: 3.12
-Classifier: Programming Language :: Python :: 3 :: Only
-Classifier: Programming Language :: Python :: Implementation :: PyPy
+Classifier: Programming Language :: Python :: 3.13
+Classifier: Programming Language :: Python :: 3.14
+Classifier: Programming Language :: Python :: 3.15
+Classifier: Topic :: Text Processing :: Markup :: XML
+Classifier: License :: OSI Approved :: MIT License
 Requires-Python: >=3.8
+Description-Content-Type: text/x-rst
 License-File: LICENSE.txt
-Requires-Dist: setuptools
 Requires-Dist: lxml>=3.1.0
 Provides-Extra: devenv
-Requires-Dist: black; extra == "devenv"
-Requires-Dist: coverage; extra == "devenv"
-Requires-Dist: flake8; extra == "devenv"
+Requires-Dist: ruff; extra == "devenv"
+Requires-Dist: pyroma>=5.0b1; extra == "devenv"
 Requires-Dist: zest.releaser[recommended]; extra == "devenv"
 
 xmldiff
@@ -127,158 +126,10 @@
 
  * Thomas Pfitzinger, [email protected]
 
+ * Alexandre Detiste
+
+ *  Denis Barucic, [email protected]
+
 The diff algorithm is based on
 "`Change Detection in Hierarchically Structured Information 
<http://infolab.stanford.edu/c3/papers/html/tdiff3-8/tdiff3-8.html>`_",
 and the text diff is using Google's ``diff_match_patch`` algorithm.
-
-Changes
-=======
-
-2.7.0 (2024-05-13)
-------------------
-
-- Changed the comparison to make accurate and standard more accurate,
-  although fast gets less accurate as a result.
-
-- Changed usage of deprecated `pkg_resources` package to `importlib.metadata`.
-
-- A `use_replace` flag was added to the `XMLFormatter` by Thomas Pfitzinger.
-  It changes text replacement from delete and insert tags to a replace tag.
-  It's not currently accessaible thtough the CLI, the question is it is better
-  to add a new formatter name, or an option to pass in formatter flags.
-
-  - Added option to XMLFormatter to use replace tags
-  - in _make_diff_tags after diffing, neighboring delete/insert diffs are 
joined to a replace tag
-  - the deleted text is added as an attribute ("old-text")
-  - the inserted text is the element's text
-
-2.6.3 (2023-05-21)
-------------------
-
-- And there was a namespace bug in the patch as well. #118
-
-
-2.6.2 (2023-05-21)
-------------------
-
-- Solved an error in the xmlformatter when using default namespaces. #89
-
-
-2.6.1 (2023-04-05)
-------------------
-
-- #108: Fixed an error that happens if using namespaces like ns0 or ns1.
-
-
-2.6 (2023-04-03)
-----------------
-
-- Added `InsertNamespace` and `DeleteNamespace` actions for better handling
-  of changing namespaces. Should improve any "Unknown namespace prefix"
-  errors. Changing the URI of a a namespace prefix is not supported, and will
-  raise an error.
-
-2.6b1 (2023-01-12)
-------------------
-
-- Used geometric mean for the node_ratio, for better handling of simple nodes.
-
-- Added an experimental --best-match method that is slower, but generate
-  smaller diffs when you have many nodes that are similar.
-
-- The -F argument now also affects the --fast-match stage.
-
-
-2.5 (2023-01-11)
-----------------
-
-- Make it possible to adjust the attributes considered when comparing nodes.
-
-- Python versions 3.7 to 3.11 are now supported.
-
-- Improved node matching method, that puts more emphasis similarities than
-  differences when weighing attributes vs children.
-
-- Added a parameter to return error code 1 when there are differences between 
the files
-
-- Added a parameter for ignoring attributes in comparison.
-
-- Solved a bug in xmlpatch in certain namespace situations.
-
-- Added a --diff-encoding parameter to xmlpatch, to support diff-files that are
-  not in your system default encoding.
-
-
-2.4 (2019-10-09)
-----------------
-
-- Added an option to pass pairs of (element, attr) as unique
-  attributes for tree matching.  Exposed this option on the command
-  line, too.
-
-
-2.3 (2019-02-27)
-----------------
-
-- Added a simple ``xmlpatch`` command and API.
-
-- Multiple updates to documentation and code style
-
-
-2.2 (2018-10-12)
-----------------
-
-- A workaround for dealing with top level comments and the xml formatter
-
-
-2.1 (2018-10-03)
-----------------
-
-- Changed the substitution unicode character area to use the Private Use Area
-  in BMP(0), to support narrow Python builds
-
-- Added --unique-attributes argument.
-
-
-2.1b1 (2018-10-01)
-------------------
-
-- Added options for faster node comparisons. The "middle" option is now
-  default, it had very few changes in matches, but is much faster.
-
-- Implemented a Fast Match algorithm for even faster diffing.
-
-- Speed improvements through caching
-
-- Fixed a bug where MoveNode actions sometimes was in the wrong order
-
-- Added an InsertComment action, as comments require different handling,
-  so it's easier to deal with them this way. You can still use DeleteNode and
-  UpdateTextIn for them with no special handling.
-
-- When renaming tags the XMLFormatter will mark them with "diff:rename"
-  instead of making a new tag and deleting the old.
-
-- Tags will now be moved first, and updated and renamed later, as the new
-  tag name or attributes might not be valid in the old location.
-
-
-2.0 (2018-09-25)
-----------------
-
-- A complete, bottom-up, pure-python rewrite
-
-- New easy API
-
-- 100% test coverage
-
-- New output formats:
-
-  - A new default output format with new actions
-
-  - A format intended to be parseable by anyone parsing the old format.
-
-  - XML with changes marked though tags and attributes
-
-- xmldiff 2.0 is significantly slower than xmldiff 0.6 or 1.0,
-  the emphasis so far is on correctness, not speed.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/README.rst new/xmldiff-3.0/README.rst
--- old/xmldiff-2.7.0/README.rst        2024-05-13 14:15:38.000000000 +0200
+++ new/xmldiff-3.0/README.rst  2026-06-11 17:00:00.000000000 +0200
@@ -92,6 +92,10 @@
 
  * Thomas Pfitzinger, [email protected]
 
+ * Alexandre Detiste
+
+ *  Denis Barucic, [email protected]
+
 The diff algorithm is based on
 "`Change Detection in Hierarchically Structured Information 
<http://infolab.stanford.edu/c3/papers/html/tdiff3-8/tdiff3-8.html>`_",
 and the text diff is using Google's ``diff_match_patch`` algorithm.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/docs/source/advanced.rst 
new/xmldiff-3.0/docs/source/advanced.rst
--- old/xmldiff-2.7.0/docs/source/advanced.rst  2024-05-13 14:15:38.000000000 
+0200
+++ new/xmldiff-3.0/docs/source/advanced.rst    2026-06-11 17:00:00.000000000 
+0200
@@ -18,7 +18,7 @@
   >>> left = '<body><p>Old Content</p></body>'
   >>> right = '<body><p>New Content</p></body>'
   >>> main.diff_texts(left, right)
-  [UpdateTextIn(node='/body/p[1]', text='New Content')]
+  [UpdateTextIn(node='/body/p[1]', text='New Content', oldtext='Old Content')]
 
 The ``xml`` formatter will set tags around the text marking it as inserted or 
deleted:
 
@@ -211,8 +211,8 @@
   >>> result = main.diff_texts(left, right,
   ...     diff_options={'fast_match': True})
   >>> result
-  [UpdateTextIn(node='/html/body/p[1]', text='Last paragraph'),
-   UpdateTextIn(node='/html/body/p[3]', text='The First paragraph')]
+  [UpdateTextIn(node='/html/body/p[1]', text='Last paragraph', oldtext='The 
First paragraph'),
+   UpdateTextIn(node='/html/body/p[3]', text='The First paragraph', 
oldtext='Last paragraph')]
 
 Now we instead got two update actions.
 This means the resulting HTML is quite different:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/docs/source/api.rst 
new/xmldiff-3.0/docs/source/api.rst
--- old/xmldiff-2.7.0/docs/source/api.rst       2024-05-13 14:15:38.000000000 
+0200
+++ new/xmldiff-3.0/docs/source/api.rst 2026-06-11 17:00:00.000000000 +0200
@@ -14,9 +14,9 @@
   >>> main.diff_files("../tests/test_data/insert-node.left.html",
   ...                 "../tests/test_data/insert-node.right.html",
   ...                 diff_options={'F': 0.5, 'ratio_mode': 'fast'})
-  [UpdateTextIn(node='/body/div[1]', text=None),
+  [UpdateTextIn(node='/body/div[1]', text=None, oldtext='\n  '),
    InsertNode(target='/body/div[1]', tag='p', position=0),
-   UpdateTextIn(node='/body/div/p[1]', text='Simple text')]
+   UpdateTextIn(node='/body/div/p[1]', text='Simple text', oldtext=None)]
 
 Which one you choose depends on if the XML is contained in files,
 text strings or ``lxml`` trees.
@@ -182,9 +182,9 @@
   >>> print(main.diff_files("../tests/test_data/insert-node.left.html",
   ...                       "../tests/test_data/insert-node.right.html",
   ...                       formatter=formatter))
-  [update-text, /body/div[1], null]
+  [update-text, /body/div[1], null, "\n  "]
   [insert, /body/div[1], p, 0]
-  [update-text, /body/div/p[1], "Simple text"]
+  [update-text, /body/div/p[1], "Simple text", null]
 
 
 XmlDiffFormatter
@@ -405,7 +405,7 @@
   >>> left = '<document><node>Content</node></document>'
   >>> right = '<document><node>New Content</node></document>'
   >>> main.diff_texts(left, right)
-  [UpdateTextIn(node='/document/node[1]', text='New Content')]
+  [UpdateTextIn(node='/document/node[1]', text='New Content', 
oldtext='Content')]
 
 
 ``UpdateTextAfter(node, name)``
@@ -422,7 +422,7 @@
   >>> left = '<document><node>Content</node></document>'
   >>> right = '<document><node>Content</node>Trailing text</document>'
   >>> main.diff_texts(left, right)
-  [UpdateTextAfter(node='/document/node[1]', text='Trailing text')]
+  [UpdateTextAfter(node='/document/node[1]', text='Trailing text', 
oldtext=None)]
 
 
 ``InsertComment(target, position, text)``
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/pyproject.toml 
new/xmldiff-3.0/pyproject.toml
--- old/xmldiff-2.7.0/pyproject.toml    1970-01-01 01:00:00.000000000 +0100
+++ new/xmldiff-3.0/pyproject.toml      2026-06-11 17:00:00.000000000 +0200
@@ -0,0 +1,66 @@
+[build-system]
+requires = ["setuptools>=61.2"]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "xmldiff"
+version = "3.0"
+description = "Creates diffs of XML files"
+readme = "README.rst"
+license = { text = "MIT" }
+requires-python = ">=3.8"
+authors = [
+    { name = "Lennart Regebro", email = "[email protected]" },
+]
+keywords = [
+    "diff",
+    "html",
+    "xml",
+]
+classifiers = [
+    "Development Status :: 4 - Beta",
+    "Intended Audience :: Developers",
+    "Intended Audience :: End Users/Desktop",
+    "Operating System :: OS Independent",
+    "Programming Language :: Python",
+    "Programming Language :: Python :: 3",
+    "Programming Language :: Python :: 3 :: Only",
+    "Programming Language :: Python :: Implementation :: PyPy",
+    "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",
+    "Programming Language :: Python :: 3.15",
+    "Topic :: Text Processing :: Markup :: XML",
+    "License :: OSI Approved :: MIT License",
+]
+dependencies = [
+    "lxml>=3.1.0",
+]
+
+[project.optional-dependencies]
+devenv = [
+    "ruff",
+    "pyroma>=5.0b1",
+    "zest.releaser[recommended]",
+]
+
+[project.scripts]
+xmldiff = "xmldiff.main:diff_command"
+xmlpatch = "xmldiff.main:patch_command"
+
+[project.urls]
+Homepage = "https://github.com/Shoobx/xmldiff";
+"Source Code" = "https://github.com/Shoobx/xmldiff";
+
+[tool.setuptools]
+packages = ["xmldiff"]
+include-package-data = true
+zip-safe = false
+
+[tool.ruff]
+exclude = ["xmldiff/diff_match_patch.py"]
+
+[tool.zest.releaser]
+create-wheel = true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/setup.cfg new/xmldiff-3.0/setup.cfg
--- old/xmldiff-2.7.0/setup.cfg 2024-05-13 14:15:38.185385700 +0200
+++ new/xmldiff-3.0/setup.cfg   2026-06-11 17:00:01.086637300 +0200
@@ -1,77 +1,3 @@
-[metadata]
-name = xmldiff
-version = 2.7.0
-description = Creates diffs of XML files
-long_description = file: README.rst, CHANGES.rst
-classifiers = 
-       Development Status :: 4 - Beta
-       Intended Audience :: Developers
-       Intended Audience :: End Users/Desktop
-       Topic :: Text Processing :: Markup :: XML
-       License :: OSI Approved :: MIT License
-       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 :: Only
-       Programming Language :: Python :: Implementation :: PyPy
-keywords = xml, html, diff
-author = Lennart Regebro
-author_email = [email protected]
-url = https://github.com/Shoobx/xmldiff
-license = MIT
-project_urls = 
-       Source Code = https://github.com/Shoobx/xmldiff
-
-[options]
-python_requires = >=3.8
-zip_safe = True
-include_package_data = True
-packages = find:
-package_dir = 
-       = .
-install_requires = 
-       setuptools
-       lxml>=3.1.0
-
-[options.packages.find]
-where = .
-exclude = 
-       doc
-       tests
-
-[options.extras_require]
-devenv = 
-       black
-       coverage
-       flake8
-       zest.releaser[recommended]
-
-[options.entry_points]
-console_scripts = 
-       xmldiff = xmldiff.main:diff_command
-       xmlpatch = xmldiff.main:patch_command
-
-[flake8]
-max-line-length = 120
-exclude = 
-       xmldiff/*diff_match_patch*.py
-
-[tool:pytest]
-testpaths = 
-       tests
-
-[check-manifest]
-ignore = 
-       .pre-commit-config.yaml
-
-[zest.releaser]
-create-wheel = yes
-
 [egg_info]
 tag_build = 
 tag_date = 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/setup.py new/xmldiff-3.0/setup.py
--- old/xmldiff-2.7.0/setup.py  2024-05-13 14:15:38.000000000 +0200
+++ new/xmldiff-3.0/setup.py    1970-01-01 01:00:00.000000000 +0100
@@ -1,3 +0,0 @@
-from setuptools import setup
-
-setup()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/tests/test_diff.py 
new/xmldiff-3.0/tests/test_diff.py
--- old/xmldiff-2.7.0/tests/test_diff.py        2024-05-13 14:15:38.000000000 
+0200
+++ new/xmldiff-3.0/tests/test_diff.py  2026-06-11 17:00:00.000000000 +0200
@@ -966,6 +966,24 @@
             ],
         )
 
+    def test_best_match_no_double_match(self):
+        left = """\
+<a>
+    <p>x<b>xy</b></p>
+</a>
+"""
+        right = """\
+<a>
+    <p>x</p>
+</a>
+"""
+        matches = self._match(left, right, best_match=True)
+        # All matched paths should be exactly equal,
+        # and /a/p/b should not be matched with anything
+        for lpath, rpath in matches:
+            self.assertEqual(lpath, rpath)
+        self.assertNotIn("/a/p/b", [m[0] for m in matches])
+
 
 class UpdateNodeTests(unittest.TestCase):
     """Testing only the update phase of the diffing"""
@@ -1019,8 +1037,8 @@
                 RenameAttrib("/root/node[1]", "attr1", "attr4"),
                 InsertAttrib("/root/node[1]", "attr5", "new"),
                 DeleteAttrib("/root/node[1]", "attr0"),
-                UpdateTextIn("/root/node[1]", "The new text"),
-                UpdateTextAfter("/root/node[1]", "Also a tail!"),
+                UpdateTextIn("/root/node[1]", "The new text", "The contained 
text"),
+                UpdateTextAfter("/root/node[1]", "Also a tail!", "And a 
tail!"),
             ],
         )
 
@@ -1263,8 +1281,9 @@
                 InsertAttrib("/document/story/app:section[4]/app:term[1]", 
"set", "ol"),
                 InsertNode("/document/story/app:section[4]", "para", 1),
                 UpdateTextIn(
-                    "/document/story/app:section[1]/para[2]/" 
"app:placeholder[1]",
+                    
"/document/story/app:section[1]/para[2]/app:placeholder[1]",
                     "consectetur",
+                    "vestibulum",
                 ),
                 InsertNode(
                     "/document/story/app:section[4]/para[1]",
@@ -1305,14 +1324,30 @@
                     "/document/story/app:section[4]/para/app:placeholder[1]",
                     "asellus congue accumsan tempor. Donec vel risus se",
                 ),
-                UpdateTextIn("/document/story/app:section[5]/para/app:ref[1]", 
"4"),
-                UpdateTextIn("/document/story/app:section[6]/para/app:ref[1]", 
"5"),
-                UpdateTextIn("/document/story/app:section[7]/para/app:ref[1]", 
"6"),
-                UpdateTextIn("/document/story/app:section[8]/para/app:ref[1]", 
"7"),
-                UpdateTextIn("/document/story/app:section[9]/para/app:ref[1]", 
"8"),
-                
UpdateTextIn("/document/story/app:section[10]/para/app:ref[1]", "9"),
-                
UpdateTextIn("/document/story/app:section[11]/para/app:ref[1]", "10"),
-                
UpdateTextIn("/document/story/app:section[12]/para/app:ref[1]", "11"),
+                UpdateTextIn(
+                    "/document/story/app:section[5]/para/app:ref[1]", "4", "3"
+                ),
+                UpdateTextIn(
+                    "/document/story/app:section[6]/para/app:ref[1]", "5", "4"
+                ),
+                UpdateTextIn(
+                    "/document/story/app:section[7]/para/app:ref[1]", "6", "5"
+                ),
+                UpdateTextIn(
+                    "/document/story/app:section[8]/para/app:ref[1]", "7", "6"
+                ),
+                UpdateTextIn(
+                    "/document/story/app:section[9]/para/app:ref[1]", "8", "7"
+                ),
+                UpdateTextIn(
+                    "/document/story/app:section[10]/para/app:ref[1]", "9", "8"
+                ),
+                UpdateTextIn(
+                    "/document/story/app:section[11]/para/app:ref[1]", "10", 
"9"
+                ),
+                UpdateTextIn(
+                    "/document/story/app:section[12]/para/app:ref[1]", "11", 
"10"
+                ),
                 InsertNode("/document/story/app:section[4]/para/u[1]", "b", 0),
                 UpdateTextIn(
                     "/document/story/app:section[4]/para/u/b[1]", "ger nec 
ferme"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/tests/test_formatting.py 
new/xmldiff-3.0/tests/test_formatting.py
--- old/xmldiff-2.7.0/tests/test_formatting.py  2024-05-13 14:15:38.000000000 
+0200
+++ new/xmldiff-3.0/tests/test_formatting.py    2026-06-11 17:00:00.000000000 
+0200
@@ -63,7 +63,7 @@
         replacer.do_element(element)
 
         self.assertEqual(
-            element.text, "This \ue007 a \ue008 with \ue00aformatted" "\ue009 
text."
+            element.text, "This \ue007 a \ue008 with \ue00aformatted\ue009 
text."
         )
 
         replacer.undo_element(element)
@@ -79,7 +79,7 @@
         replacer.do_element(element)
 
         self.assertEqual(
-            element.text, "This is \ue008doubly \ue00aformatted\ue009" "\ue007 
text."
+            element.text, "This is \ue008doubly \ue00aformatted\ue009\ue007 
text."
         )
 
         replacer.undo_element(element)
@@ -153,7 +153,7 @@
 
             #
             self.assertEqual(
-                element.text, "This \uf906 a \uf907 with \uf909some" "\uf908 
text."
+                element.text, "This \uf906 a \uf907 with \uf909some\uf908 
text."
             )
 
             try:
@@ -172,8 +172,7 @@
                 # This should raise an error on a narrow build
                 self.assertEqual(
                     element.text,
-                    "This \U00010006 a \U00010007 with \U00010009some"
-                    "\U00010008 text.",
+                    "This \U00010006 a \U00010007 with 
\U00010009some\U00010008 text.",
                 )
             except ValueError:
                 if sys.maxunicode > 0x10000:
@@ -227,7 +226,7 @@
     def test_insert_attr(self):
         left = "<document><node>We need more text</node></document>"
         action = actions.InsertAttrib("/document/node", "attr", "val")
-        expected = START + ' attr="val" diff:add-attr="attr">' "We need more 
text" + END
+        expected = START + ' attr="val" diff:add-attr="attr">We need more 
text' + END
 
         self._format_test(left, action, expected)
 
@@ -243,7 +242,7 @@
         # renamed:
         left = '<document><node attr="val">Text</node></document>'
         action = actions.RenameAttrib("/document/node", "attr", "bottr")
-        expected = START + ' bottr="val" diff:rename-attr="attr:bottr"' 
">Text" + END
+        expected = START + ' bottr="val" diff:rename-attr="attr:bottr">Text' + 
END
 
         self._format_test(left, action, expected)
 
@@ -271,14 +270,14 @@
     def test_rename_node(self):
         left = "<document><node><para>Content</para>Tail</node></document>"
         action = actions.RenameNode("/document/node[1]/para[1]", "newtag")
-        expected = START + '><newtag diff:rename="para">Content' 
"</newtag>Tail" + END
+        expected = START + '><newtag diff:rename="para">Content</newtag>Tail' 
+ END
 
         self._format_test(left, action, expected)
 
     def test_update_attr(self):
         left = '<document><node attr="val"/></document>'
         action = actions.UpdateAttrib("/document/node", "attr", "newval")
-        expected = START + ' attr="newval" diff:update-attr="attr:val"/>' 
"</document>"
+        expected = START + ' attr="newval" 
diff:update-attr="attr:val"/></document>'
 
         self._format_test(left, action, expected)
 
@@ -302,7 +301,7 @@
     def test_update_text_after_1(self):
         left = "<document><node/><node/></document>"
         action = actions.UpdateTextAfter("/document/node[1]", "Text")
-        expected = START + "/><diff:insert>Text</diff:insert>" 
"<node/></document>"
+        expected = START + 
"/><diff:insert>Text</diff:insert><node/></document>"
 
         self._format_test(left, action, expected)
 
@@ -337,7 +336,7 @@
     def test_replace_text_after_1(self):
         left = "<document><node/><node/></document>"
         action = actions.UpdateTextAfter("/document/node[1]", "Text")
-        expected = START + "/><diff:insert>Text</diff:insert>" 
"<node/></document>"
+        expected = START + 
"/><diff:insert>Text</diff:insert><node/></document>"
 
         self._format_test(left, action, expected, use_replace=True)
 
@@ -381,7 +380,7 @@
 
     def test_del_text(self):
         action = actions.UpdateTextIn("/document/node", None)
-        expected = "[update-text, /document/node, null]"
+        expected = "[update-text, /document/node, null, null]"
         self._format_test(action, expected)
 
     def test_insert_attr(self):
@@ -430,21 +429,25 @@
 
     def test_update_text_in(self):
         action = actions.UpdateTextIn("/document/node", "Text")
-        expected = '[update-text, /document/node, "Text"]'
+        expected = '[update-text, /document/node, "Text", null]'
         self._format_test(action, expected)
 
         action = actions.UpdateTextIn("/document/node", 'Also a bit of text, 
"rick"')
-        expected = "[update-text, /document/node, " '"Also a bit of text, 
\\"rick\\""]'
+        expected = (
+            '[update-text, /document/node, "Also a bit of text, \\"rick\\"", 
null]'
+        )
         self._format_test(action, expected)
 
     def test_update_text_after_1(self):
         action = actions.UpdateTextAfter("/document/node[1]", "Text")
-        expected = '[update-text-after, /document/node[1], "Text"]'
+        expected = '[update-text-after, /document/node[1], "Text", null]'
         self._format_test(action, expected)
 
     def test_update_text_after_2(self):
         action = actions.UpdateTextAfter("/document/node", "Also a bit of 
text, rick")
-        expected = "[update-text-after, /document/node, " '"Also a bit of 
text, rick"]'
+        expected = (
+            '[update-text-after, /document/node, "Also a bit of text, rick", 
null]'
+        )
         self._format_test(action, expected)
 
     def test_insert_comment(self):
@@ -511,7 +514,7 @@
 
         action = actions.UpdateTextIn("/document/node", 'Also a bit of text, 
"rick"')
         expected = (
-            "[update, /document/node/text()[1], " '"Also a bit of text, 
\\"rick\\""]'
+            '[update, /document/node/text()[1], "Also a bit of text, 
\\"rick\\""]'
         )
         self._format_test(action, expected)
 
@@ -522,7 +525,7 @@
 
     def test_update_text_after_2(self):
         action = actions.UpdateTextAfter("/document/node", "Also a bit of 
text, rick")
-        expected = "[update, /document/node/text()[2], " '"Also a bit of text, 
rick"]'
+        expected = '[update, /document/node/text()[2], "Also a bit of text, 
rick"]'
         self._format_test(action, expected)
 
     def test_all_actions(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/tests/test_main.py 
new/xmldiff-3.0/tests/test_main.py
--- old/xmldiff-2.7.0/tests/test_main.py        2024-05-13 14:15:38.000000000 
+0200
+++ new/xmldiff-3.0/tests/test_main.py  2026-06-11 17:00:00.000000000 +0200
@@ -44,7 +44,7 @@
         with open(LEFT_FILE, "rb") as infile:
             with open(RIGHT_FILE, "rb") as infile:
                 # Give something else, and it fails:
-                with self.assertRaises(ValueError):
+                with self.assertRaises(TypeError):
                     main.diff_texts(infile, infile)
 
     def test_api_diff_trees(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/tests/test_patch.py 
new/xmldiff-3.0/tests/test_patch.py
--- old/xmldiff-2.7.0/tests/test_patch.py       2024-05-13 14:15:38.000000000 
+0200
+++ new/xmldiff-3.0/tests/test_patch.py 2026-06-11 17:00:00.000000000 +0200
@@ -23,12 +23,10 @@
 
 
 class PatcherTests(unittest.TestCase):
-    patcher = Patcher()
-
     def _test(self, start, action, end):
-        tree = etree.fromstring(start)
-        self.patcher.handle_action(action, tree)
-        self.assertEqual(etree.tounicode(tree), end)
+        patcher = Patcher()
+        result = patcher.patch([action], etree.fromstring(start))
+        self.assertEqual(etree.tounicode(result), end)
 
     def test_delete_node(self):
         self._test("<root><deleteme/></root>", DeleteNode("/root/deleteme"), 
"<root/>")
@@ -54,6 +52,13 @@
             "<root><anode/><moveme/></root>",
         )
 
+    def test_move_node_with_namespace(self):
+        self._test(
+            '<root 
xmlns:ns="http://example.com/ns";><ns:src><moveme/></ns:src><ns:dst/></root>',
+            MoveNode("/root/ns:src/moveme", "/root/ns:dst", 0),
+            '<root 
xmlns:ns="http://example.com/ns";><ns:src/><ns:dst><moveme/></ns:dst></root>',
+        )
+
     def test_update_text_in(self):
         self._test(
             "<root><anode/></root>",
@@ -253,3 +258,13 @@
             expected = f.read()
         # lxml.etree.parse() will strip ending whitespace
         self.assertEqual(result, expected.rstrip())
+
+    def test_parse_commas(self):
+        parser = DiffParser()
+
+        # There should be able to be a comma in the value
+        actions = list(parser.parse('[update-text-after, /root/anode[1], 
"foo,bar"]'))
+        self.assertEqual(
+            actions,
+            [UpdateTextAfter(node="/root/anode[1]", text="foo,bar", 
oldtext=None)],
+        )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/xmldiff/actions.py 
new/xmldiff-3.0/xmldiff/actions.py
--- old/xmldiff-2.7.0/xmldiff/actions.py        2024-05-13 14:15:38.000000000 
+0200
+++ new/xmldiff-3.0/xmldiff/actions.py  2026-06-11 17:00:00.000000000 +0200
@@ -6,8 +6,8 @@
 RenameNode = namedtuple("RenameNode", "node tag")
 MoveNode = namedtuple("MoveNode", "node target position")
 
-UpdateTextIn = namedtuple("UpdateTextIn", "node text")
-UpdateTextAfter = namedtuple("UpdateTextAfter", "node text")
+UpdateTextIn = namedtuple("UpdateTextIn", "node text oldtext", defaults=[None])
+UpdateTextAfter = namedtuple("UpdateTextAfter", "node text oldtext", 
defaults=[None])
 
 UpdateAttrib = namedtuple("UpdateAttrib", "node name value")
 DeleteAttrib = namedtuple("DeleteAttrib", "node name")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/xmldiff/diff.py 
new/xmldiff-3.0/xmldiff/diff.py
--- old/xmldiff-2.7.0/xmldiff/diff.py   2024-05-13 14:15:38.000000000 +0200
+++ new/xmldiff-3.0/xmldiff/diff.py     2026-06-11 17:00:00.000000000 +0200
@@ -65,9 +65,7 @@
             right = right.getroot()
 
         if not (etree.iselement(left) and etree.iselement(right)):
-            raise TypeError(
-                "The 'left' and 'right' parameters must be " "lxml Elements."
-            )
+            raise TypeError("The 'left' and 'right' parameters must be lxml 
Elements.")
 
         # Left gets modified as a part of the diff, deepcopy it first.
         self.left = deepcopy(left)
@@ -157,10 +155,16 @@
                     unmatched_lnodes.append((lnode, match_node, max_match))
                     # unmatched_lnodes.append(lnode)
 
+            # Sort by descending match quality so better matches get
+            # priority, and remove matched rnodes to prevent multiple
+            # left nodes from matching the same right node.
             lnodes = []
-            for lnode, rnode, max_match in unmatched_lnodes:
+            for lnode, rnode, max_match in sorted(
+                unmatched_lnodes, key=lambda x: -x[2]
+            ):
                 if max_match >= self.F and rnode in rnodes:
                     self.append_match(lnode, rnode, max_match)
+                    rnodes.remove(rnode)
                 else:
                     lnodes.append(lnode)
 
@@ -334,11 +338,11 @@
         left_xpath = utils.getpath(left)
 
         if left.text != right.text:
-            yield actions.UpdateTextIn(left_xpath, right.text)
+            yield actions.UpdateTextIn(left_xpath, right.text, left.text)
             left.text = right.text
 
         if left.tail != right.tail:
-            yield actions.UpdateTextAfter(left_xpath, right.tail)
+            yield actions.UpdateTextAfter(left_xpath, right.tail, left.tail)
             left.tail = right.tail
 
     def find_pos(self, node):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/xmldiff/formatting.py 
new/xmldiff-3.0/xmldiff/formatting.py
--- old/xmldiff-2.7.0/xmldiff/formatting.py     2024-05-13 14:15:38.000000000 
+0200
+++ new/xmldiff-3.0/xmldiff/formatting.py       2026-06-11 17:00:00.000000000 
+0200
@@ -766,10 +766,20 @@
         return ("update-attribute", action.node, action.name, 
json.dumps(action.value))
 
     def _handle_UpdateTextIn(self, action):
-        return "update-text", action.node, json.dumps(action.text)
+        return (
+            "update-text",
+            action.node,
+            json.dumps(action.text),
+            json.dumps(action.oldtext),
+        )
 
     def _handle_UpdateTextAfter(self, action):
-        return "update-text-after", action.node, json.dumps(action.text)
+        return (
+            "update-text-after",
+            action.node,
+            json.dumps(action.text),
+            json.dumps(action.oldtext),
+        )
 
     def _handle_RenameNode(self, action):
         return "rename", action.node, action.tag
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/xmldiff/main.py 
new/xmldiff-3.0/xmldiff/main.py
--- old/xmldiff-2.7.0/xmldiff/main.py   2024-05-13 14:15:38.000000000 +0200
+++ new/xmldiff-3.0/xmldiff/main.py     2026-06-11 17:00:00.000000000 +0200
@@ -1,4 +1,5 @@
 """All major API points and command-line tools"""
+
 from importlib import metadata
 
 from argparse import ArgumentParser, ArgumentTypeError
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/xmldiff/patch.py 
new/xmldiff-3.0/xmldiff/patch.py
--- old/xmldiff-2.7.0/xmldiff/patch.py  2024-05-13 14:15:38.000000000 +0200
+++ new/xmldiff-3.0/xmldiff/patch.py    2026-06-11 17:00:00.000000000 +0200
@@ -1,10 +1,14 @@
+import re
+
 from copy import deepcopy
-from csv import reader
 from json import loads
 from lxml import etree
 from xmldiff import actions
 
 
+DIFF_SPLIT = re.compile('(?:"[^"]*"|[^, ])+|(?<![^,])(?![^,])')
+
+
 class Patcher:
     @property
     def nsmap(self):
@@ -47,7 +51,7 @@
     def _handle_MoveNode(self, action, tree):
         node = tree.xpath(action.node, namespaces=self.nsmap)[0]
         node.getparent().remove(node)
-        target = tree.xpath(action.target)[0]
+        target = tree.xpath(action.target, namespaces=self.nsmap)[0]
         target.insert(action.position, node)
 
     def _handle_UpdateTextIn(self, action, tree):
@@ -119,7 +123,7 @@
         line = line[1:-1]
         # Split the line on commas (ignoring commas in quoted strings) and
         # strip extraneous spaces. The first is the action, the rest params.
-        parts = [x.strip() for x in next(reader([line]))]
+        parts = DIFF_SPLIT.findall(line)
         action = parts[0]
         params = parts[1:]
         # Get the method, and return the result of calling it
@@ -138,10 +142,10 @@
     def _handle_move(self, node, target, position):
         return actions.MoveNode(node, target, int(position))
 
-    def _handle_update_text(self, node, text):
+    def _handle_update_text(self, node, text, oldtext=None):
         return actions.UpdateTextIn(node, loads(text))
 
-    def _handle_update_text_after(self, node, text):
+    def _handle_update_text_after(self, node, text, oldtext=None):
         return actions.UpdateTextAfter(node, loads(text))
 
     def _handle_update_attribute(self, node, name, value):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/xmldiff/utils.py 
new/xmldiff-3.0/xmldiff/utils.py
--- old/xmldiff-2.7.0/xmldiff/utils.py  2024-05-13 14:15:38.000000000 +0200
+++ new/xmldiff-3.0/xmldiff/utils.py    2026-06-11 17:00:00.000000000 +0200
@@ -1,5 +1,6 @@
 import re
 
+from collections import deque
 from operator import eq
 
 # This namespace is reserved for lxml internal use, which only
@@ -23,10 +24,10 @@
 
 def breadth_first_traverse(node):
     # First yield the root node
-    queue = [node]
+    queue = deque([node])
 
     while queue:
-        item = queue.pop(0)
+        item = queue.popleft()
         yield item
         queue.extend(item.getchildren())
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/xmldiff.egg-info/PKG-INFO 
new/xmldiff-3.0/xmldiff.egg-info/PKG-INFO
--- old/xmldiff-2.7.0/xmldiff.egg-info/PKG-INFO 2024-05-13 14:15:38.000000000 
+0200
+++ new/xmldiff-3.0/xmldiff.egg-info/PKG-INFO   2026-06-11 17:00:01.000000000 
+0200
@@ -1,36 +1,35 @@
 Metadata-Version: 2.1
 Name: xmldiff
-Version: 2.7.0
+Version: 3.0
 Summary: Creates diffs of XML files
-Home-page: https://github.com/Shoobx/xmldiff
-Author: Lennart Regebro
-Author-email: [email protected]
+Author-email: Lennart Regebro <[email protected]>
 License: MIT
+Project-URL: Homepage, https://github.com/Shoobx/xmldiff
 Project-URL: Source Code, https://github.com/Shoobx/xmldiff
-Keywords: xml,html,diff
+Keywords: diff,html,xml
 Classifier: Development Status :: 4 - Beta
 Classifier: Intended Audience :: Developers
 Classifier: Intended Audience :: End Users/Desktop
-Classifier: Topic :: Text Processing :: Markup :: XML
-Classifier: License :: OSI Approved :: MIT License
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3 :: Only
+Classifier: Programming Language :: Python :: Implementation :: PyPy
 Classifier: Programming Language :: Python :: 3.10
 Classifier: Programming Language :: Python :: 3.11
 Classifier: Programming Language :: Python :: 3.12
-Classifier: Programming Language :: Python :: 3 :: Only
-Classifier: Programming Language :: Python :: Implementation :: PyPy
+Classifier: Programming Language :: Python :: 3.13
+Classifier: Programming Language :: Python :: 3.14
+Classifier: Programming Language :: Python :: 3.15
+Classifier: Topic :: Text Processing :: Markup :: XML
+Classifier: License :: OSI Approved :: MIT License
 Requires-Python: >=3.8
+Description-Content-Type: text/x-rst
 License-File: LICENSE.txt
-Requires-Dist: setuptools
 Requires-Dist: lxml>=3.1.0
 Provides-Extra: devenv
-Requires-Dist: black; extra == "devenv"
-Requires-Dist: coverage; extra == "devenv"
-Requires-Dist: flake8; extra == "devenv"
+Requires-Dist: ruff; extra == "devenv"
+Requires-Dist: pyroma>=5.0b1; extra == "devenv"
 Requires-Dist: zest.releaser[recommended]; extra == "devenv"
 
 xmldiff
@@ -127,158 +126,10 @@
 
  * Thomas Pfitzinger, [email protected]
 
+ * Alexandre Detiste
+
+ *  Denis Barucic, [email protected]
+
 The diff algorithm is based on
 "`Change Detection in Hierarchically Structured Information 
<http://infolab.stanford.edu/c3/papers/html/tdiff3-8/tdiff3-8.html>`_",
 and the text diff is using Google's ``diff_match_patch`` algorithm.
-
-Changes
-=======
-
-2.7.0 (2024-05-13)
-------------------
-
-- Changed the comparison to make accurate and standard more accurate,
-  although fast gets less accurate as a result.
-
-- Changed usage of deprecated `pkg_resources` package to `importlib.metadata`.
-
-- A `use_replace` flag was added to the `XMLFormatter` by Thomas Pfitzinger.
-  It changes text replacement from delete and insert tags to a replace tag.
-  It's not currently accessaible thtough the CLI, the question is it is better
-  to add a new formatter name, or an option to pass in formatter flags.
-
-  - Added option to XMLFormatter to use replace tags
-  - in _make_diff_tags after diffing, neighboring delete/insert diffs are 
joined to a replace tag
-  - the deleted text is added as an attribute ("old-text")
-  - the inserted text is the element's text
-
-2.6.3 (2023-05-21)
-------------------
-
-- And there was a namespace bug in the patch as well. #118
-
-
-2.6.2 (2023-05-21)
-------------------
-
-- Solved an error in the xmlformatter when using default namespaces. #89
-
-
-2.6.1 (2023-04-05)
-------------------
-
-- #108: Fixed an error that happens if using namespaces like ns0 or ns1.
-
-
-2.6 (2023-04-03)
-----------------
-
-- Added `InsertNamespace` and `DeleteNamespace` actions for better handling
-  of changing namespaces. Should improve any "Unknown namespace prefix"
-  errors. Changing the URI of a a namespace prefix is not supported, and will
-  raise an error.
-
-2.6b1 (2023-01-12)
-------------------
-
-- Used geometric mean for the node_ratio, for better handling of simple nodes.
-
-- Added an experimental --best-match method that is slower, but generate
-  smaller diffs when you have many nodes that are similar.
-
-- The -F argument now also affects the --fast-match stage.
-
-
-2.5 (2023-01-11)
-----------------
-
-- Make it possible to adjust the attributes considered when comparing nodes.
-
-- Python versions 3.7 to 3.11 are now supported.
-
-- Improved node matching method, that puts more emphasis similarities than
-  differences when weighing attributes vs children.
-
-- Added a parameter to return error code 1 when there are differences between 
the files
-
-- Added a parameter for ignoring attributes in comparison.
-
-- Solved a bug in xmlpatch in certain namespace situations.
-
-- Added a --diff-encoding parameter to xmlpatch, to support diff-files that are
-  not in your system default encoding.
-
-
-2.4 (2019-10-09)
-----------------
-
-- Added an option to pass pairs of (element, attr) as unique
-  attributes for tree matching.  Exposed this option on the command
-  line, too.
-
-
-2.3 (2019-02-27)
-----------------
-
-- Added a simple ``xmlpatch`` command and API.
-
-- Multiple updates to documentation and code style
-
-
-2.2 (2018-10-12)
-----------------
-
-- A workaround for dealing with top level comments and the xml formatter
-
-
-2.1 (2018-10-03)
-----------------
-
-- Changed the substitution unicode character area to use the Private Use Area
-  in BMP(0), to support narrow Python builds
-
-- Added --unique-attributes argument.
-
-
-2.1b1 (2018-10-01)
-------------------
-
-- Added options for faster node comparisons. The "middle" option is now
-  default, it had very few changes in matches, but is much faster.
-
-- Implemented a Fast Match algorithm for even faster diffing.
-
-- Speed improvements through caching
-
-- Fixed a bug where MoveNode actions sometimes was in the wrong order
-
-- Added an InsertComment action, as comments require different handling,
-  so it's easier to deal with them this way. You can still use DeleteNode and
-  UpdateTextIn for them with no special handling.
-
-- When renaming tags the XMLFormatter will mark them with "diff:rename"
-  instead of making a new tag and deleting the old.
-
-- Tags will now be moved first, and updated and renamed later, as the new
-  tag name or attributes might not be valid in the old location.
-
-
-2.0 (2018-09-25)
-----------------
-
-- A complete, bottom-up, pure-python rewrite
-
-- New easy API
-
-- 100% test coverage
-
-- New output formats:
-
-  - A new default output format with new actions
-
-  - A format intended to be parseable by anyone parsing the old format.
-
-  - XML with changes marked though tags and attributes
-
-- xmldiff 2.0 is significantly slower than xmldiff 0.6 or 1.0,
-  the emphasis so far is on correctness, not speed.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/xmldiff.egg-info/SOURCES.txt 
new/xmldiff-3.0/xmldiff.egg-info/SOURCES.txt
--- old/xmldiff-2.7.0/xmldiff.egg-info/SOURCES.txt      2024-05-13 
14:15:38.000000000 +0200
+++ new/xmldiff-3.0/xmldiff.egg-info/SOURCES.txt        2026-06-11 
17:00:01.000000000 +0200
@@ -1,22 +1,13 @@
 .coveragerc
 .coveralls.yml
+.pre-commit-config.yaml
 .travis.yml
 CHANGES.rst
-CHANGES.txt
 LICENSE.txt
 MANIFEST.in
 Makefile
 README.rst
-setup.cfg
-setup.py
-./xmldiff/__init__.py
-./xmldiff/actions.py
-./xmldiff/diff.py
-./xmldiff/diff_match_patch.py
-./xmldiff/formatting.py
-./xmldiff/main.py
-./xmldiff/patch.py
-./xmldiff/utils.py
+pyproject.toml
 docs/Makefile
 docs/make.bat
 docs/requirements.txt
@@ -59,10 +50,18 @@
 tests/test_data/sbt_template.expected.xml
 tests/test_data/sbt_template.left.xml
 tests/test_data/sbt_template.right.xml
+xmldiff/__init__.py
+xmldiff/actions.py
+xmldiff/diff.py
+xmldiff/diff_match_patch.py
+xmldiff/formatting.py
+xmldiff/main.py
+xmldiff/patch.py
+xmldiff/utils.py
 xmldiff.egg-info/PKG-INFO
 xmldiff.egg-info/SOURCES.txt
 xmldiff.egg-info/dependency_links.txt
 xmldiff.egg-info/entry_points.txt
+xmldiff.egg-info/not-zip-safe
 xmldiff.egg-info/requires.txt
-xmldiff.egg-info/top_level.txt
-xmldiff.egg-info/zip-safe
\ No newline at end of file
+xmldiff.egg-info/top_level.txt
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/xmldiff.egg-info/not-zip-safe 
new/xmldiff-3.0/xmldiff.egg-info/not-zip-safe
--- old/xmldiff-2.7.0/xmldiff.egg-info/not-zip-safe     1970-01-01 
01:00:00.000000000 +0100
+++ new/xmldiff-3.0/xmldiff.egg-info/not-zip-safe       2026-06-11 
17:00:01.000000000 +0200
@@ -0,0 +1 @@
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/xmldiff.egg-info/requires.txt 
new/xmldiff-3.0/xmldiff.egg-info/requires.txt
--- old/xmldiff-2.7.0/xmldiff.egg-info/requires.txt     2024-05-13 
14:15:38.000000000 +0200
+++ new/xmldiff-3.0/xmldiff.egg-info/requires.txt       2026-06-11 
17:00:01.000000000 +0200
@@ -1,8 +1,6 @@
-setuptools
 lxml>=3.1.0
 
 [devenv]
-black
-coverage
-flake8
+ruff
+pyroma>=5.0b1
 zest.releaser[recommended]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xmldiff-2.7.0/xmldiff.egg-info/zip-safe 
new/xmldiff-3.0/xmldiff.egg-info/zip-safe
--- old/xmldiff-2.7.0/xmldiff.egg-info/zip-safe 2024-05-13 14:15:38.000000000 
+0200
+++ new/xmldiff-3.0/xmldiff.egg-info/zip-safe   1970-01-01 01:00:00.000000000 
+0100
@@ -1 +0,0 @@
-

Reply via email to