Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-nh3 for openSUSE:Factory 
checked in at 2026-04-08 17:13:40
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-nh3 (Old)
 and      /work/SRC/openSUSE:Factory/.python-nh3.new.21863 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-nh3"

Wed Apr  8 17:13:40 2026 rev:7 rq:1344941 version:0.3.4

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-nh3/python-nh3.changes    2025-10-07 
18:25:50.671059009 +0200
+++ /work/SRC/openSUSE:Factory/.python-nh3.new.21863/python-nh3.changes 
2026-04-08 17:13:53.903401616 +0200
@@ -1,0 +2,24 @@
+Sun Apr  5 13:57:40 UTC 2026 - ecsos <[email protected]>
+
+- Update to 0.3.4
+  - Bump pyo3 from 0.28.1 to 0.28.2 in #114
+  - Validate rel attribute conflict with link_rel in #117
+  - Expose default clean_content_tags as module constant in #118
+  - Accept frozenset and Mapping in type stubs in #119
+- Changes from 0.3.3
+  - Bump pyo3 from 0.27.1 to 0.27.2 in #106
+    - Bump actions/checkout from 5 to 6 in the github-actions group in #105
+  - Bump the github-actions group with 2 updates in #108
+  - Add riscv64 build, and make target list more explicit #110
+  - Bump pyo3 from 0.27.2 to 0.28.0 in #111
+- Changes from 0.3.2
+  - Upgrade GitHub Actions in #94
+  - GitHub Actions: Stop reinstalling Rust on windows-11-arm in #95
+  - Add README reference in pyproject.toml in #97
+  - Keep GitHub Actions up to date with GitHub's Dependabot in #96
+  - Build wheels for Python 3.14 free-threaded in #100
+- Changes from 0.3.1
+  - Bump ammonia from 4.1.1 to 4.1.2 in #93
+  - Bump pyo3 from 0.25.1 to 0.26.0 in #92
+
+-------------------------------------------------------------------

Old:
----
  nh3-0.3.0.tar.gz

New:
----
  nh3-0.3.4.tar.gz

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

Other differences:
------------------
++++++ python-nh3.spec ++++++
--- /var/tmp/diff_new_pack.z6DcbE/_old  2026-04-08 17:13:54.847440429 +0200
+++ /var/tmp/diff_new_pack.z6DcbE/_new  2026-04-08 17:13:54.851440594 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-nh3
 #
-# Copyright (c) 2025 SUSE LLC and contributors
+# 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,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-nh3
-Version:        0.3.0
+Version:        0.3.4
 Release:        0
 Summary:        Ammonia HTML sanitizer Python binding
 License:        MIT
@@ -28,7 +28,7 @@
 BuildRequires:  %{python_module maturin >= 1.0}
 BuildRequires:  %{python_module pip}
 BuildRequires:  %{python_module pytest}
-BuildRequires:  cargo
+BuildRequires:  cargo-packaging
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
 BuildRequires:  zstd

++++++ _service ++++++
--- /var/tmp/diff_new_pack.z6DcbE/_old  2026-04-08 17:13:54.887442074 +0200
+++ /var/tmp/diff_new_pack.z6DcbE/_new  2026-04-08 17:13:54.895442403 +0200
@@ -1,10 +1,8 @@
 <services>
   <service name="download_files" mode="manual"/>
   <service name="cargo_vendor" mode="manual">
-    <param name="srcdir">nh3-0.3.0</param>
+    <param name="src">nh3-0.3.4.tar.gz</param>
     <param name="compression">zst</param>
   </service>
-  <service name="cargo_audit" mode="manual">
-  </service>
 </services>
 

++++++ nh3-0.3.0.tar.gz -> nh3-0.3.4.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nh3-0.3.0/.github/dependabot.yml 
new/nh3-0.3.4/.github/dependabot.yml
--- old/nh3-0.3.0/.github/dependabot.yml        2025-07-17 16:38:00.000000000 
+0200
+++ new/nh3-0.3.4/.github/dependabot.yml        2006-07-24 03:21:28.000000000 
+0200
@@ -9,3 +9,11 @@
     directory: "/" # Location of package manifests
     schedule:
       interval: "weekly"
+  - package-ecosystem: "github-actions"
+    directory: "/"
+    groups:
+      github-actions:
+        patterns:
+          - "*" # Group all Actions updates into a single larger pull request
+    schedule:
+      interval: "weekly"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nh3-0.3.0/.github/workflows/CI.yml 
new/nh3-0.3.4/.github/workflows/CI.yml
--- old/nh3-0.3.0/.github/workflows/CI.yml      2025-07-17 16:38:00.000000000 
+0200
+++ new/nh3-0.3.4/.github/workflows/CI.yml      2006-07-24 03:21:28.000000000 
+0200
@@ -11,8 +11,8 @@
   macos:
     runs-on: macos-latest
     steps:
-      - uses: actions/checkout@v3
-      - uses: actions/setup-python@v4
+      - uses: actions/checkout@v6
+      - uses: actions/setup-python@v6
         with:
           python-version: 3.12
           architecture: x64
@@ -27,7 +27,7 @@
         uses: pyo3/maturin-action@v1
         with:
           target: universal2-apple-darwin
-          args: --release --out dist -i python3.13t
+          args: --release --out dist -i python3.14t
           sccache: true
       - name: Install built wheel
         run: |
@@ -35,7 +35,7 @@
           pip install pytest
           cd tests && pytest
       - name: Upload wheels
-        uses: actions/upload-artifact@v4
+        uses: actions/upload-artifact@v7
         with:
           name: wheels-macos
           path: dist
@@ -46,8 +46,8 @@
       matrix:
         target: [x64, x86]
     steps:
-      - uses: actions/checkout@v3
-      - uses: actions/setup-python@v4
+      - uses: actions/checkout@v6
+      - uses: actions/setup-python@v6
         with:
           python-version: 3.12
           architecture: ${{ matrix.target }}
@@ -61,14 +61,14 @@
         uses: pyo3/maturin-action@v1
         with:
           target: ${{ matrix.target }}
-          args: --release --out dist -i python3.13t
+          args: --release --out dist -i python3.14t
       - name: Install built wheel
         run: |
           pip install nh3 --no-index --find-links dist --force-reinstall
           pip install pytest
           cd tests && pytest
       - name: Upload wheels
