From 81ef8b0b74949e37bdafec34e4403f351a8f03ed Mon Sep 17 00:00:00 2001 From: miute Date: Thu, 25 Jun 2026 23:00:54 +0900 Subject: [PATCH 1/3] Bump pugixml from 1.15 to 1.16 - Add `XMLNode.ensure_attribute(name: str)` - Add `XMLNode.ensure_child(name: str)` - Enable PUGIXML_CHARCONV_FLOAT option. --- CHANGELOG.md | 4 ++++ CMakeLists.txt | 1 + src/main.cpp | 38 ++++++++++++++++++++++++++++++++++++++ src/third_party/pugixml | 2 +- tests/test_attribute.py | 29 +++++++++++++++++++++++++++++ tests/test_node.py | 23 +++++++++++++++++++++++ 6 files changed, 96 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2d9939..505e61e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ ### Changed +- Bump pugixml from 1.15 to 1.16 ([#200]) + - Add `pugixml.pugi.XMLNode.ensure_attribute(name: str)` + - Add `pugixml.pugi.XMLNode.ensure_child(name: str)` - Bump pybind11 from 2.13.6 to 3.0.4 ([#141], [#159], [#198]) ### Added @@ -136,3 +139,4 @@ Initial release. [#154]: https://github.com/miute/pugixml-python/pull/154 [#159]: https://github.com/miute/pugixml-python/pull/159 [#198]: https://github.com/miute/pugixml-python/pull/198 +[#200]: https://github.com/miute/pugixml-python/pull/200 diff --git a/CMakeLists.txt b/CMakeLists.txt index d84789e..932ea97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,7 @@ cmake_policy(SET CMP0074 NEW) project(pugi LANGUAGES CXX) +set(PUGIXML_CHARCONV_FLOAT ON) set(PYBIND11_FINDPYTHON ON) set(DESTDIR pugixml CACHE STRING "The directory where the binaries will be written. (e.g., path/to/pugixml-python/src/pugixml)") message(STATUS "DESTDIR: ${DESTDIR}") diff --git a/src/main.cpp b/src/main.cpp index 01fc771..62ab44f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1048,6 +1048,39 @@ PYBIND11_MODULE(MODULE_NAME, m) { bool: :obj:`True` if node is empty, :obj:`False` otherwise. )doc"); + node.def("ensure_attribute", py::overload_cast(&xml_node::ensure_attribute), + py::arg("name").none(false), + R"doc( + Return the attribute with the specified name. + + If the attribute with the specified name does not exist, it will be created. + + Args: + name (str): The name of the attribute. + + Returns: + XMLAttribute: The attribute with the specified name, or empty attribute if error occurs. + + See Also: + :meth:`.attribute` + )doc"); + + node.def("ensure_child", py::overload_cast(&xml_node::ensure_child), py::arg("name").none(false), + R"doc( + Return the child node with the specified name. + + If the child node with the specified name does not exist, it will be created as an element. + + Args: + name (str): The name of the child node. + + Returns: + XMLNode: The child node with the specified name, or empty node if error occurs. + + See Also: + :meth:`.child` + )doc"); + node.def("type", &xml_node::type, R"doc( Return the node type. @@ -1176,6 +1209,9 @@ PYBIND11_MODULE(MODULE_NAME, m) { Returns: XMLNode: The first node found, or empty node if not exists. + + See Also: + :meth:`.ensure_child` )doc"); node.def("attribute", py::overload_cast(&xml_node::attribute, py::const_), @@ -1190,6 +1226,8 @@ PYBIND11_MODULE(MODULE_NAME, m) { "attribute after the one found, or with an empty attribute if not found.\n\n" "Returns:\n" " XMLAttribute: The first attribute found, or empty attribute if not exists.\n\n" + "See Also:\n" + " :meth:`.ensure_attribute`\n\n" "Examples:\n" " >>> from pugixml import pugi\n" " >>> doc = pugi.XMLDocument()\n" diff --git a/src/third_party/pugixml b/src/third_party/pugixml index ee86beb..c8033ce 160000 --- a/src/third_party/pugixml +++ b/src/third_party/pugixml @@ -1 +1 @@ -Subproject commit ee86beb30e4973f5feffe3ce63bfa4fbadf72f38 +Subproject commit c8033ce9d039e7f9d134877c363397b3cfe20816 diff --git a/tests/test_attribute.py b/tests/test_attribute.py index 02453fa..762a749 100644 --- a/tests/test_attribute.py +++ b/tests/test_attribute.py @@ -240,6 +240,35 @@ def test_empty() -> None: assert not node.attribute("attr2").empty() +def test_ensure_attribute() -> None: + doc = pugi.XMLDocument() + doc.load_string("") + node = doc.child("node") + + a1 = node.ensure_attribute("a1") + assert isinstance(a1, pugi.XMLAttribute) + assert not a1.empty() + assert a1 == node.attribute("a1") + assert a1.value() == "v1" + + a2 = node.ensure_attribute("a2") + assert isinstance(a2, pugi.XMLAttribute) + assert not a2.empty() + assert a2 != a1 + assert a2.set_value("v2") + + a3 = node.child("child").ensure_attribute("a3") + assert isinstance(a3, pugi.XMLAttribute) + assert not a3.empty() + assert a3 != a2 + assert a3 != a1 + assert a3.set_value("v3") + + writer = pugi.StringWriter() + doc.print(writer, flags=pugi.FORMAT_RAW) + assert writer.getvalue() == '' + + def test_hash_value() -> None: doc = pugi.XMLDocument() doc.load_string("") diff --git a/tests/test_node.py b/tests/test_node.py index de008f5..d25cfb3 100644 --- a/tests/test_node.py +++ b/tests/test_node.py @@ -539,6 +539,29 @@ def test_empty() -> None: assert not doc.child("node").empty() +def test_ensure_child() -> None: + doc = pugi.XMLDocument() + doc.load_string("foo") + node = doc.child("node") + + child = node.ensure_child("child") + assert isinstance(child, pugi.XMLNode) + assert not child.empty() + assert child == node.child("child") + + n1 = node.ensure_child("n1") + assert isinstance(n1, pugi.XMLNode) + assert not n1.empty() + + n2 = doc.ensure_child("n2") + assert isinstance(n2, pugi.XMLNode) + assert not n2.empty() + + writer = pugi.StringWriter() + doc.print(writer, flags=pugi.FORMAT_RAW) + assert writer.getvalue() == "foo" + + def test_file_writer() -> None: doc = pugi.XMLDocument() doc.load_string("\U0001f308") From 712d39e9a9c7e9066bc5842ed392e6c8fadc3ad9 Mon Sep 17 00:00:00 2001 From: miute Date: Thu, 25 Jun 2026 23:52:51 +0900 Subject: [PATCH 2/3] Update the macOS deployment target - Move the MACOSX_DEPLOYMENT_TARGET environment variable from the CI workflows to CMakeLists.txt. - Change the minimum deployment target from 12.0 to 13.3. --- .github/workflows/build.yml | 3 --- .github/workflows/tests.yml | 3 --- CMakeLists.txt | 4 ++++ 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e48034e..14b4627 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,9 +5,6 @@ on: tags: [v*] workflow_dispatch: -env: - MACOSX_DEPLOYMENT_TARGET: '12.0' - jobs: build_wheels: runs-on: ${{matrix.os}} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 890008a..4b3bc6c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,9 +7,6 @@ on: pull_request: workflow_dispatch: -env: - MACOSX_DEPLOYMENT_TARGET: '12.0' - jobs: test: runs-on: ${{matrix.os}} diff --git a/CMakeLists.txt b/CMakeLists.txt index 932ea97..43476dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,10 @@ cmake_policy(SET CMP0074 NEW) project(pugi LANGUAGES CXX) +if(APPLE) + set(CMAKE_OSX_DEPLOYMENT_TARGET "13.3" CACHE STRING "Minimum macOS version" FORCE) +endif() + set(PUGIXML_CHARCONV_FLOAT ON) set(PYBIND11_FINDPYTHON ON) set(DESTDIR pugixml CACHE STRING "The directory where the binaries will be written. (e.g., path/to/pugixml-python/src/pugixml)") From 8bc40c74545e623aa84dc095ce6c9640e4b24251 Mon Sep 17 00:00:00 2001 From: miute Date: Fri, 26 Jun 2026 21:30:15 +0900 Subject: [PATCH 3/3] Disable PUGIXML_CHARCONV_FLOAT for macOS builds - Disable PUGIXML_CHARCONV_FLOAT option for macOS builds because Xcode 26 or later is required. - Bump MACOSX_DEPLOYMENT_TARGET from 13.3 to 14.5. --- .github/workflows/tests.yml | 2 +- CMakeLists.txt | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4b3bc6c..4dbe60e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest, macos-latest] + os: [ubuntu-latest, windows-latest, macos-14] python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] steps: diff --git a/CMakeLists.txt b/CMakeLists.txt index 43476dd..f546c85 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,10 +5,12 @@ cmake_policy(SET CMP0074 NEW) project(pugi LANGUAGES CXX) if(APPLE) - set(CMAKE_OSX_DEPLOYMENT_TARGET "13.3" CACHE STRING "Minimum macOS version" FORCE) + set(CMAKE_OSX_DEPLOYMENT_TARGET "14.5" CACHE STRING "Minimum macOS version" FORCE) + set(PUGIXML_CHARCONV_FLOAT OFF) # PUGIXML_CHARCONV_FLOAT requires Xcode 26 or later +else() + set(PUGIXML_CHARCONV_FLOAT ON) endif() -set(PUGIXML_CHARCONV_FLOAT ON) set(PYBIND11_FINDPYTHON ON) set(DESTDIR pugixml CACHE STRING "The directory where the binaries will be written. (e.g., path/to/pugixml-python/src/pugixml)") message(STATUS "DESTDIR: ${DESTDIR}")