-        uses: actions/upload-artifact@v4
+        uses: actions/upload-artifact@v7
         with:
           name: wheels-windows-${{ matrix.target }}
           path: dist
@@ -79,18 +79,11 @@
       matrix:
         target: [aarch64-pc-windows-msvc]
     steps:
-      - uses: actions/checkout@v3
-      - uses: actions/setup-python@v4
+      - uses: actions/checkout@v6
+      - uses: actions/setup-python@v6
         with:
           python-version: 3.12
           architecture: arm64
-      # rust toolchain is not currently installed on windopws arm64 images 
https://github.com/actions/partner-runner-images/issues/77
-      - name: Setup rust
-        id: setup-rust
-        run: |
-          Invoke-WebRequest 
https://static.rust-lang.org/rustup/dist/aarch64-pc-windows-msvc/rustup-init.exe
 -OutFile .\rustup-init.exe
-          .\rustup-init.exe -y
-          Add-Content $env:GITHUB_PATH "$env:USERPROFILE\.cargo\bin"
       - name: Build wheels
         uses: pyo3/maturin-action@v1
         with:
@@ -100,14 +93,14 @@
         uses: pyo3/maturin-action@v1
         with:
           target: ${{ matrix.target }}
-          args: --release --out dist -i python3.13t
+          args: --release --out dist -i python3.14t
       - name: Install built wheel
         run: |
           pip install nh3 --no-index --find-links dist --force-reinstall
           pip install pytest
           cd tests && pytest
       - name: Upload wheels
-        uses: actions/upload-artifact@v4
+        uses: actions/upload-artifact@v7
         with:
           name: wheels-windows-arm-${{ matrix.target }}
           path: dist
@@ -118,8 +111,8 @@
       matrix:
         target: [x86_64, i686]
     steps:
-      - uses: actions/checkout@v3
-      - uses: actions/setup-python@v4
+      - uses: actions/checkout@v6
+      - uses: actions/setup-python@v6
         with:
           python-version: 3.12
           architecture: x64
@@ -138,7 +131,7 @@
           rust-toolchain: nightly
           target: ${{ matrix.target }}
           manylinux: auto
-          args: --release --out dist -i python3.13t
+          args: --release --out dist -i python3.14t
           sccache: true
           before-script-linux: yum install -y libatomic
       - name: Install built wheel
@@ -148,7 +141,7 @@
           pip install pytest
           cd tests && pytest
       - name: Upload wheels
-        uses: actions/upload-artifact@v4
+        uses: actions/upload-artifact@v7
         with:
           name: wheels-linux-${{ matrix.target }}
           path: dist
@@ -157,17 +150,29 @@
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        target: [aarch64, armv7, s390x, ppc64le, ppc64]
+        platform:
+          - target: aarch64-unknown-linux-gnu
+            arch: aarch64
+          - target: armv7-unknown-linux-gnueabihf
+            arch: armv7
+          - target: s390x-unknown-linux-gnu
+            arch: s390x
+          - target: powerpc64le-unknown-linux-gnu
+            arch: ppc64le
+          - target: powerpc64-unknown-linux-gnu
+            arch: ppc64
+          - target: riscv64gc-unknown-linux-gnu
+            arch: riscv64
     steps:
-      - uses: actions/checkout@v3
-      - uses: actions/setup-python@v4
+      - uses: actions/checkout@v6
+      - uses: actions/setup-python@v6
         with:
           python-version: 3.12
       - name: Build wheels
         uses: pyo3/maturin-action@v1
         with:
           rust-toolchain: nightly
-          target: ${{ matrix.target }}
+          target: ${{ matrix.platform.target }}
           manylinux: auto
           args: --release --out dist
           sccache: true
@@ -175,15 +180,15 @@
         uses: pyo3/maturin-action@v1
         with:
           rust-toolchain: nightly
-          target: ${{ matrix.target }}
+          target: ${{ matrix.platform.target }}
           manylinux: auto
           args: --release --out dist -i python3.13
           sccache: true
-      - uses: uraimo/[email protected]
-        if: matrix.target != 'ppc64'
+      - uses: uraimo/[email protected]
+        if: matrix.platform.arch != 'ppc64'
         name: Install built wheel
         with:
-          arch: ${{ matrix.target }}
+          arch: ${{ matrix.platform.arch }}
           distro: ubuntu22.04
           githubToken: ${{ github.token }}
           install: |
@@ -194,9 +199,9 @@
             pip3 install nh3 --no-index --find-links dist/ --force-reinstall
             cd tests && pytest
       - name: Upload wheels
-        uses: actions/upload-artifact@v4
+        uses: actions/upload-artifact@v7
         with:
-          name: wheels-linux-${{ matrix.target }}
+          name: wheels-linux-${{ matrix.platform.arch }}
           path: dist
 
   musllinux:
@@ -207,8 +212,8 @@
           - x86_64-unknown-linux-musl
           - i686-unknown-linux-musl
     steps:
-      - uses: actions/checkout@v3
-      - uses: actions/setup-python@v4
+      - uses: actions/checkout@v6
+      - uses: actions/setup-python@v6
         with:
           python-version: 3.12
           architecture: x64
@@ -224,23 +229,21 @@
         with:
           target: ${{ matrix.target }}
           manylinux: musllinux_1_2
-          args: --release --out dist -i python3.13t
+          args: --release --out dist -i python3.14t
           sccache: true
       - name: Install built wheel
         if: matrix.target == 'x86_64-unknown-linux-musl'
-        uses: addnab/docker-run-action@v3
-        with:
-          image: alpine:latest
-          options: -v ${{ github.workspace }}:/io -w /io
-          run: |
+        run: |
+          docker run --rm -v ${{ github.workspace }}:/io -w /io alpine:latest 
sh -c '
             apk add py3-virtualenv
             python3 -m virtualenv .venv
             source .venv/bin/activate
             pip install -U pip pytest
             pip install nh3 --no-index --find-links /io/dist/ --force-reinstall
             cd tests && python3 -m pytest
+          '
       - name: Upload wheels
-        uses: actions/upload-artifact@v4
+        uses: actions/upload-artifact@v7
         with:
           name: wheels-${{ matrix.target }}
           path: dist
@@ -255,8 +258,8 @@
           - target: armv7-unknown-linux-musleabihf
             arch: armv7
     steps:
-      - uses: actions/checkout@v3
-      - uses: actions/setup-python@v4
+      - uses: actions/checkout@v6
+      - uses: actions/setup-python@v6
         with:
           python-version: 3.12
       - name: Build wheels
@@ -271,9 +274,9 @@
         with:
           target: ${{ matrix.platform.target }}
           manylinux: musllinux_1_2
-          args: --release --out dist -i python3.13t
+          args: --release --out dist -i python3.14t
           sccache: true
-      - uses: uraimo/[email protected]
+      - uses: uraimo/[email protected]
         name: Install built wheel
         with:
           arch: ${{ matrix.platform.arch }}
@@ -288,16 +291,16 @@
             pip install nh3 --no-index --find-links dist/ --force-reinstall
             cd tests && python3 -m pytest
       - name: Upload wheels
-        uses: actions/upload-artifact@v4
+        uses: actions/upload-artifact@v7
         with:
-          name: wheels-${{ matrix.platform.target }}
+          name: wheels-${{ matrix.platform.arch }}
           path: dist
 
   sdist:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v3
-      - uses: actions/setup-python@v4
+      - uses: actions/checkout@v6
+      - uses: actions/setup-python@v6
         with:
           python-version: 3.12
           architecture: x64
@@ -307,7 +310,7 @@
           command: sdist
           args: --out dist
       - name: Upload sdist
-        uses: actions/upload-artifact@v4
+        uses: actions/upload-artifact@v7
         with:
           name: wheels-sdist
           path: dist
@@ -319,11 +322,11 @@
     needs:
       [macos, windows, windows-arm, linux, linux-cross, musllinux, 
musllinux-cross, sdist]
     steps:
-      - uses: actions/download-artifact@v4
+      - uses: actions/download-artifact@v8
         with:
           pattern: wheels-*
           merge-multiple: true
-      - uses: actions/setup-python@v4
+      - uses: actions/setup-python@v6
         with:
           python-version: 3.12
       - name: Publish to PyPI
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nh3-0.3.0/.readthedocs.yml 
new/nh3-0.3.4/.readthedocs.yml
--- old/nh3-0.3.0/.readthedocs.yml      2025-07-17 16:38:00.000000000 +0200
+++ new/nh3-0.3.4/.readthedocs.yml      2006-07-24 03:21:28.000000000 +0200
@@ -9,8 +9,8 @@
 build:
   os: "ubuntu-22.04"
   tools:
-    python: "3.12"
-    rust: "1.82"
+    python: "3.14"
+    rust: "latest"
 
 python:
   install:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nh3-0.3.0/Cargo.lock new/nh3-0.3.4/Cargo.lock
--- old/nh3-0.3.0/Cargo.lock    2025-07-17 16:38:00.000000000 +0200
+++ new/nh3-0.3.4/Cargo.lock    2006-07-24 03:21:28.000000000 +0200
@@ -10,9 +10,9 @@
 
 [[package]]
 name = "ammonia"
-version = "4.1.1"
+version = "4.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "d6b346764dd0814805de8abf899fe03065bcee69bb1a4771c785817e39f3978f"
+checksum = "17e913097e1a2124b46746c980134e8c954bc17a6a59bb3fde96f088d126dde6"
 dependencies = [
  "cssparser",
  "html5ever",
@@ -22,31 +22,26 @@
 ]
 
 [[package]]
-name = "autocfg"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
-
-[[package]]
 name = "bitflags"
-version = "2.9.1"
+version = "2.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
+checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
 
 [[package]]
 name = "cc"
-version = "1.2.29"
+version = "1.2.57"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362"
+checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423"
 dependencies = [
+ "find-msvc-tools",
  "shlex",
 ]
 
 [[package]]
 name = "cfg-if"
-version = "1.0.1"
+version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
 
 [[package]]
 name = "cssparser"
@@ -84,9 +79,9 @@
 
 [[package]]
 name = "dtoa"
-version = "1.0.10"
+version = "1.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04"
+checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590"
 
 [[package]]
 name = "dtoa-short"
@@ -98,10 +93,16 @@
 ]
 
 [[package]]
+name = "find-msvc-tools"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
+
+[[package]]
 name = "form_urlencoded"
-version = "1.2.1"
+version = "1.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
+checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
 dependencies = [
  "percent-encoding",
 ]
@@ -141,9 +142,9 @@
 
 [[package]]
 name = "icu_collections"
-version = "2.0.0"
+version = "2.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
+checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43"
 dependencies = [
  "displaydoc",
  "potential_utf",
@@ -154,9 +155,9 @@
 
 [[package]]
 name = "icu_locale_core"
-version = "2.0.0"
+version = "2.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
+checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6"
 dependencies = [
  "displaydoc",
  "litemap",
@@ -167,11 +168,10 @@
 
 [[package]]
 name = "icu_normalizer"
-version = "2.0.0"
+version = "2.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
+checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599"
 dependencies = [
- "displaydoc",
  "icu_collections",
  "icu_normalizer_data",
  "icu_properties",
@@ -182,42 +182,38 @@
 
 [[package]]
 name = "icu_normalizer_data"
-version = "2.0.0"
+version = "2.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
+checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a"
 
 [[package]]
 name = "icu_properties"
-version = "2.0.1"
+version = "2.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
+checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec"
 dependencies = [
- "displaydoc",
  "icu_collections",
  "icu_locale_core",
  "icu_properties_data",
  "icu_provider",
- "potential_utf",
  "zerotrie",
  "zerovec",
 ]
 
 [[package]]
 name = "icu_properties_data"
-version = "2.0.1"
+version = "2.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
+checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af"
 
 [[package]]
 name = "icu_provider"
-version = "2.0.0"
+version = "2.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
+checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614"
 dependencies = [
  "displaydoc",
  "icu_locale_core",
- "stable_deref_trait",
- "tinystr",
  "writeable",
  "yoke",
  "zerofrom",
@@ -227,9 +223,9 @@
 
 [[package]]
 name = "idna"
-version = "1.0.3"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
+checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
 dependencies = [
  "idna_adapter",
  "smallvec",
@@ -247,44 +243,37 @@
 ]
 
 [[package]]
-name = "indoc"
-version = "2.0.6"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
-
-[[package]]
 name = "itoa"
-version = "1.0.15"
+version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
 
 [[package]]
 name = "libc"
-version = "0.2.174"
+version = "0.2.183"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
+checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
 
 [[package]]
 name = "litemap"
-version = "0.8.0"
+version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
+checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"
 
 [[package]]
 name = "lock_api"
-version = "0.4.13"
+version = "0.4.14"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
+checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
 dependencies = [
- "autocfg",
  "scopeguard",
 ]
 
 [[package]]
 name = "log"
-version = "0.4.27"
+version = "0.4.29"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
+checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
 
 [[package]]
 name = "mac"
@@ -321,15 +310,6 @@
 ]
 
 [[package]]
-name = "memoffset"
-version = "0.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
 name = "new_debug_unreachable"
 version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index";
@@ -337,7 +317,7 @@
 
 [[package]]
 name = "nh3"
-version = "0.3.0"
+version = "0.3.4"
 dependencies = [
  "ammonia",
  "ouroboros",
@@ -346,9 +326,9 @@
 
 [[package]]
 name = "once_cell"
-version = "1.21.3"
+version = "1.21.4"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
 
 [[package]]
 name = "ouroboros"
@@ -376,9 +356,9 @@
 
 [[package]]
 name = "parking_lot"
-version = "0.12.4"
+version = "0.12.5"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
+checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
 dependencies = [
  "lock_api",
  "parking_lot_core",
@@ -386,22 +366,22 @@
 
 [[package]]
 name = "parking_lot_core"
-version = "0.9.11"
+version = "0.9.12"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
+checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
 dependencies = [
  "cfg-if",
  "libc",
  "redox_syscall",
  "smallvec",
- "windows-targets",
+ "windows-link",
 ]
 
 [[package]]
 name = "percent-encoding"
-version = "2.3.1"
+version = "2.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
 
 [[package]]
 name = "phf"
@@ -457,15 +437,15 @@
 
 [[package]]
 name = "portable-atomic"
-version = "1.11.1"
+version = "1.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
+checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
 
 [[package]]
 name = "potential_utf"
-version = "0.1.2"
+version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585"
+checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77"
 dependencies = [
  "zerovec",
 ]
@@ -478,9 +458,9 @@
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.95"
+version = "1.0.106"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
+checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
 dependencies = [
  "unicode-ident",
 ]
@@ -500,37 +480,33 @@
 
 [[package]]
 name = "pyo3"
-version = "0.25.1"
+version = "0.28.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "8970a78afe0628a3e3430376fc5fd76b6b45c4d43360ffd6cdd40bdde72b682a"
+checksum = "cf85e27e86080aafd5a22eae58a162e133a589551542b3e5cee4beb27e54f8e1"
 dependencies = [
- "indoc",
  "libc",
- "memoffset",
  "once_cell",
  "portable-atomic",
  "pyo3-build-config",
  "pyo3-ffi",
  "pyo3-macros",
- "unindent",
 ]
 
 [[package]]
 name = "pyo3-build-config"
-version = "0.25.1"
+version = "0.28.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "458eb0c55e7ece017adeba38f2248ff3ac615e53660d7c71a238d7d2a01c7598"
+checksum = "8bf94ee265674bf76c09fa430b0e99c26e319c945d96ca0d5a8215f31bf81cf7"
 dependencies = [
- "once_cell",
  "python3-dll-a",
  "target-lexicon",
 ]
 
 [[package]]
 name = "pyo3-ffi"
-version = "0.25.1"
+version = "0.28.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "7114fe5457c61b276ab77c5055f206295b812608083644a5c5b2640c3102565c"
+checksum = "491aa5fc66d8059dd44a75f4580a2962c1862a1c2945359db36f6c2818b748dc"
 dependencies = [
  "libc",
  "pyo3-build-config",
@@ -538,9 +514,9 @@
 
 [[package]]
 name = "pyo3-macros"
-version = "0.25.1"
+version = "0.28.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "a8725c0a622b374d6cb051d11a0983786448f7785336139c3c94f5aa6bef7e50"
+checksum = "f5d671734e9d7a43449f8480f8b38115df67bef8d21f76837fa75ee7aaa5e52e"
 dependencies = [
  "proc-macro2",
  "pyo3-macros-backend",
@@ -550,9 +526,9 @@
 
 [[package]]
 name = "pyo3-macros-backend"
-version = "0.25.1"
+version = "0.28.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "4109984c22491085343c05b0dbc54ddc405c3cf7b4374fc533f5c3313a572ccc"
+checksum = "22faaa1ce6c430a1f71658760497291065e6450d7b5dc2bcf254d49f66ee700a"
 dependencies = [
  "heck 0.5.0",
  "proc-macro2",
@@ -572,9 +548,9 @@
 
 [[package]]
 name = "quote"
-version = "1.0.40"
+version = "1.0.45"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
 dependencies = [
  "proc-macro2",
 ]
@@ -596,9 +572,9 @@
 
 [[package]]
 name = "redox_syscall"
-version = "0.5.13"
+version = "0.5.18"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6"
+checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
 dependencies = [
  "bitflags",
 ]
@@ -611,18 +587,27 @@
 
 [[package]]
 name = "serde"
-version = "1.0.219"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.219"
+version = "1.0.228"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -637,9 +622,9 @@
 
 [[package]]
 name = "siphasher"
-version = "1.0.1"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
+checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e"
 
 [[package]]
 name = "smallvec"
@@ -649,9 +634,9 @@
 
 [[package]]
 name = "stable_deref_trait"
-version = "1.2.0"
+version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
 
 [[package]]
 name = "static_assertions"
@@ -686,9 +671,9 @@
 
 [[package]]
 name = "syn"
-version = "2.0.104"
+version = "2.0.117"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
+checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -708,9 +693,9 @@
 
 [[package]]
 name = "target-lexicon"
-version = "0.13.2"
+version = "0.13.5"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a"
+checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
 
 [[package]]
 name = "tendril"
@@ -725,9 +710,9 @@
 
 [[package]]
 name = "tinystr"
-version = "0.8.1"
+version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b"
+checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869"
 dependencies = [
  "displaydoc",
  "zerovec",
@@ -735,25 +720,20 @@
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.18"
+version = "1.0.24"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
-
-[[package]]
-name = "unindent"
-version = "0.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
+checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
 
 [[package]]
 name = "url"
-version = "2.5.4"
+version = "2.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
+checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
 dependencies = [
  "form_urlencoded",
  "idna",
  "percent-encoding",
+ "serde",
 ]
 
 [[package]]
@@ -787,74 +767,16 @@
 ]
 
 [[package]]
-name = "windows-targets"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
-dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_gnullvm",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
-]
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
-
-[[package]]
-name = "windows_i686_gnullvm"
-version = "0.52.6"
+name = "windows-link"
+version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
 
 [[package]]
 name = "writeable"
-version = "0.6.1"
+version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
+checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
 
 [[package]]
 name = "yansi"
@@ -864,11 +786,10 @@
 
 [[package]]
 name = "yoke"
-version = "0.8.0"
+version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
+checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954"
 dependencies = [
- "serde",
  "stable_deref_trait",
  "yoke-derive",
  "zerofrom",
@@ -876,9 +797,9 @@
 
 [[package]]
 name = "yoke-derive"
-version = "0.8.0"
+version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
+checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -909,9 +830,9 @@
 
 [[package]]
 name = "zerotrie"
-version = "0.2.2"
+version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
+checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851"
 dependencies = [
  "displaydoc",
  "yoke",
@@ -920,9 +841,9 @@
 
 [[package]]
 name = "zerovec"
-version = "0.11.2"
+version = "0.11.5"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428"
+checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002"
 dependencies = [
  "yoke",
  "zerofrom",
@@ -931,9 +852,9 @@
 
 [[package]]
 name = "zerovec-derive"
-version = "0.11.1"
+version = "0.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
+checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
 dependencies = [
  "proc-macro2",
  "quote",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nh3-0.3.0/Cargo.toml new/nh3-0.3.4/Cargo.toml
--- old/nh3-0.3.0/Cargo.toml    1970-01-01 01:00:00.000000000 +0100
+++ new/nh3-0.3.4/Cargo.toml    2006-07-24 03:21:28.000000000 +0200
@@ -1,8 +1,8 @@
 [package]
 name = "nh3"
-version = "0.3.0"
+version = "0.3.4"
 authors = ["messense <[email protected]>"]
-edition = "2021"
+edition = "2024"
 description = "Python bindings to the ammonia HTML sanitization library."
 license = "MIT"
 repository = "https://github.com/messense/nh3";
@@ -14,6 +14,6 @@
 crate-type = ["cdylib"]
 
 [dependencies]
-ammonia = "4.1.1"
-pyo3 = { version = "0.25.1", features = ["abi3-py38", "generate-import-lib"] }
+ammonia = "4.1.2"
+pyo3 = { version = "0.28.2", features = ["abi3-py38", "generate-import-lib"] }
 ouroboros = "0.18"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nh3-0.3.0/PKG-INFO new/nh3-0.3.4/PKG-INFO
--- old/nh3-0.3.0/PKG-INFO      1970-01-01 01:00:00.000000000 +0100
+++ new/nh3-0.3.4/PKG-INFO      2006-07-24 03:21:28.000000000 +0200
@@ -1,13 +1,12 @@
 Metadata-Version: 2.4
 Name: nh3
-Version: 0.3.0
+Version: 0.3.4
 Classifier: Programming Language :: Rust
 Classifier: Programming Language :: Python :: Implementation :: CPython
 Classifier: Programming Language :: Python :: Implementation :: PyPy
 Classifier: Topic :: Software Development :: Libraries :: Python Modules
 License-File: LICENSE
 Summary: Python binding to Ammonia HTML sanitizer Rust crate
-Author: messense <[email protected]>
 Author-email: messense <[email protected]>
 License: MIT
 Requires-Python: >=3.8
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nh3-0.3.0/nh3.pyi new/nh3-0.3.4/nh3.pyi
--- old/nh3-0.3.0/nh3.pyi       2025-07-17 16:38:00.000000000 +0200
+++ new/nh3-0.3.4/nh3.pyi       2006-07-24 03:21:28.000000000 +0200
@@ -1,41 +1,42 @@
-from typing import Callable, Dict, Optional, Set
+from typing import AbstractSet, Callable, Dict, Mapping, Optional, Set
 
 ALLOWED_TAGS: Set[str]
 ALLOWED_ATTRIBUTES: Dict[str, Set[str]]
 ALLOWED_URL_SCHEMES: Set[str]
+CLEAN_CONTENT_TAGS: Set[str]
 
 class Cleaner:
     def __init__(
         self,
-        tags: Optional[Set[str]] = None,
-        clean_content_tags: Optional[Set[str]] = None,
-        attributes: Optional[Dict[str, Set[str]]] = None,
+        tags: Optional[AbstractSet[str]] = None,
+        clean_content_tags: Optional[AbstractSet[str]] = None,
+        attributes: Optional[Mapping[str, AbstractSet[str]]] = None,
         attribute_filter: Optional[Callable[[str, str, str], Optional[str]]] = 
None,
         strip_comments: bool = True,
         link_rel: Optional[str] = "noopener noreferrer",
-        generic_attribute_prefixes: Optional[Set[str]] = None,
-        tag_attribute_values: Optional[Dict[str, Dict[str, Set[str]]]] = None,
-        set_tag_attribute_values: Optional[Dict[str, Dict[str, str]]] = None,
-        url_schemes: Optional[Set[str]] = None,
-        allowed_classes: Optional[Dict[str, Set[str]]] = None,
-        filter_style_properties: Optional[Set[str]] = None,
+        generic_attribute_prefixes: Optional[AbstractSet[str]] = None,
+        tag_attribute_values: Optional[Mapping[str, Mapping[str, 
AbstractSet[str]]]] = None,
+        set_tag_attribute_values: Optional[Mapping[str, Mapping[str, str]]] = 
None,
+        url_schemes: Optional[AbstractSet[str]] = None,
+        allowed_classes: Optional[Mapping[str, AbstractSet[str]]] = None,
+        filter_style_properties: Optional[AbstractSet[str]] = None,
     ) -> None: ...
     def clean(self, html: str) -> str: ...
 
 def clean(
     html: str,
-    tags: Optional[Set[str]] = None,
-    clean_content_tags: Optional[Set[str]] = None,
-    attributes: Optional[Dict[str, Set[str]]] = None,
+    tags: Optional[AbstractSet[str]] = None,
+    clean_content_tags: Optional[AbstractSet[str]] = None,
+    attributes: Optional[Mapping[str, AbstractSet[str]]] = None,
     attribute_filter: Optional[Callable[[str, str, str], Optional[str]]] = 
None,
     strip_comments: bool = True,
     link_rel: Optional[str] = "noopener noreferrer",
-    generic_attribute_prefixes: Optional[Set[str]] = None,
-    tag_attribute_values: Optional[Dict[str, Dict[str, Set[str]]]] = None,
-    set_tag_attribute_values: Optional[Dict[str, Dict[str, str]]] = None,
-    url_schemes: Optional[Set[str]] = None,
-    allowed_classes: Optional[Dict[str, Set[str]]] = None,
-    filter_style_properties: Optional[Set[str]] = None,
+    generic_attribute_prefixes: Optional[AbstractSet[str]] = None,
+    tag_attribute_values: Optional[Mapping[str, Mapping[str, 
AbstractSet[str]]]] = None,
+    set_tag_attribute_values: Optional[Mapping[str, Mapping[str, str]]] = None,
+    url_schemes: Optional[AbstractSet[str]] = None,
+    allowed_classes: Optional[Mapping[str, AbstractSet[str]]] = None,
+    filter_style_properties: Optional[AbstractSet[str]] = None,
 ) -> str: ...
 def clean_text(html: str) -> str: ...
 def is_html(html: str) -> bool: ...
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nh3-0.3.0/pyproject.toml new/nh3-0.3.4/pyproject.toml
--- old/nh3-0.3.0/pyproject.toml        2025-07-17 16:38:00.000000000 +0200
+++ new/nh3-0.3.4/pyproject.toml        2006-07-24 03:21:28.000000000 +0200
@@ -6,6 +6,7 @@
 name = "nh3"
 description = "Python binding to Ammonia HTML sanitizer Rust crate"
 authors = [{ name = "messense", email = "[email protected]" }]
+readme = "README.md"
 requires-python = ">=3.8"
 license = {text = "MIT"}
 classifiers = [
@@ -14,7 +15,7 @@
     "Programming Language :: Python :: Implementation :: PyPy",
     "Topic :: Software Development :: Libraries :: Python Modules",
 ]
-dynamic = ["version"]
+dynamic = ["urls", "version"]
 
 [tool.maturin]
 features = ["pyo3/extension-module"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nh3-0.3.0/src/lib.rs new/nh3-0.3.4/src/lib.rs
--- old/nh3-0.3.0/src/lib.rs    2025-07-17 16:38:00.000000000 +0200
+++ new/nh3-0.3.4/src/lib.rs    2006-07-24 03:21:28.000000000 +0200
@@ -2,7 +2,7 @@
 use std::collections::{HashMap, HashSet};
 
 use ouroboros::self_referencing;
-use pyo3::exceptions::PyTypeError;
+use pyo3::exceptions::{PyTypeError, PyValueError};
 use pyo3::prelude::*;
 use pyo3::types::{PyString, PyTuple};
 
@@ -10,7 +10,7 @@
     tags: Option<HashSet<String>>,
     clean_content_tags: Option<HashSet<String>>,
     attributes: Option<HashMap<String, HashSet<String>>>,
-    attribute_filter: Option<PyObject>,
+    attribute_filter: Option<Py<PyAny>>,
     strip_comments: bool,
     link_rel: Option<String>,
     generic_attribute_prefixes: Option<HashSet<String>>,
@@ -48,6 +48,51 @@
     builder: ammonia::Builder<'this>,
 }
 
+/// Create a reusable sanitizer according to the given options.
+///
+/// :param tags: Sets the tags that are allowed.
+/// :type tags: ``set[str]``, optional
+/// :param clean_content_tags: Sets the tags whose contents will be completely 
removed from the output.
+/// :type clean_content_tags: ``set[str]``, optional
+/// :param attributes: Sets the HTML attributes that are allowed on specific 
tags,
+///    ``*`` key means the attributes are allowed on any tag.
+/// :type attributes: ``dict[str, set[str]]``, optional
+/// :param attribute_filter: Allows rewriting of all attributes using a 
callback.
+///     The callback takes name of the element, attribute and its value.
+///     Returns ``None`` to remove the attribute, or a value to use.
+/// :type attribute_filter: ``Callable[[str, str, str], str | None]``, optional
+/// :param strip_comments: Configures the handling of HTML comments, defaults 
to ``True``.
+/// :type strip_comments: ``bool``
+/// :param link_rel: Configures a ``rel`` attribute that will be added on 
links, defaults to ``noopener noreferrer``.
+///     To turn on rel-insertion, pass a space-separated list.
+///     If ``rel`` is in the generic or tag attributes, this must be set to 
``None``. Common ``rel`` values to include:
+///
+///     - ``noopener``: This prevents a particular type of XSS attack, and 
should usually be turned on for untrusted HTML.
+///     - ``noreferrer``: This prevents the browser from sending the source 
URL to the website that is linked to.
+///     - ``nofollow``: This prevents search engines from using this link for 
ranking, which disincentivizes spammers.
+/// :type link_rel: ``str``
+/// :param generic_attribute_prefixes: Sets the prefix of attributes that are 
allowed on any tag.
+/// :type generic_attribute_prefixes: ``set[str]``, optional
+/// :param tag_attribute_values: Sets the values of HTML attributes that are 
allowed on specific tags.
+///     The value is structured as a map from tag names to a map from 
attribute names to a set of attribute values.
+///     If a tag is not itself whitelisted, adding entries to this map will do 
nothing.
+/// :type tag_attribute_values: ``dict[str, dict[str, set[str]]]``, optional
+/// :param set_tag_attribute_values: Sets the values of HTML attributes that 
are to be set on specific tags.
+///     The value is structured as a map from tag names to a map from 
attribute names to an attribute value.
+///     If a tag is not itself whitelisted, adding entries to this map will do 
nothing.
+/// :type set_tag_attribute_values: ``dict[str, dict[str, str]]``, optional
+/// :param url_schemes: Sets the URL schemes permitted on ``href`` and ``src`` 
attributes.
+/// :type url_schemes: ``set[str]``, optional
+/// :param allowed_classes: Sets the CSS classes that are allowed on specific 
tags.
+///     The values is structured as a map from tag names to a set of class 
names.
+///     The `class` attribute itself should not be whitelisted if this 
parameter is used.
+/// :type allowed_classes: ``dict[str, set[str]]``, optional
+/// :param filter_style_properties: Only allows the specified properties in 
`style` attributes.
+///     Irrelevant if `style` is not an allowed attribute.
+///     Note that if style filtering is enabled style properties will be 
normalised e.g.
+///     invalid declarations and @rules will be removed, with only 
syntactically valid
+///     declarations kept.
+/// :type filter_style_properties: ``set[str]``, optional
 #[pyclass]
 pub struct Cleaner {
     inner: Inner,
@@ -122,10 +167,10 @@
         let attribute_filter = config
             .attribute_filter
             .as_ref()
-            .map(|f| Python::with_gil(|py| f.clone_ref(py)));
+            .map(|f| Python::attach(|py| f.clone_ref(py)));
         if let Some(callback) = attribute_filter {
             builder.attribute_filter(move |element, attribute, value| {
-                Python::with_gil(|py| {
+                Python::attach(|py| {
                     let res = callback.call(
                         py,
                         PyTuple::new(
@@ -143,12 +188,15 @@
                         Ok(val) => {
                             if val.is_none(py) {
                                 return None;
-                            } else if let Ok(s) = val.extract::<String>(py) {
-                                return Some(Cow::<str>::Owned(s));
                             } else {
-                                PyTypeError::new_err(
-                                    "expected attribute_filter to return str 
or None",
-                                )
+                                match val.extract::<String>(py) {
+                                    Ok(s) => {
+                                        return Some(Cow::<str>::Owned(s));
+                                    }
+                                    _ => PyTypeError::new_err(
+                                        "expected attribute_filter to return 
str or None",
+                                    ),
+                                }
                             }
                         }
                         Err(err) => err,
@@ -207,51 +255,6 @@
 
 #[pymethods]
 impl Cleaner {
-    /// Create a reusable sanitizer according to the given options.
-    ///
-    /// :param tags: Sets the tags that are allowed.
-    /// :type tags: ``set[str]``, optional
-    /// :param clean_content_tags: Sets the tags whose contents will be 
completely removed from the output.
-    /// :type clean_content_tags: ``set[str]``, optional
-    /// :param attributes: Sets the HTML attributes that are allowed on 
specific tags,
-    ///    ``*`` key means the attributes are allowed on any tag.
-    /// :type attributes: ``dict[str, set[str]]``, optional
-    /// :param attribute_filter: Allows rewriting of all attributes using a 
callback.
-    ///     The callback takes name of the element, attribute and its value.
-    ///     Returns ``None`` to remove the attribute, or a value to use.
-    /// :type attribute_filter: ``Callable[[str, str, str], str | None]``, 
optional
-    /// :param strip_comments: Configures the handling of HTML comments, 
defaults to ``True``.
-    /// :type strip_comments: ``bool``
-    /// :param link_rel: Configures a ``rel`` attribute that will be added on 
links, defaults to ``noopener noreferrer``.
-    ///     To turn on rel-insertion, pass a space-separated list.
-    ///     If ``rel`` is in the generic or tag attributes, this must be set 
to ``None``. Common ``rel`` values to include:
-    ///
-    ///     - ``noopener``: This prevents a particular type of XSS attack, and 
should usually be turned on for untrusted HTML.
-    ///     - ``noreferrer``: This prevents the browser from sending the 
source URL to the website that is linked to.
-    ///     - ``nofollow``: This prevents search engines from using this link 
for ranking, which disincentivizes spammers.
-    /// :type link_rel: ``str``
-    /// :param generic_attribute_prefixes: Sets the prefix of attributes that 
are allowed on any tag.
-    /// :type generic_attribute_prefixes: ``set[str]``, optional
-    /// :param tag_attribute_values: Sets the values of HTML attributes that 
are allowed on specific tags.
-    ///     The value is structured as a map from tag names to a map from 
attribute names to a set of attribute values.
-    ///     If a tag is not itself whitelisted, adding entries to this map 
will do nothing.
-    /// :type tag_attribute_values: ``dict[str, dict[str, set[str]]]``, 
optional
-    /// :param set_tag_attribute_values: Sets the values of HTML attributes 
that are to be set on specific tags.
-    ///     The value is structured as a map from tag names to a map from 
attribute names to an attribute value.
-    ///     If a tag is not itself whitelisted, adding entries to this map 
will do nothing.
-    /// :type set_tag_attribute_values: ``dict[str, dict[str, str]]``, optional
-    /// :param url_schemes: Sets the URL schemes permitted on ``href`` and 
``src`` attributes.
-    /// :type url_schemes: ``set[str]``, optional
-    /// :param allowed_classes: Sets the CSS classes that are allowed on 
specific tags.
-    ///     The values is structured as a map from tag names to a set of class 
names.
-    ///     The `class` attribute itself should not be whitelisted if this 
parameter is used.
-    /// :type allowed_classes: ``dict[str, set[str]]``, optional
-    /// :param filter_style_properties: Only allows the specified properties 
in `style` attributes.
-    ///     Irrelevant if `style` is not an allowed attribute.
-    ///     Note that if style filtering is enabled style properties will be 
normalised e.g.
-    ///     invalid declarations and @rules will be removed, with only 
syntactically valid
-    ///     declarations kept.
-    /// :type filter_style_properties: ``set[str]``, optional
     #[new]
     #[pyo3(signature = (
         tags = None,
@@ -272,7 +275,7 @@
         tags: Option<HashSet<String>>,
         clean_content_tags: Option<HashSet<String>>,
         attributes: Option<HashMap<String, HashSet<String>>>,
-        attribute_filter: Option<PyObject>,
+        attribute_filter: Option<Py<PyAny>>,
         strip_comments: bool,
         link_rel: Option<&str>,
         generic_attribute_prefixes: Option<HashSet<String>>,
@@ -287,6 +290,19 @@
                 return Err(PyTypeError::new_err("attribute_filter must be 
callable"));
             }
         }
+        if link_rel.is_some() {
+            if let Some(ref attrs) = attributes {
+                for (tag, attr_set) in attrs.iter() {
+                    if attr_set.contains("rel") {
+                        return Err(PyValueError::new_err(format!(
+                            "\"rel\" attribute is not allowed for tag \"{}\" 
when link_rel is set; \
+                             pass link_rel=None to manage the \"rel\" 
attribute directly",
+                            tag
+                        )));
+                    }
+                }
+            }
+        }
         let config = Config {
             tags,
             clean_content_tags,
@@ -307,7 +323,7 @@
     /// Sanitize an HTML fragment
     #[pyo3(name = "clean")]
     fn py_clean(&self, py: Python, html: &str) -> PyResult<String> {
-        Ok(py.allow_threads(|| self.clean(html)))
+        Ok(py.detach(|| self.clean(html)))
     }
 }
 
@@ -380,7 +396,7 @@
     tags: Option<HashSet<String>>,
     clean_content_tags: Option<HashSet<String>>,
     attributes: Option<HashMap<String, HashSet<String>>>,
-    attribute_filter: Option<PyObject>,
+    attribute_filter: Option<Py<PyAny>>,
     strip_comments: bool,
     link_rel: Option<&str>,
     generic_attribute_prefixes: Option<HashSet<String>>,
@@ -405,7 +421,7 @@
         allowed_classes,
         filter_style_properties,
     )?;
-    Ok(py.allow_threads(|| cleaner.clean(html)))
+    Ok(py.detach(|| cleaner.clean(html)))
 }
 
 /// Turn an arbitrary string into unformatted HTML.
@@ -428,7 +444,7 @@
 ///      'Robert&quot;);&#32;abuse();&#47;&#47;'
 #[pyfunction]
 fn clean_text(py: Python, html: &str) -> String {
-    py.allow_threads(|| ammonia::clean_text(html))
+    py.detach(|| ammonia::clean_text(html))
 }
 
 /// Determine if a given string contains HTML.
@@ -452,7 +468,7 @@
 ///     True
 #[pyfunction]
 fn is_html(py: Python, html: &str) -> bool {
-    py.allow_threads(|| ammonia::is_html(html))
+    py.detach(|| ammonia::is_html(html))
 }
 
 /// Python bindings to the ammonia HTML sanitization library ( 
https://github.com/rust-ammonia/ammonia ).
@@ -468,5 +484,6 @@
     m.add("ALLOWED_TAGS", a.clone_tags())?;
     m.add("ALLOWED_ATTRIBUTES", a.clone_tag_attributes())?;
     m.add("ALLOWED_URL_SCHEMES", a.clone_url_schemes())?;
+    m.add("CLEAN_CONTENT_TAGS", a.clone_clean_content_tags())?;
     Ok(())
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nh3-0.3.0/tests/test_nh3.py 
new/nh3-0.3.4/tests/test_nh3.py
--- old/nh3-0.3.0/tests/test_nh3.py     2025-07-17 16:38:00.000000000 +0200
+++ new/nh3-0.3.4/tests/test_nh3.py     2006-07-24 03:21:28.000000000 +0200
@@ -88,11 +88,76 @@
     nh3.clean(html, attribute_filter=lambda _element, _attribute, _value: True)
 
 
+def test_clean_rel_attribute_conflict():
+    with pytest.raises(ValueError, match="link_rel is set"):
+        nh3.clean(
+            "<a href='http://example.com'>test</a>",
+            tags={"a"},
+            attributes={"a": {"href", "rel"}},
+        )
+
+    # No error when link_rel=None
+    result = nh3.clean(
+        "<a href='http://example.com' rel='nofollow'>test</a>",
+        tags={"a"},
+        attributes={"a": {"href", "rel"}},
+        link_rel=None,
+    )
+    assert result == '<a href="http://example.com"; rel="nofollow">test</a>'
+
+    # No error when rel is not in attributes
+    nh3.clean(
+        "<a href='http://example.com'>test</a>",
+        tags={"a"},
+        attributes={"a": {"href"}},
+    )
+
+
+def test_cleaner_rel_attribute_conflict():
+    with pytest.raises(ValueError, match="link_rel is set"):
+        nh3.Cleaner(
+            tags={"a"},
+            attributes={"a": {"href", "rel"}},
+        )
+
+    # No error when link_rel=None
+    cleaner = nh3.Cleaner(
+        tags={"a"},
+        attributes={"a": {"href", "rel"}},
+        link_rel=None,
+    )
+    result = cleaner.clean("<a href='http://example.com' 
rel='nofollow'>test</a>")
+    assert result == '<a href="http://example.com"; rel="nofollow">test</a>'
+
+
 def test_clean_text():
     res = nh3.clean_text('Robert"); abuse();//')
     assert res == "Robert&quot;);&#32;abuse();&#47;&#47;"
 
 
+def test_clean_content_tags_constant():
+    assert isinstance(nh3.CLEAN_CONTENT_TAGS, set)
+    assert "script" in nh3.CLEAN_CONTENT_TAGS
+    assert "style" in nh3.CLEAN_CONTENT_TAGS
+
+
+def test_frozenset_args():
+    html = "<b><img src='x'>hello</b>"
+    assert nh3.clean(html, tags=frozenset({"b"})) == "<b>hello</b>"
+    assert (
+        nh3.clean(html, tags=frozenset({"img"}), attributes={"img": 
frozenset({"src"})})
+        == '<img src="x">hello'
+    )
+
+
+def test_cleaner_frozenset_args():
+    cleaner = nh3.Cleaner(
+        tags=frozenset({"b", "img"}),
+        attributes={"img": frozenset({"src"})},
+    )
+    assert cleaner.clean("<b><img src='x'>hi</b>") == '<b><img src="x">hi</b>'
+
+
 def test_is_html():
     assert not nh3.is_html("plain text")
     assert nh3.is_html("<p>html!</p>")

++++++ vendor.tar.zst ++++++
/work/SRC/openSUSE:Factory/python-nh3/vendor.tar.zst 
/work/SRC/openSUSE:Factory/.python-nh3.new.21863/vendor.tar.zst differ: char 7, 
line 1

Reply via email to