brewdoc-darwin-arm64 0.0.0-stage → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +128 -2
- package/binary/_internal/PIL/.dylibs/libXau.6.dylib +0 -0
- package/binary/_internal/PIL/.dylibs/libavif.16.4.2.dylib +0 -0
- package/binary/_internal/PIL/.dylibs/libbrotlicommon.1.2.0.dylib +0 -0
- package/binary/_internal/PIL/.dylibs/libbrotlidec.1.2.0.dylib +0 -0
- package/binary/_internal/PIL/.dylibs/libfreetype.6.dylib +0 -0
- package/binary/_internal/PIL/.dylibs/libharfbuzz.0.dylib +0 -0
- package/binary/_internal/PIL/.dylibs/libjpeg.62.4.0.dylib +0 -0
- package/binary/_internal/PIL/.dylibs/liblcms2.2.dylib +0 -0
- package/binary/_internal/PIL/.dylibs/liblzma.5.dylib +0 -0
- package/binary/_internal/PIL/.dylibs/libopenjp2.2.5.4.dylib +0 -0
- package/binary/_internal/PIL/.dylibs/libpng16.16.dylib +0 -0
- package/binary/_internal/PIL/.dylibs/libsharpyuv.0.dylib +0 -0
- package/binary/_internal/PIL/.dylibs/libtiff.6.dylib +0 -0
- package/binary/_internal/PIL/.dylibs/libwebp.7.dylib +0 -0
- package/binary/_internal/PIL/.dylibs/libwebpdemux.2.dylib +0 -0
- package/binary/_internal/PIL/.dylibs/libwebpmux.3.dylib +0 -0
- package/binary/_internal/PIL/.dylibs/libxcb.1.1.0.dylib +0 -0
- package/binary/_internal/PIL/.dylibs/libz.1.3.1.zlib-ng.dylib +0 -0
- package/binary/_internal/PIL/_avif.cpython-312-darwin.so +0 -0
- package/binary/_internal/PIL/_imaging.cpython-312-darwin.so +0 -0
- package/binary/_internal/PIL/_imagingcms.cpython-312-darwin.so +0 -0
- package/binary/_internal/PIL/_imagingft.cpython-312-darwin.so +0 -0
- package/binary/_internal/PIL/_imagingmath.cpython-312-darwin.so +0 -0
- package/binary/_internal/PIL/_imagingtk.cpython-312-darwin.so +0 -0
- package/binary/_internal/PIL/_webp.cpython-312-darwin.so +0 -0
- package/binary/_internal/_cffi_backend.cpython-312-darwin.so +0 -0
- package/binary/_internal/_quickjs.abi3.so +0 -0
- package/binary/_internal/base_library.zip +0 -0
- package/binary/_internal/brewdoc/_urljs/glue.js +858 -0
- package/binary/_internal/brewdoc/_vendor/THIRD_PARTY_NOTICES.txt +342 -0
- package/binary/_internal/brewdoc/_vendor/linkedom-worker.js +12650 -0
- package/binary/_internal/brewdoc-0.3.2.dist-info/INSTALLER +1 -0
- package/binary/_internal/brewdoc-0.3.2.dist-info/METADATA +157 -0
- package/binary/_internal/brewdoc-0.3.2.dist-info/RECORD +30 -0
- package/binary/_internal/brewdoc-0.3.2.dist-info/REQUESTED +0 -0
- package/binary/_internal/brewdoc-0.3.2.dist-info/WHEEL +4 -0
- package/binary/_internal/brewdoc-0.3.2.dist-info/direct_url.json +1 -0
- package/binary/_internal/brewdoc-0.3.2.dist-info/entry_points.txt +2 -0
- package/binary/_internal/brewdoc-0.3.2.dist-info/licenses/LICENSE +21 -0
- package/binary/_internal/brewdoc-0.3.2.dist-info/uv_cache.json +1 -0
- package/binary/_internal/cffi-2.1.1.dist-info/INSTALLER +1 -0
- package/binary/_internal/cffi-2.1.1.dist-info/METADATA +67 -0
- package/binary/_internal/cffi-2.1.1.dist-info/RECORD +34 -0
- package/binary/_internal/cffi-2.1.1.dist-info/REQUESTED +0 -0
- package/binary/_internal/cffi-2.1.1.dist-info/WHEEL +6 -0
- package/binary/_internal/cffi-2.1.1.dist-info/entry_points.txt +5 -0
- package/binary/_internal/cffi-2.1.1.dist-info/licenses/LICENSE +23 -0
- package/binary/_internal/cffi-2.1.1.dist-info/top_level.txt +2 -0
- package/binary/_internal/charset_normalizer/cd.cpython-312-darwin.so +0 -0
- package/binary/_internal/charset_normalizer/md.cpython-312-darwin.so +0 -0
- package/binary/_internal/charset_normalizer-3.5.2.dist-info/INSTALLER +1 -0
- package/binary/_internal/charset_normalizer-3.5.2.dist-info/METADATA +892 -0
- package/binary/_internal/charset_normalizer-3.5.2.dist-info/RECORD +24 -0
- package/binary/_internal/charset_normalizer-3.5.2.dist-info/REQUESTED +0 -0
- package/binary/_internal/charset_normalizer-3.5.2.dist-info/WHEEL +6 -0
- package/binary/_internal/charset_normalizer-3.5.2.dist-info/entry_points.txt +2 -0
- package/binary/_internal/charset_normalizer-3.5.2.dist-info/licenses/LICENSE +21 -0
- package/binary/_internal/charset_normalizer-3.5.2.dist-info/top_level.txt +1 -0
- package/binary/_internal/cryptography/hazmat/bindings/_rust.abi3.so +0 -0
- package/binary/_internal/cryptography-50.0.2.dist-info/INSTALLER +1 -0
- package/binary/_internal/cryptography-50.0.2.dist-info/METADATA +111 -0
- package/binary/_internal/cryptography-50.0.2.dist-info/RECORD +122 -0
- package/binary/_internal/cryptography-50.0.2.dist-info/REQUESTED +0 -0
- package/binary/_internal/cryptography-50.0.2.dist-info/WHEEL +4 -0
- package/binary/_internal/cryptography-50.0.2.dist-info/licenses/LICENSE +3 -0
- package/binary/_internal/cryptography-50.0.2.dist-info/licenses/LICENSE.APACHE +202 -0
- package/binary/_internal/cryptography-50.0.2.dist-info/licenses/LICENSE.BSD +27 -0
- package/binary/_internal/cryptography-50.0.2.dist-info/sboms/cryptography-rust.cyclonedx.json +1365 -0
- package/binary/_internal/cryptography-50.0.2.dist-info/sboms/sbom.json +43 -0
- package/binary/_internal/libXau.6.dylib +0 -0
- package/binary/_internal/libavif.16.4.2.dylib +0 -0
- package/binary/_internal/libbrotlicommon.1.2.0.dylib +0 -0
- package/binary/_internal/libbrotlidec.1.2.0.dylib +0 -0
- package/binary/_internal/libfreetype.6.dylib +0 -0
- package/binary/_internal/libharfbuzz.0.dylib +0 -0
- package/binary/_internal/libjpeg.62.4.0.dylib +0 -0
- package/binary/_internal/liblcms2.2.dylib +0 -0
- package/binary/_internal/liblzma.5.dylib +0 -0
- package/binary/_internal/libopenjp2.2.5.4.dylib +0 -0
- package/binary/_internal/libpng16.16.dylib +0 -0
- package/binary/_internal/libpython3.12.dylib +0 -0
- package/binary/_internal/libsharpyuv.0.dylib +0 -0
- package/binary/_internal/libtiff.6.dylib +0 -0
- package/binary/_internal/libwebp.7.dylib +0 -0
- package/binary/_internal/libwebpdemux.2.dylib +0 -0
- package/binary/_internal/libwebpmux.3.dylib +0 -0
- package/binary/_internal/libxcb.1.1.0.dylib +0 -0
- package/binary/_internal/libz.1.3.1.zlib-ng.dylib +0 -0
- package/binary/_internal/pdfminer/cmap/78-EUC-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/78-EUC-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/78-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/78-RKSJ-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/78-RKSJ-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/78-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/78ms-RKSJ-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/78ms-RKSJ-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/83pv-RKSJ-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/83pv-RKSJ-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/90ms-RKSJ-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/90ms-RKSJ-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/90msp-RKSJ-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/90msp-RKSJ-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/90pv-RKSJ-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/90pv-RKSJ-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/Add-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/Add-RKSJ-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/Add-RKSJ-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/Add-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/B5-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/B5-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/B5pc-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/B5pc-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/CNS-EUC-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/CNS-EUC-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/CNS1-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/CNS1-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/CNS2-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/CNS2-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/ETHK-B5-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/ETHK-B5-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/ETen-B5-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/ETen-B5-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/ETenms-B5-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/ETenms-B5-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/EUC-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/EUC-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/Ext-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/Ext-RKSJ-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/Ext-RKSJ-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/Ext-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/GB-EUC-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/GB-EUC-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/GB-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/GB-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/GBK-EUC-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/GBK-EUC-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/GBK2K-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/GBK2K-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/GBKp-EUC-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/GBKp-EUC-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/GBT-EUC-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/GBT-EUC-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/GBT-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/GBT-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/GBTpc-EUC-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/GBTpc-EUC-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/GBpc-EUC-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/GBpc-EUC-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/HKdla-B5-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/HKdla-B5-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/HKdlb-B5-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/HKdlb-B5-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/HKgccs-B5-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/HKgccs-B5-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/HKm314-B5-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/HKm314-B5-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/HKm471-B5-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/HKm471-B5-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/HKscs-B5-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/HKscs-B5-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/Hankaku-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/Hankaku-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/Hiragana-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/Hiragana-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/KSC-EUC-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/KSC-EUC-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/KSC-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/KSC-Johab-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/KSC-Johab-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/KSC-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/KSCms-UHC-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/KSCms-UHC-HW-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/KSCms-UHC-HW-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/KSCms-UHC-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/KSCpc-EUC-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/KSCpc-EUC-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/Katakana-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/Katakana-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/NWP-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/NWP-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/README.txt +79 -0
- package/binary/_internal/pdfminer/cmap/RKSJ-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/RKSJ-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/Roman-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/Roman-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniCNS-UCS2-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniCNS-UCS2-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniCNS-UTF16-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniCNS-UTF16-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniCNS-UTF32-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniCNS-UTF32-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniCNS-UTF8-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniCNS-UTF8-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniGB-UCS2-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniGB-UCS2-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniGB-UTF16-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniGB-UTF16-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniGB-UTF32-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniGB-UTF32-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniGB-UTF8-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniGB-UTF8-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniJIS-UCS2-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniJIS-UCS2-HW-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniJIS-UCS2-HW-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniJIS-UCS2-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniJIS-UTF16-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniJIS-UTF16-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniJIS-UTF32-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniJIS-UTF32-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniJIS-UTF8-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniJIS-UTF8-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniJIS2004-UTF16-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniJIS2004-UTF16-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniJIS2004-UTF32-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniJIS2004-UTF32-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniJIS2004-UTF8-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniJIS2004-UTF8-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniJISX0213-UTF32-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniJISX0213-UTF32-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniJISX02132004-UTF32-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniJISX02132004-UTF32-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniKS-UCS2-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniKS-UCS2-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniKS-UTF16-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniKS-UTF16-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniKS-UTF32-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniKS-UTF32-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniKS-UTF8-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/UniKS-UTF8-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/WP-Symbol-H.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/WP-Symbol-V.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/to-unicode-Adobe-CNS1.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/to-unicode-Adobe-GB1.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/to-unicode-Adobe-Japan1.json.gz +0 -0
- package/binary/_internal/pdfminer/cmap/to-unicode-Adobe-Korea1.json.gz +0 -0
- package/binary/_internal/pdfminer/py.typed +0 -0
- package/binary/_internal/pdfminer_six-20260107.dist-info/INSTALLER +1 -0
- package/binary/_internal/pdfminer_six-20260107.dist-info/METADATA +110 -0
- package/binary/_internal/pdfminer_six-20260107.dist-info/RECORD +191 -0
- package/binary/_internal/pdfminer_six-20260107.dist-info/REQUESTED +0 -0
- package/binary/_internal/pdfminer_six-20260107.dist-info/WHEEL +5 -0
- package/binary/_internal/pdfminer_six-20260107.dist-info/licenses/LICENSE +22 -0
- package/binary/_internal/pdfminer_six-20260107.dist-info/top_level.txt +1 -0
- package/binary/_internal/pdfplumber-0.11.10.dist-info/INSTALLER +1 -0
- package/binary/_internal/pdfplumber-0.11.10.dist-info/METADATA +617 -0
- package/binary/_internal/pdfplumber-0.11.10.dist-info/RECORD +30 -0
- package/binary/_internal/pdfplumber-0.11.10.dist-info/REQUESTED +0 -0
- package/binary/_internal/pdfplumber-0.11.10.dist-info/WHEEL +5 -0
- package/binary/_internal/pdfplumber-0.11.10.dist-info/entry_points.txt +2 -0
- package/binary/_internal/pdfplumber-0.11.10.dist-info/licenses/LICENSE.txt +21 -0
- package/binary/_internal/pdfplumber-0.11.10.dist-info/top_level.txt +1 -0
- package/binary/_internal/pillow-12.3.0.dist-info/INSTALLER +1 -0
- package/binary/_internal/pillow-12.3.0.dist-info/METADATA +180 -0
- package/binary/_internal/pillow-12.3.0.dist-info/RECORD +141 -0
- package/binary/_internal/pillow-12.3.0.dist-info/REQUESTED +0 -0
- package/binary/_internal/pillow-12.3.0.dist-info/WHEEL +6 -0
- package/binary/_internal/pillow-12.3.0.dist-info/licenses/LICENSE +1574 -0
- package/binary/_internal/pillow-12.3.0.dist-info/sboms/pillow-12.3.0.cdx.json +721 -0
- package/binary/_internal/pillow-12.3.0.dist-info/top_level.txt +1 -0
- package/binary/_internal/pillow-12.3.0.dist-info/zip-safe +1 -0
- package/binary/_internal/pycparser-3.0.dist-info/INSTALLER +1 -0
- package/binary/_internal/pycparser-3.0.dist-info/METADATA +244 -0
- package/binary/_internal/pycparser-3.0.dist-info/RECORD +15 -0
- package/binary/_internal/pycparser-3.0.dist-info/REQUESTED +0 -0
- package/binary/_internal/pycparser-3.0.dist-info/WHEEL +5 -0
- package/binary/_internal/pycparser-3.0.dist-info/licenses/LICENSE +27 -0
- package/binary/_internal/pycparser-3.0.dist-info/top_level.txt +1 -0
- package/binary/_internal/pypdfium2/version.json +11 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/INSTALLER +1 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/METADATA +1139 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/RECORD +75 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/REQUESTED +0 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/WHEEL +5 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/entry_points.txt +2 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/licenses/LICENSES/Apache-2.0.txt +202 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/licenses/LICENSES/BSD-3-Clause.txt +26 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/licenses/LICENSES/CC-BY-4.0.txt +317 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/abseil.txt +203 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/agg23.txt +14 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/fast_float.txt +27 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/freetype.txt +169 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/icu.txt +568 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/lcms.txt +27 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/libjpeg_turbo.ijg +260 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/libjpeg_turbo.md +135 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/libopenjpeg.txt +32 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/libpng.txt +134 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/libtiff.txt +21 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/llvm-libc.txt +278 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/pdfium-binaries.txt +9 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/pdfium.txt +230 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/simdutf.txt +18 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/zlib.txt +29 -0
- package/binary/_internal/pypdfium2-5.13.0.dist-info/top_level.txt +4 -0
- package/binary/_internal/pypdfium2_raw/libpdfium.dylib +0 -0
- package/binary/_internal/pypdfium2_raw/version.json +10 -0
- package/binary/_internal/python_calamine/_python_calamine.cpython-312-darwin.so +0 -0
- package/binary/_internal/python_calamine-0.8.2.dist-info/INSTALLER +1 -0
- package/binary/_internal/python_calamine-0.8.2.dist-info/METADATA +94 -0
- package/binary/_internal/python_calamine-0.8.2.dist-info/RECORD +11 -0
- package/binary/_internal/python_calamine-0.8.2.dist-info/REQUESTED +0 -0
- package/binary/_internal/python_calamine-0.8.2.dist-info/WHEEL +4 -0
- package/binary/_internal/python_calamine-0.8.2.dist-info/licenses/LICENSE +21 -0
- package/binary/_internal/python_calamine-0.8.2.dist-info/sboms/python-calamine.cyclonedx.json +1652 -0
- package/binary/_internal/quickjs_ng-0.17.0.1.dist-info/INSTALLER +1 -0
- package/binary/_internal/quickjs_ng-0.17.0.1.dist-info/METADATA +161 -0
- package/binary/_internal/quickjs_ng-0.17.0.1.dist-info/RECORD +9 -0
- package/binary/_internal/quickjs_ng-0.17.0.1.dist-info/REQUESTED +0 -0
- package/binary/_internal/quickjs_ng-0.17.0.1.dist-info/WHEEL +6 -0
- package/binary/_internal/quickjs_ng-0.17.0.1.dist-info/licenses/LICENSE +21 -0
- package/binary/_internal/quickjs_ng-0.17.0.1.dist-info/top_level.txt +2 -0
- package/binary/_internal/selectolax/base.pxi +4 -0
- package/binary/_internal/selectolax/lexbor/attrs.pxi +123 -0
- package/binary/_internal/selectolax/lexbor/fragment_lookup.pxi +52 -0
- package/binary/_internal/selectolax/lexbor/node.pxi +1355 -0
- package/binary/_internal/selectolax/lexbor/node_remove.pxi +29 -0
- package/binary/_internal/selectolax/lexbor/selection.pxi +251 -0
- package/binary/_internal/selectolax/lexbor/util.pxi +114 -0
- package/binary/_internal/selectolax/lexbor.c +66981 -0
- package/binary/_internal/selectolax/lexbor.cpython-312-darwin.so +0 -0
- package/binary/_internal/selectolax/lexbor.pxd +682 -0
- package/binary/_internal/selectolax/lexbor.pyi +1534 -0
- package/binary/_internal/selectolax/lexbor.pyx +1046 -0
- package/binary/_internal/selectolax/modest/node.pxi +976 -0
- package/binary/_internal/selectolax/modest/selection.pxi +199 -0
- package/binary/_internal/selectolax/modest/util.pxi +20 -0
- package/binary/_internal/selectolax/py.typed +0 -0
- package/binary/_internal/selectolax/utils.pxi +117 -0
- package/binary/_internal/selectolax-0.4.13.dist-info/INSTALLER +1 -0
- package/binary/_internal/selectolax-0.4.13.dist-info/METADATA +222 -0
- package/binary/_internal/selectolax-0.4.13.dist-info/RECORD +30 -0
- package/binary/_internal/selectolax-0.4.13.dist-info/REQUESTED +0 -0
- package/binary/_internal/selectolax-0.4.13.dist-info/WHEEL +6 -0
- package/binary/_internal/selectolax-0.4.13.dist-info/licenses/LICENSE +10 -0
- package/binary/_internal/selectolax-0.4.13.dist-info/top_level.txt +1 -0
- package/binary/brewdoc +0 -0
- package/binary/licenses/installed/brewdoc/brewdoc/_vendor/THIRD_PARTY_NOTICES.txt +342 -0
- package/binary/licenses/installed/brewdoc/brewdoc-0.3.2.dist-info/licenses/LICENSE +21 -0
- package/binary/licenses/installed/cffi/cffi-2.1.1.dist-info/licenses/LICENSE +23 -0
- package/binary/licenses/installed/charset-normalizer/charset_normalizer-3.5.2.dist-info/licenses/LICENSE +21 -0
- package/binary/licenses/installed/cryptography/cryptography-50.0.2.dist-info/licenses/LICENSE +3 -0
- package/binary/licenses/installed/cryptography/cryptography-50.0.2.dist-info/licenses/LICENSE.APACHE +202 -0
- package/binary/licenses/installed/cryptography/cryptography-50.0.2.dist-info/licenses/LICENSE.BSD +27 -0
- package/binary/licenses/installed/interpreter/LICENSE.txt +279 -0
- package/binary/licenses/installed/pdfminer.six/pdfminer_six-20260107.dist-info/licenses/LICENSE +22 -0
- package/binary/licenses/installed/pdfplumber/pdfplumber-0.11.10.dist-info/licenses/LICENSE.txt +21 -0
- package/binary/licenses/installed/pillow/pillow-12.3.0.dist-info/licenses/LICENSE +1574 -0
- package/binary/licenses/installed/pycparser/pycparser-3.0.dist-info/licenses/LICENSE +27 -0
- package/binary/licenses/installed/pypdfium2/pypdfium2-5.13.0.dist-info/licenses/LICENSES/Apache-2.0.txt +202 -0
- package/binary/licenses/installed/pypdfium2/pypdfium2-5.13.0.dist-info/licenses/LICENSES/BSD-3-Clause.txt +26 -0
- package/binary/licenses/installed/pypdfium2/pypdfium2-5.13.0.dist-info/licenses/LICENSES/CC-BY-4.0.txt +317 -0
- package/binary/licenses/installed/pypdfium2/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/abseil.txt +203 -0
- package/binary/licenses/installed/pypdfium2/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/agg23.txt +14 -0
- package/binary/licenses/installed/pypdfium2/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/fast_float.txt +27 -0
- package/binary/licenses/installed/pypdfium2/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/freetype.txt +169 -0
- package/binary/licenses/installed/pypdfium2/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/icu.txt +568 -0
- package/binary/licenses/installed/pypdfium2/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/lcms.txt +27 -0
- package/binary/licenses/installed/pypdfium2/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/libjpeg_turbo.ijg +260 -0
- package/binary/licenses/installed/pypdfium2/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/libjpeg_turbo.md +135 -0
- package/binary/licenses/installed/pypdfium2/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/libopenjpeg.txt +32 -0
- package/binary/licenses/installed/pypdfium2/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/libpng.txt +134 -0
- package/binary/licenses/installed/pypdfium2/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/libtiff.txt +21 -0
- package/binary/licenses/installed/pypdfium2/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/llvm-libc.txt +278 -0
- package/binary/licenses/installed/pypdfium2/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/pdfium-binaries.txt +9 -0
- package/binary/licenses/installed/pypdfium2/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/pdfium.txt +230 -0
- package/binary/licenses/installed/pypdfium2/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/simdutf.txt +18 -0
- package/binary/licenses/installed/pypdfium2/pypdfium2-5.13.0.dist-info/licenses/data/darwin_arm64/BUILD_LICENSES/zlib.txt +29 -0
- package/binary/licenses/installed/python-calamine/python_calamine-0.8.2.dist-info/licenses/LICENSE +21 -0
- package/binary/licenses/installed/quickjs-ng/quickjs_ng-0.17.0.1.dist-info/licenses/LICENSE +21 -0
- package/binary/licenses/installed/runtime-hooks/pyi_rth_cryptography_openssl.py +20 -0
- package/binary/licenses/installed/runtime-hooks/pyi_rth_inspect.py +99 -0
- package/binary/licenses/installed/runtime-hooks/pyi_rth_multiprocessing.py +88 -0
- package/binary/licenses/installed/runtime-hooks/pyi_rth_pkgutil.py +64 -0
- package/binary/licenses/installed/selectolax/selectolax-0.4.13.dist-info/licenses/LICENSE +10 -0
- package/binary/licenses/installed-manifest.json +192 -0
- package/binary/licenses/supplemental/openssl/3.5.9/README-copyright.txt +9 -0
- package/binary/licenses/supplemental/openssl/4.0.3/README-copyright.txt +9 -0
- package/binary/licenses/supplemental/provenance.json +2347 -0
- package/binary/licenses/supplemental/pyinstaller-6.22.3/COPYING.txt +648 -0
- package/binary/licenses/supplemental/pyinstaller-6.22.3/bootloader/waflib/LICENSE +25 -0
- package/binary/licenses/supplemental/pyinstaller-6.22.3/bootloader/zlib/LICENSE +22 -0
- package/binary/licenses/supplemental/pyinstaller-6.22.3/doc/license.rst +24 -0
- package/binary/licenses/supplemental/pyinstaller-hooks-contrib-2026.8/LICENSE +521 -0
- package/binary/licenses/supplemental/python-build-standalone-20260929/LICENSE +373 -0
- package/binary/licenses/supplemental/python-build-standalone-20260929/LICENSE.bdb.txt +126 -0
- package/binary/licenses/supplemental/python-build-standalone-20260929/LICENSE.bzip2.txt +37 -0
- package/binary/licenses/supplemental/python-build-standalone-20260929/LICENSE.cpython.txt +771 -0
- package/binary/licenses/supplemental/python-build-standalone-20260929/LICENSE.expat.txt +21 -0
- package/binary/licenses/supplemental/python-build-standalone-20260929/LICENSE.libX11.txt +942 -0
- package/binary/licenses/supplemental/python-build-standalone-20260929/LICENSE.libXau.txt +21 -0
- package/binary/licenses/supplemental/python-build-standalone-20260929/LICENSE.libedit.txt +29 -0
- package/binary/licenses/supplemental/python-build-standalone-20260929/LICENSE.libffi.txt +21 -0
- package/binary/licenses/supplemental/python-build-standalone-20260929/LICENSE.liblzma.txt +13 -0
- package/binary/licenses/supplemental/python-build-standalone-20260929/LICENSE.libuuid.txt +27 -0
- package/binary/licenses/supplemental/python-build-standalone-20260929/LICENSE.libxcb.txt +30 -0
- package/binary/licenses/supplemental/python-build-standalone-20260929/LICENSE.mpdecimal.txt +24 -0
- package/binary/licenses/supplemental/python-build-standalone-20260929/LICENSE.ncurses.txt +29 -0
- package/binary/licenses/supplemental/python-build-standalone-20260929/LICENSE.openssl-1.1.txt +124 -0
- package/binary/licenses/supplemental/python-build-standalone-20260929/LICENSE.openssl-3.txt +177 -0
- package/binary/licenses/supplemental/python-build-standalone-20260929/LICENSE.sqlite.txt +23 -0
- package/binary/licenses/supplemental/python-build-standalone-20260929/LICENSE.tcl.txt +40 -0
- package/binary/licenses/supplemental/python-build-standalone-20260929/LICENSE.tix.txt +54 -0
- package/binary/licenses/supplemental/python-build-standalone-20260929/LICENSE.zlib.txt +21 -0
- package/binary/licenses/supplemental/python-calamine-0.8.2/LICENSE +21 -0
- package/binary/licenses/supplemental/python-calamine-0.8.2/source-identity/Cargo.lock +620 -0
- package/binary/licenses/supplemental/python-calamine-0.8.2/source-identity/Cargo.toml +22 -0
- package/binary/licenses/supplemental/quickjs-ng-0.17.0.1/LICENSE +21 -0
- package/binary/licenses/supplemental/quickjs-ng-0.17.0.1/engine-headers/upstream-quickjs/cutils.h.txt +24 -0
- package/binary/licenses/supplemental/quickjs-ng-0.17.0.1/engine-headers/upstream-quickjs/dtoa.c.txt +23 -0
- package/binary/licenses/supplemental/quickjs-ng-0.17.0.1/engine-headers/upstream-quickjs/dtoa.h.txt +23 -0
- package/binary/licenses/supplemental/quickjs-ng-0.17.0.1/engine-headers/upstream-quickjs/libregexp-opcode.h.txt +23 -0
- package/binary/licenses/supplemental/quickjs-ng-0.17.0.1/engine-headers/upstream-quickjs/libregexp.c.txt +23 -0
- package/binary/licenses/supplemental/quickjs-ng-0.17.0.1/engine-headers/upstream-quickjs/libregexp.h.txt +23 -0
- package/binary/licenses/supplemental/quickjs-ng-0.17.0.1/engine-headers/upstream-quickjs/libunicode.c.txt +23 -0
- package/binary/licenses/supplemental/quickjs-ng-0.17.0.1/engine-headers/upstream-quickjs/libunicode.h.txt +23 -0
- package/binary/licenses/supplemental/quickjs-ng-0.17.0.1/engine-headers/upstream-quickjs/list.h.txt +23 -0
- package/binary/licenses/supplemental/quickjs-ng-0.17.0.1/engine-headers/upstream-quickjs/quickjs-atom.h.txt +24 -0
- package/binary/licenses/supplemental/quickjs-ng-0.17.0.1/engine-headers/upstream-quickjs/quickjs-opcode.h.txt +24 -0
- package/binary/licenses/supplemental/quickjs-ng-0.17.0.1/engine-headers/upstream-quickjs/quickjs.c.txt +26 -0
- package/binary/licenses/supplemental/quickjs-ng-0.17.0.1/engine-headers/upstream-quickjs/quickjs.h.txt +26 -0
- package/binary/licenses/supplemental/rust-adler2-2.0.1/LICENSE-0BSD +12 -0
- package/binary/licenses/supplemental/rust-adler2-2.0.1/LICENSE-APACHE +201 -0
- package/binary/licenses/supplemental/rust-adler2-2.0.1/LICENSE-MIT +23 -0
- package/binary/licenses/supplemental/rust-android_system_properties-0.1.5/LICENSE-APACHE +13 -0
- package/binary/licenses/supplemental/rust-android_system_properties-0.1.5/LICENSE-MIT +20 -0
- package/binary/licenses/supplemental/rust-atoi_simd-0.18.1/LICENSE-APACHE +201 -0
- package/binary/licenses/supplemental/rust-atoi_simd-0.18.1/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-autocfg-1.5.1/LICENSE-APACHE +201 -0
- package/binary/licenses/supplemental/rust-autocfg-1.5.1/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-bumpalo-3.20.3/LICENSE-APACHE +201 -0
- package/binary/licenses/supplemental/rust-bumpalo-3.20.3/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-byteorder-1.5.0/COPYING +3 -0
- package/binary/licenses/supplemental/rust-byteorder-1.5.0/LICENSE-MIT +21 -0
- package/binary/licenses/supplemental/rust-calamine-0.36.0/LICENSE-MIT.md +23 -0
- package/binary/licenses/supplemental/rust-cc-1.2.64/LICENSE-APACHE +201 -0
- package/binary/licenses/supplemental/rust-cc-1.2.64/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-cfg-if-1.0.4/LICENSE-APACHE +201 -0
- package/binary/licenses/supplemental/rust-cfg-if-1.0.4/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-chrono-0.4.45/LICENSE.txt +240 -0
- package/binary/licenses/supplemental/rust-codepage-0.1.2/COPYRIGHT +9 -0
- package/binary/licenses/supplemental/rust-codepage-0.1.2/LICENSE-APACHE +202 -0
- package/binary/licenses/supplemental/rust-codepage-0.1.2/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-core-foundation-sys-0.8.7/LICENSE-APACHE +201 -0
- package/binary/licenses/supplemental/rust-core-foundation-sys-0.8.7/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-crc32fast-1.5.0/LICENSE-APACHE +202 -0
- package/binary/licenses/supplemental/rust-crc32fast-1.5.0/LICENSE-MIT +21 -0
- package/binary/licenses/supplemental/rust-debug_unsafe-0.1.4/LICENSE-APACHE +201 -0
- package/binary/licenses/supplemental/rust-debug_unsafe-0.1.4/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-encoding_rs-0.8.35/COPYRIGHT +17 -0
- package/binary/licenses/supplemental/rust-encoding_rs-0.8.35/LICENSE-APACHE +202 -0
- package/binary/licenses/supplemental/rust-encoding_rs-0.8.35/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-encoding_rs-0.8.35/LICENSE-WHATWG +26 -0
- package/binary/licenses/supplemental/rust-equivalent-1.0.2/LICENSE-APACHE +201 -0
- package/binary/licenses/supplemental/rust-equivalent-1.0.2/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-fast-float2-0.2.3/LICENSE-APACHE +201 -0
- package/binary/licenses/supplemental/rust-fast-float2-0.2.3/LICENSE-MIT +23 -0
- package/binary/licenses/supplemental/rust-find-msvc-tools-0.1.9/LICENSE-APACHE +201 -0
- package/binary/licenses/supplemental/rust-find-msvc-tools-0.1.9/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-flate2-1.1.9/LICENSE-APACHE +201 -0
- package/binary/licenses/supplemental/rust-flate2-1.1.9/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-futures-core-0.3.32/LICENSE-APACHE +202 -0
- package/binary/licenses/supplemental/rust-futures-core-0.3.32/LICENSE-MIT +26 -0
- package/binary/licenses/supplemental/rust-futures-task-0.3.32/LICENSE-APACHE +202 -0
- package/binary/licenses/supplemental/rust-futures-task-0.3.32/LICENSE-MIT +26 -0
- package/binary/licenses/supplemental/rust-futures-util-0.3.32/LICENSE-APACHE +202 -0
- package/binary/licenses/supplemental/rust-futures-util-0.3.32/LICENSE-MIT +26 -0
- package/binary/licenses/supplemental/rust-hashbrown-0.17.1/LICENSE-APACHE +201 -0
- package/binary/licenses/supplemental/rust-hashbrown-0.17.1/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-heck-0.5.0/LICENSE-APACHE +201 -0
- package/binary/licenses/supplemental/rust-heck-0.5.0/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-iana-time-zone-0.1.65/LICENSE-APACHE +201 -0
- package/binary/licenses/supplemental/rust-iana-time-zone-0.1.65/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-iana-time-zone-haiku-0.1.2/LICENSE-APACHE +201 -0
- package/binary/licenses/supplemental/rust-iana-time-zone-haiku-0.1.2/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-indexmap-2.14.0/LICENSE-APACHE +201 -0
- package/binary/licenses/supplemental/rust-indexmap-2.14.0/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-js-sys-0.3.102/LICENSE-APACHE +201 -0
- package/binary/licenses/supplemental/rust-js-sys-0.3.102/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-libc-0.2.186/LICENSE-APACHE +176 -0
- package/binary/licenses/supplemental/rust-libc-0.2.186/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-log-0.4.32/LICENSE-APACHE +201 -0
- package/binary/licenses/supplemental/rust-log-0.4.32/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-memchr-2.8.2/COPYING +3 -0
- package/binary/licenses/supplemental/rust-memchr-2.8.2/LICENSE-MIT +21 -0
- package/binary/licenses/supplemental/rust-miniz_oxide-0.8.9/LICENSE +25 -0
- package/binary/licenses/supplemental/rust-miniz_oxide-0.8.9/LICENSE-APACHE.md +177 -0
- package/binary/licenses/supplemental/rust-miniz_oxide-0.8.9/LICENSE-MIT.md +24 -0
- package/binary/licenses/supplemental/rust-miniz_oxide-0.8.9/LICENSE-ZLIB.md +14 -0
- package/binary/licenses/supplemental/rust-num-traits-0.2.19/LICENSE-APACHE +201 -0
- package/binary/licenses/supplemental/rust-num-traits-0.2.19/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-once_cell-1.21.4/LICENSE-APACHE +201 -0
- package/binary/licenses/supplemental/rust-once_cell-1.21.4/LICENSE-MIT +23 -0
- package/binary/licenses/supplemental/rust-pin-project-lite-0.2.17/LICENSE-APACHE +177 -0
- package/binary/licenses/supplemental/rust-pin-project-lite-0.2.17/LICENSE-MIT +23 -0
- package/binary/licenses/supplemental/rust-portable-atomic-1.13.1/LICENSE-APACHE +177 -0
- package/binary/licenses/supplemental/rust-portable-atomic-1.13.1/LICENSE-MIT +23 -0
- package/binary/licenses/supplemental/rust-proc-macro2-1.0.106/LICENSE-APACHE +176 -0
- package/binary/licenses/supplemental/rust-proc-macro2-1.0.106/LICENSE-MIT +23 -0
- package/binary/licenses/supplemental/rust-pyo3-0.29.0/LICENSE-APACHE +178 -0
- package/binary/licenses/supplemental/rust-pyo3-0.29.0/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-pyo3-0.29.0/pyo3-runtime/LICENSE-APACHE +178 -0
- package/binary/licenses/supplemental/rust-pyo3-0.29.0/pyo3-runtime/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-pyo3-build-config-0.29.0/LICENSE-APACHE +178 -0
- package/binary/licenses/supplemental/rust-pyo3-build-config-0.29.0/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-pyo3-ffi-0.29.0/LICENSE-APACHE +178 -0
- package/binary/licenses/supplemental/rust-pyo3-ffi-0.29.0/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-pyo3-file-0.16.0/Cargo.toml +14 -0
- package/binary/licenses/supplemental/rust-pyo3-file-0.16.0/README.md +90 -0
- package/binary/licenses/supplemental/rust-pyo3-file-0.16.0/declared-license/Apache-2.0.txt +73 -0
- package/binary/licenses/supplemental/rust-pyo3-macros-0.29.0/LICENSE-APACHE +178 -0
- package/binary/licenses/supplemental/rust-pyo3-macros-0.29.0/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-pyo3-macros-backend-0.29.0/LICENSE-APACHE +178 -0
- package/binary/licenses/supplemental/rust-pyo3-macros-backend-0.29.0/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-quick-xml-0.41.0/LICENSE-MIT.md +23 -0
- package/binary/licenses/supplemental/rust-quote-1.0.45/LICENSE-APACHE +176 -0
- package/binary/licenses/supplemental/rust-quote-1.0.45/LICENSE-MIT +23 -0
- package/binary/licenses/supplemental/rust-rustversion-1.0.22/LICENSE-APACHE +176 -0
- package/binary/licenses/supplemental/rust-rustversion-1.0.22/LICENSE-MIT +23 -0
- package/binary/licenses/supplemental/rust-serde-1.0.228/LICENSE-APACHE +176 -0
- package/binary/licenses/supplemental/rust-serde-1.0.228/LICENSE-MIT +23 -0
- package/binary/licenses/supplemental/rust-serde_core-1.0.228/LICENSE-APACHE +176 -0
- package/binary/licenses/supplemental/rust-serde_core-1.0.228/LICENSE-MIT +23 -0
- package/binary/licenses/supplemental/rust-serde_derive-1.0.228/LICENSE-APACHE +176 -0
- package/binary/licenses/supplemental/rust-serde_derive-1.0.228/LICENSE-MIT +23 -0
- package/binary/licenses/supplemental/rust-shlex-2.0.1/LICENSE-APACHE +13 -0
- package/binary/licenses/supplemental/rust-shlex-2.0.1/LICENSE-MIT +21 -0
- package/binary/licenses/supplemental/rust-simd-adler32-0.3.9/LICENSE.md +21 -0
- package/binary/licenses/supplemental/rust-slab-0.4.12/LICENSE +25 -0
- package/binary/licenses/supplemental/rust-syn-2.0.118/LICENSE-APACHE +176 -0
- package/binary/licenses/supplemental/rust-syn-2.0.118/LICENSE-MIT +23 -0
- package/binary/licenses/supplemental/rust-target-lexicon-0.13.5/LICENSE +220 -0
- package/binary/licenses/supplemental/rust-typed-path-0.12.3/LICENSE-APACHE +176 -0
- package/binary/licenses/supplemental/rust-typed-path-0.12.3/LICENSE-MIT +23 -0
- package/binary/licenses/supplemental/rust-unicode-ident-1.0.24/LICENSE-APACHE +176 -0
- package/binary/licenses/supplemental/rust-unicode-ident-1.0.24/LICENSE-MIT +23 -0
- package/binary/licenses/supplemental/rust-unicode-ident-1.0.24/LICENSE-UNICODE +39 -0
- package/binary/licenses/supplemental/rust-wasm-bindgen-0.2.125/LICENSE-APACHE +201 -0
- package/binary/licenses/supplemental/rust-wasm-bindgen-0.2.125/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-wasm-bindgen-macro-0.2.125/LICENSE-APACHE +201 -0
- package/binary/licenses/supplemental/rust-wasm-bindgen-macro-0.2.125/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-wasm-bindgen-macro-support-0.2.125/LICENSE-APACHE +201 -0
- package/binary/licenses/supplemental/rust-wasm-bindgen-macro-support-0.2.125/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-wasm-bindgen-shared-0.2.125/LICENSE-APACHE +201 -0
- package/binary/licenses/supplemental/rust-wasm-bindgen-shared-0.2.125/LICENSE-MIT +25 -0
- package/binary/licenses/supplemental/rust-windows-core-0.62.2/license-apache-2.0 +201 -0
- package/binary/licenses/supplemental/rust-windows-core-0.62.2/license-mit +21 -0
- package/binary/licenses/supplemental/rust-windows-implement-0.60.2/license-apache-2.0 +201 -0
- package/binary/licenses/supplemental/rust-windows-implement-0.60.2/license-mit +21 -0
- package/binary/licenses/supplemental/rust-windows-interface-0.59.3/license-apache-2.0 +201 -0
- package/binary/licenses/supplemental/rust-windows-interface-0.59.3/license-mit +21 -0
- package/binary/licenses/supplemental/rust-windows-link-0.2.1/license-apache-2.0 +201 -0
- package/binary/licenses/supplemental/rust-windows-link-0.2.1/license-mit +21 -0
- package/binary/licenses/supplemental/rust-windows-result-0.4.1/license-apache-2.0 +201 -0
- package/binary/licenses/supplemental/rust-windows-result-0.4.1/license-mit +21 -0
- package/binary/licenses/supplemental/rust-windows-strings-0.5.1/license-apache-2.0 +201 -0
- package/binary/licenses/supplemental/rust-windows-strings-0.5.1/license-mit +21 -0
- package/binary/licenses/supplemental/rust-zip-8.6.0/LICENSE +21 -0
- package/binary/licenses/supplemental/rust-zlib-rs-0.6.3/LICENSE +19 -0
- package/binary/licenses/supplemental/rust-zopfli-0.8.3/COPYING +201 -0
- package/binary/licenses/supplemental/selectolax-0.4.13/LICENSE +10 -0
- package/binary/licenses/supplemental/selectolax-0.4.13/lexbor/LICENSE +223 -0
- package/binary/licenses/supplemental/selectolax-0.4.13/lexbor/NOTICE +16 -0
- package/binary/version.json +6 -0
- package/native-manifest.json +4364 -0
- package/native-verification.json +338 -0
- package/package.json +24 -4
|
@@ -0,0 +1,1355 @@
|
|
|
1
|
+
cimport cython
|
|
2
|
+
from cpython.exc cimport PyErr_SetNone
|
|
3
|
+
|
|
4
|
+
import logging
|
|
5
|
+
|
|
6
|
+
logger = logging.getLogger("selectolax")
|
|
7
|
+
|
|
8
|
+
_TAG_TO_NAME = {
|
|
9
|
+
0x0005: "-doctype",
|
|
10
|
+
0x0002: "-text",
|
|
11
|
+
0x0004: "-comment",
|
|
12
|
+
}
|
|
13
|
+
ctypedef fused str_or_LexborNode:
|
|
14
|
+
str
|
|
15
|
+
bytes
|
|
16
|
+
LexborNode
|
|
17
|
+
|
|
18
|
+
ctypedef fused str_or_bytes:
|
|
19
|
+
str
|
|
20
|
+
bytes
|
|
21
|
+
|
|
22
|
+
cdef inline bytes to_bytes(str_or_LexborNode value):
|
|
23
|
+
cdef bytes bytes_val
|
|
24
|
+
if isinstance(value, unicode):
|
|
25
|
+
bytes_val = <bytes> value.encode("utf-8")
|
|
26
|
+
elif isinstance(value, bytes):
|
|
27
|
+
bytes_val = <bytes> value
|
|
28
|
+
return bytes_val
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@cython.final
|
|
32
|
+
cdef class LexborNode:
|
|
33
|
+
"""A class that represents HTML node (element)."""
|
|
34
|
+
|
|
35
|
+
cdef void set_as_fragment_root(self):
|
|
36
|
+
self._is_fragment_root = 1
|
|
37
|
+
|
|
38
|
+
@staticmethod
|
|
39
|
+
cdef LexborNode new(lxb_dom_node_t *node, LexborHTMLParser parser):
|
|
40
|
+
cdef LexborNode lxbnode = LexborNode.__new__(LexborNode)
|
|
41
|
+
lxbnode.node = node
|
|
42
|
+
lxbnode.parser = parser
|
|
43
|
+
lxbnode._is_fragment_root = 0
|
|
44
|
+
return lxbnode
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def mem_id(self):
|
|
48
|
+
return <size_t> self.node
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def child(self):
|
|
52
|
+
"""Alias for the `first_child` property.
|
|
53
|
+
|
|
54
|
+
**Deprecated**. Please use `first_child` instead.
|
|
55
|
+
"""
|
|
56
|
+
return self.first_child
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def first_child(self):
|
|
60
|
+
"""Return the first child node."""
|
|
61
|
+
cdef LexborNode node
|
|
62
|
+
if self.node.first_child:
|
|
63
|
+
node = LexborNode.new(<lxb_dom_node_t *> self.node.first_child, self.parser)
|
|
64
|
+
return node
|
|
65
|
+
return None
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def parent(self):
|
|
69
|
+
"""Return the parent node."""
|
|
70
|
+
cdef LexborNode node
|
|
71
|
+
if self.node.parent != NULL:
|
|
72
|
+
node = LexborNode.new(<lxb_dom_node_t *> self.node.parent, self.parser)
|
|
73
|
+
return node
|
|
74
|
+
return None
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def next(self):
|
|
78
|
+
"""Return next node."""
|
|
79
|
+
cdef LexborNode node
|
|
80
|
+
if self.node.next != NULL:
|
|
81
|
+
node = LexborNode.new(<lxb_dom_node_t *> self.node.next, self.parser)
|
|
82
|
+
return node
|
|
83
|
+
return None
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def prev(self):
|
|
87
|
+
"""Return previous node."""
|
|
88
|
+
cdef LexborNode node
|
|
89
|
+
if self.node.prev != NULL:
|
|
90
|
+
node = LexborNode.new(<lxb_dom_node_t *> self.node.prev, self.parser)
|
|
91
|
+
return node
|
|
92
|
+
return None
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def last_child(self):
|
|
96
|
+
"""Return last child node."""
|
|
97
|
+
cdef LexborNode node
|
|
98
|
+
if self.node.last_child != NULL:
|
|
99
|
+
node = LexborNode.new(<lxb_dom_node_t *> self.node.last_child, self.parser)
|
|
100
|
+
return node
|
|
101
|
+
return None
|
|
102
|
+
|
|
103
|
+
@property
|
|
104
|
+
def html(self):
|
|
105
|
+
"""Return HTML representation of the current node including all its child nodes.
|
|
106
|
+
|
|
107
|
+
Returns
|
|
108
|
+
-------
|
|
109
|
+
text : str
|
|
110
|
+
"""
|
|
111
|
+
cdef lexbor_str_t *lxb_str
|
|
112
|
+
cdef lxb_status_t status
|
|
113
|
+
lxb_str = lexbor_str_create()
|
|
114
|
+
if self._is_fragment_root:
|
|
115
|
+
status = serialize_fragment(self.node, lxb_str)
|
|
116
|
+
# status = lxb_html_serialize_tree_str(self.node, lxb_str)
|
|
117
|
+
else:
|
|
118
|
+
status = lxb_html_serialize_tree_str(self.node, lxb_str)
|
|
119
|
+
if status == 0:
|
|
120
|
+
html = lxb_str.data.decode(_ENCODING).replace('<-undef>', '')
|
|
121
|
+
lexbor_str_destroy(lxb_str, self.node.owner_document.text, True)
|
|
122
|
+
return html
|
|
123
|
+
lexbor_str_destroy(lxb_str, self.node.owner_document.text, True)
|
|
124
|
+
return None
|
|
125
|
+
|
|
126
|
+
cdef inline str _serialize_html(self, lxb_html_serialize_opt_t options, size_t indent, bint pretty):
|
|
127
|
+
cdef lexbor_str_t *lxb_str
|
|
128
|
+
cdef lxb_status_t status
|
|
129
|
+
|
|
130
|
+
lxb_str = lexbor_str_create()
|
|
131
|
+
if self._is_fragment_root:
|
|
132
|
+
if pretty:
|
|
133
|
+
status = serialize_fragment_pretty(self.node, lxb_str, options, indent)
|
|
134
|
+
else:
|
|
135
|
+
status = serialize_fragment(self.node, lxb_str)
|
|
136
|
+
else:
|
|
137
|
+
if pretty:
|
|
138
|
+
status = lxb_html_serialize_pretty_tree_str(self.node, options, indent, lxb_str)
|
|
139
|
+
else:
|
|
140
|
+
status = lxb_html_serialize_tree_str(self.node, lxb_str)
|
|
141
|
+
|
|
142
|
+
if status == 0:
|
|
143
|
+
html = lxb_str.data.decode(_ENCODING).replace('<-undef>', '')
|
|
144
|
+
lexbor_str_destroy(lxb_str, self.node.owner_document.text, True)
|
|
145
|
+
return html
|
|
146
|
+
lexbor_str_destroy(lxb_str, self.node.owner_document.text, True)
|
|
147
|
+
return None
|
|
148
|
+
|
|
149
|
+
cdef inline str _serialize_inner_html(self, lxb_html_serialize_opt_t options, size_t indent, bint pretty):
|
|
150
|
+
cdef lexbor_str_t *lxb_str
|
|
151
|
+
cdef lxb_status_t status
|
|
152
|
+
|
|
153
|
+
lxb_str = lexbor_str_create()
|
|
154
|
+
if pretty:
|
|
155
|
+
status = lxb_html_serialize_pretty_deep_str(self.node, options, indent, lxb_str)
|
|
156
|
+
else:
|
|
157
|
+
status = lxb_html_serialize_deep_str(self.node, lxb_str)
|
|
158
|
+
|
|
159
|
+
if status == 0 and lxb_str.data:
|
|
160
|
+
html = lxb_str.data.decode(_ENCODING).replace('<-undef>', '')
|
|
161
|
+
lexbor_str_destroy(lxb_str, self.node.owner_document.text, True)
|
|
162
|
+
return html
|
|
163
|
+
lexbor_str_destroy(lxb_str, self.node.owner_document.text, True)
|
|
164
|
+
return None
|
|
165
|
+
|
|
166
|
+
def html_pretty(
|
|
167
|
+
self,
|
|
168
|
+
Py_ssize_t indent=0,
|
|
169
|
+
bint skip_ws_nodes=False,
|
|
170
|
+
bint skip_comment=False,
|
|
171
|
+
bint raw=False,
|
|
172
|
+
bint without_closing=False,
|
|
173
|
+
bint tag_with_ns=False,
|
|
174
|
+
bint without_text_indent=False,
|
|
175
|
+
bint full_doctype=False,
|
|
176
|
+
bint html5test=False,
|
|
177
|
+
):
|
|
178
|
+
"""Return pretty-printed HTML for the current node.
|
|
179
|
+
|
|
180
|
+
Parameters
|
|
181
|
+
----------
|
|
182
|
+
indent : int, optional
|
|
183
|
+
Initial indentation level passed to Lexbor. Defaults to ``0``.
|
|
184
|
+
skip_ws_nodes : bool, optional
|
|
185
|
+
Skip text nodes that contain only whitespace.
|
|
186
|
+
skip_comment : bool, optional
|
|
187
|
+
Exclude HTML comment nodes from the serialized output.
|
|
188
|
+
raw : bool, optional
|
|
189
|
+
Serialize text and attribute values without HTML escaping.
|
|
190
|
+
without_closing : bool, optional
|
|
191
|
+
Omit closing tags for non-void elements.
|
|
192
|
+
tag_with_ns : bool, optional
|
|
193
|
+
Include namespace prefixes in serialized tag names when available.
|
|
194
|
+
without_text_indent : bool, optional
|
|
195
|
+
Disable extra indentation added around text and comment content.
|
|
196
|
+
full_doctype : bool, optional
|
|
197
|
+
Serialize the full document type declaration when a doctype node is present.
|
|
198
|
+
html5test : bool, optional
|
|
199
|
+
Serialize using Lexbor's HTML5 test formatting mode.
|
|
200
|
+
"""
|
|
201
|
+
cdef lxb_html_serialize_opt_t options
|
|
202
|
+
if indent < 0:
|
|
203
|
+
raise ValueError("indent must be greater than or equal to 0")
|
|
204
|
+
options = _html_pretty_options(
|
|
205
|
+
skip_ws_nodes,
|
|
206
|
+
skip_comment,
|
|
207
|
+
raw,
|
|
208
|
+
without_closing,
|
|
209
|
+
tag_with_ns,
|
|
210
|
+
without_text_indent,
|
|
211
|
+
full_doctype,
|
|
212
|
+
html5test,
|
|
213
|
+
)
|
|
214
|
+
return self._serialize_html(options, <size_t> indent, True)
|
|
215
|
+
|
|
216
|
+
def inner_html_pretty(
|
|
217
|
+
self,
|
|
218
|
+
Py_ssize_t indent=0,
|
|
219
|
+
bint skip_ws_nodes=False,
|
|
220
|
+
bint skip_comment=False,
|
|
221
|
+
bint raw=False,
|
|
222
|
+
bint without_closing=False,
|
|
223
|
+
bint tag_with_ns=False,
|
|
224
|
+
bint without_text_indent=False,
|
|
225
|
+
bint full_doctype=False,
|
|
226
|
+
bint html5test=False,
|
|
227
|
+
):
|
|
228
|
+
"""Return pretty-printed HTML representation of the child nodes.
|
|
229
|
+
|
|
230
|
+
Parameters
|
|
231
|
+
----------
|
|
232
|
+
indent : int, optional
|
|
233
|
+
Initial indentation level passed to Lexbor. Defaults to ``0``.
|
|
234
|
+
skip_ws_nodes : bool, optional
|
|
235
|
+
Skip text nodes that contain only whitespace.
|
|
236
|
+
skip_comment : bool, optional
|
|
237
|
+
Exclude HTML comment nodes from the serialized output.
|
|
238
|
+
raw : bool, optional
|
|
239
|
+
Serialize text and attribute values without HTML escaping.
|
|
240
|
+
without_closing : bool, optional
|
|
241
|
+
Omit closing tags for non-void elements.
|
|
242
|
+
tag_with_ns : bool, optional
|
|
243
|
+
Include namespace prefixes in serialized tag names when available.
|
|
244
|
+
without_text_indent : bool, optional
|
|
245
|
+
Disable extra indentation added around text and comment content.
|
|
246
|
+
full_doctype : bool, optional
|
|
247
|
+
Serialize the full document type declaration when a doctype node is present.
|
|
248
|
+
html5test : bool, optional
|
|
249
|
+
Serialize using Lexbor's HTML5 test formatting mode.
|
|
250
|
+
"""
|
|
251
|
+
cdef lxb_html_serialize_opt_t options
|
|
252
|
+
if indent < 0:
|
|
253
|
+
raise ValueError("indent must be greater than or equal to 0")
|
|
254
|
+
options = _html_pretty_options(
|
|
255
|
+
skip_ws_nodes,
|
|
256
|
+
skip_comment,
|
|
257
|
+
raw,
|
|
258
|
+
without_closing,
|
|
259
|
+
tag_with_ns,
|
|
260
|
+
without_text_indent,
|
|
261
|
+
full_doctype,
|
|
262
|
+
html5test,
|
|
263
|
+
)
|
|
264
|
+
return self._serialize_inner_html(options, <size_t> indent, True)
|
|
265
|
+
|
|
266
|
+
def __hash__(self):
|
|
267
|
+
return self.mem_id
|
|
268
|
+
|
|
269
|
+
def text_lexbor(self):
|
|
270
|
+
"""Returns the text of the node including text of all its child nodes.
|
|
271
|
+
|
|
272
|
+
Uses builtin method from lexbor.
|
|
273
|
+
"""
|
|
274
|
+
|
|
275
|
+
cdef size_t str_len = 0
|
|
276
|
+
cdef lxb_char_t * text
|
|
277
|
+
text = lxb_dom_node_text_content(self.node, &str_len)
|
|
278
|
+
if text == NULL or <int> str_len == 0:
|
|
279
|
+
return ""
|
|
280
|
+
|
|
281
|
+
unicode_text = text.decode(_ENCODING)
|
|
282
|
+
return unicode_text
|
|
283
|
+
|
|
284
|
+
def text(self, bool deep=True, str separator='', bool strip=False, bool skip_empty=False):
|
|
285
|
+
"""Return concatenated text from this node.
|
|
286
|
+
|
|
287
|
+
Parameters
|
|
288
|
+
----------
|
|
289
|
+
deep : bool, optional
|
|
290
|
+
When ``True`` (default), include text from all descendant nodes; when
|
|
291
|
+
``False``, only include direct children.
|
|
292
|
+
separator : str, optional
|
|
293
|
+
String inserted between successive text fragments.
|
|
294
|
+
strip : bool, optional
|
|
295
|
+
If ``True``, apply ``str.strip()`` to each fragment before joining to
|
|
296
|
+
remove surrounding whitespace. Defaults to ``False``.
|
|
297
|
+
skip_empty : bool, optional
|
|
298
|
+
Exclude text nodes whose content is only ASCII whitespace (space,
|
|
299
|
+
tab, newline, form feed or carriage return) when ``True``.
|
|
300
|
+
Defaults to ``False``.
|
|
301
|
+
|
|
302
|
+
Returns
|
|
303
|
+
-------
|
|
304
|
+
text : str
|
|
305
|
+
Combined textual content assembled according to the provided options.
|
|
306
|
+
|
|
307
|
+
"""
|
|
308
|
+
cdef unsigned char * text
|
|
309
|
+
cdef LexborNode start_node = self._get_node()
|
|
310
|
+
cdef lxb_dom_node_t * node = <lxb_dom_node_t *> start_node.node.first_child
|
|
311
|
+
|
|
312
|
+
if not deep:
|
|
313
|
+
container = TextContainer(separator, strip)
|
|
314
|
+
if _is_node_type(self.node, LXB_DOM_NODE_TYPE_TEXT):
|
|
315
|
+
text = <unsigned char *> lexbor_str_data_noi(&(<lxb_dom_character_data_t *> self.node).data)
|
|
316
|
+
if text != NULL:
|
|
317
|
+
if not skip_empty or not self.is_empty_text_node:
|
|
318
|
+
py_text = text.decode(_ENCODING)
|
|
319
|
+
container.append(py_text)
|
|
320
|
+
|
|
321
|
+
while node != NULL:
|
|
322
|
+
if _is_node_type(node, LXB_DOM_NODE_TYPE_TEXT):
|
|
323
|
+
text = <unsigned char *> lexbor_str_data_noi(&(<lxb_dom_character_data_t *> node).data)
|
|
324
|
+
if text != NULL:
|
|
325
|
+
if not skip_empty or not is_empty_text_node(node):
|
|
326
|
+
py_text = text.decode(_ENCODING)
|
|
327
|
+
container.append(py_text)
|
|
328
|
+
node = node.next
|
|
329
|
+
return container.text
|
|
330
|
+
else:
|
|
331
|
+
container = TextContainer(separator, strip)
|
|
332
|
+
if _is_node_type(self.node, LXB_DOM_NODE_TYPE_TEXT):
|
|
333
|
+
text = <unsigned char *> lexbor_str_data_noi(&(<lxb_dom_character_data_t *> self.node).data)
|
|
334
|
+
if text != NULL:
|
|
335
|
+
if not skip_empty or not self.is_empty_text_node:
|
|
336
|
+
container.append(text.decode(_ENCODING))
|
|
337
|
+
|
|
338
|
+
lxb_dom_node_simple_walk(
|
|
339
|
+
<lxb_dom_node_t *> start_node.node,
|
|
340
|
+
<lxb_dom_node_simple_walker_f> text_callback,
|
|
341
|
+
<void *> container
|
|
342
|
+
)
|
|
343
|
+
return container.text
|
|
344
|
+
|
|
345
|
+
cdef inline LexborNode _get_node(self):
|
|
346
|
+
cdef LexborNode node
|
|
347
|
+
if self._is_fragment_root and not _is_node_type(self.node, LXB_DOM_NODE_TYPE_TEXT):
|
|
348
|
+
node = self.parent
|
|
349
|
+
else:
|
|
350
|
+
node = self
|
|
351
|
+
return node
|
|
352
|
+
|
|
353
|
+
def css(self, str query):
|
|
354
|
+
"""Evaluate CSS selector against current node and its child nodes.
|
|
355
|
+
|
|
356
|
+
Matches pattern `query` against HTML tree.
|
|
357
|
+
`CSS selectors reference <https://www.w3schools.com/cssref/css_selectors.asp>`_.
|
|
358
|
+
|
|
359
|
+
Special selectors:
|
|
360
|
+
|
|
361
|
+
- parser.css('p:lexbor-contains("awesome" i)') -- case-insensitive contains
|
|
362
|
+
- parser.css('p:lexbor-contains("awesome")') -- case-sensitive contains
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
Parameters
|
|
366
|
+
----------
|
|
367
|
+
query : str
|
|
368
|
+
CSS selector (e.g. "div > :nth-child(2n+1):not(:has(a))").
|
|
369
|
+
|
|
370
|
+
Returns
|
|
371
|
+
-------
|
|
372
|
+
selector : list of `Node` objects
|
|
373
|
+
"""
|
|
374
|
+
return self.parser.selector.find(query, self._get_node())
|
|
375
|
+
|
|
376
|
+
def css_first(self, str query, default=None, bool strict=False):
|
|
377
|
+
"""Same as `css` but returns only the first match.
|
|
378
|
+
|
|
379
|
+
When `strict=False` stops at the first match. Works faster.
|
|
380
|
+
|
|
381
|
+
Parameters
|
|
382
|
+
----------
|
|
383
|
+
|
|
384
|
+
query : str
|
|
385
|
+
default : Any, default None
|
|
386
|
+
Default value to return if there is no match.
|
|
387
|
+
strict: bool, default False
|
|
388
|
+
Set to True if you want to check if there is strictly only one match in the document.
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
Returns
|
|
392
|
+
-------
|
|
393
|
+
selector : `LexborNode` object
|
|
394
|
+
"""
|
|
395
|
+
if strict:
|
|
396
|
+
results = self.parser.selector.find(query, self._get_node())
|
|
397
|
+
else:
|
|
398
|
+
results = self.parser.selector.find_first(query, self._get_node())
|
|
399
|
+
n_results = len(results)
|
|
400
|
+
if n_results > 0:
|
|
401
|
+
if strict and n_results > 1:
|
|
402
|
+
raise ValueError("Expected 1 match, but found %s matches" % n_results)
|
|
403
|
+
return results[0]
|
|
404
|
+
return default
|
|
405
|
+
|
|
406
|
+
def any_css_matches(self, tuple selectors):
|
|
407
|
+
"""Returns True if any of CSS selectors matches a node"""
|
|
408
|
+
for selector in selectors:
|
|
409
|
+
if self.parser.selector.any_matches(selector, self):
|
|
410
|
+
return True
|
|
411
|
+
return False
|
|
412
|
+
|
|
413
|
+
def css_matches(self, str selector):
|
|
414
|
+
"""Returns True if CSS selector matches a node."""
|
|
415
|
+
return bool(self.parser.selector.any_matches(selector, self))
|
|
416
|
+
|
|
417
|
+
def __repr__(self):
|
|
418
|
+
return '<LexborNode %s>' % self.tag
|
|
419
|
+
|
|
420
|
+
@property
|
|
421
|
+
def tag_id(self):
|
|
422
|
+
cdef lxb_tag_id_t tag_id = lxb_dom_node_tag_id_noi(self.node)
|
|
423
|
+
return tag_id
|
|
424
|
+
|
|
425
|
+
@property
|
|
426
|
+
def tag(self):
|
|
427
|
+
"""Return the name of the current tag (e.g. div, p, img).
|
|
428
|
+
|
|
429
|
+
For for non-tag nodes, returns the following names:
|
|
430
|
+
|
|
431
|
+
* `-text` - text node
|
|
432
|
+
* `-document` - document node
|
|
433
|
+
* `-comment` - comment node
|
|
434
|
+
|
|
435
|
+
This
|
|
436
|
+
|
|
437
|
+
Returns
|
|
438
|
+
-------
|
|
439
|
+
text : str
|
|
440
|
+
"""
|
|
441
|
+
|
|
442
|
+
cdef lxb_char_t *c_text
|
|
443
|
+
cdef size_t str_len = 0
|
|
444
|
+
if self.tag_id in [LXB_TAG__EM_DOCTYPE, LXB_TAG__TEXT, LXB_TAG__EM_COMMENT]:
|
|
445
|
+
return _TAG_TO_NAME[self.tag_id]
|
|
446
|
+
c_text = lxb_dom_element_qualified_name(<lxb_dom_element_t *> self.node, &str_len)
|
|
447
|
+
text = None
|
|
448
|
+
if c_text:
|
|
449
|
+
text = c_text.decode(_ENCODING)
|
|
450
|
+
return text
|
|
451
|
+
|
|
452
|
+
def decompose(self, bool recursive=True):
|
|
453
|
+
"""Remove the current node from the tree.
|
|
454
|
+
|
|
455
|
+
Parameters
|
|
456
|
+
----------
|
|
457
|
+
recursive : bool, default True
|
|
458
|
+
Whenever to delete all its child nodes
|
|
459
|
+
|
|
460
|
+
Examples
|
|
461
|
+
--------
|
|
462
|
+
|
|
463
|
+
>>> tree = LexborHTMLParser(html)
|
|
464
|
+
>>> for tag in tree.css('script'):
|
|
465
|
+
>>> tag.decompose()
|
|
466
|
+
|
|
467
|
+
"""
|
|
468
|
+
if self.node == <lxb_dom_node_t *> lxb_dom_document_root(&self.parser.document.dom_document):
|
|
469
|
+
raise SelectolaxError("Decomposing the root node is not allowed.")
|
|
470
|
+
|
|
471
|
+
if recursive:
|
|
472
|
+
node_remove_deep(<lxb_dom_node_t *> self.node)
|
|
473
|
+
else:
|
|
474
|
+
lxb_dom_node_remove(<lxb_dom_node_t *> self.node)
|
|
475
|
+
|
|
476
|
+
def strip_tags(self, list tags, bool recursive = False):
|
|
477
|
+
"""Remove specified tags from the HTML tree.
|
|
478
|
+
|
|
479
|
+
Parameters
|
|
480
|
+
----------
|
|
481
|
+
tags : list
|
|
482
|
+
List of tags to remove.
|
|
483
|
+
recursive : bool, default True
|
|
484
|
+
Whenever to delete all its child nodes
|
|
485
|
+
|
|
486
|
+
Examples
|
|
487
|
+
--------
|
|
488
|
+
|
|
489
|
+
>>> tree = LexborHTMLParser('<html><head></head><body><script></script><div>Hello world!</div></body></html>')
|
|
490
|
+
>>> tags = ['head', 'style', 'script', 'xmp', 'iframe', 'noembed', 'noframes']
|
|
491
|
+
>>> tree.strip_tags(tags)
|
|
492
|
+
>>> tree.html
|
|
493
|
+
'<html><body><div>Hello world!</div></body></html>'
|
|
494
|
+
|
|
495
|
+
"""
|
|
496
|
+
cdef LexborNode element
|
|
497
|
+
for tag in tags:
|
|
498
|
+
for element in self.css(tag):
|
|
499
|
+
element.decompose(recursive=recursive)
|
|
500
|
+
|
|
501
|
+
@property
|
|
502
|
+
def attributes(self):
|
|
503
|
+
"""Get all attributes that belong to the current node.
|
|
504
|
+
|
|
505
|
+
The value of empty attributes is None.
|
|
506
|
+
|
|
507
|
+
Returns
|
|
508
|
+
-------
|
|
509
|
+
attributes : dictionary of all attributes.
|
|
510
|
+
|
|
511
|
+
Examples
|
|
512
|
+
--------
|
|
513
|
+
|
|
514
|
+
>>> tree = LexborHTMLParser("<div data id='my_id'></div>")
|
|
515
|
+
>>> node = tree.css_first('div')
|
|
516
|
+
>>> node.attributes
|
|
517
|
+
{'data': None, 'id': 'my_id'}
|
|
518
|
+
"""
|
|
519
|
+
cdef lxb_dom_attr_t *attr = lxb_dom_element_first_attribute_noi(<lxb_dom_element_t *> self.node)
|
|
520
|
+
cdef size_t str_len = 0
|
|
521
|
+
attributes = dict()
|
|
522
|
+
|
|
523
|
+
if not _is_node_type(self.node, LXB_DOM_NODE_TYPE_ELEMENT):
|
|
524
|
+
return attributes
|
|
525
|
+
|
|
526
|
+
while attr != NULL:
|
|
527
|
+
key = lxb_dom_attr_local_name_noi(attr, &str_len)
|
|
528
|
+
value = lxb_dom_attr_value_noi(attr, &str_len)
|
|
529
|
+
|
|
530
|
+
if value:
|
|
531
|
+
py_value = value.decode(_ENCODING)
|
|
532
|
+
else:
|
|
533
|
+
py_value = None
|
|
534
|
+
attributes[key.decode(_ENCODING)] = py_value
|
|
535
|
+
|
|
536
|
+
attr = attr.next
|
|
537
|
+
return attributes
|
|
538
|
+
|
|
539
|
+
@property
|
|
540
|
+
def attrs(self):
|
|
541
|
+
"""A dict-like object that is similar to the ``attributes`` property, but operates directly on the Node data.
|
|
542
|
+
|
|
543
|
+
.. warning:: Use ``attributes`` instead, if you don't want to modify Node attributes.
|
|
544
|
+
|
|
545
|
+
Returns
|
|
546
|
+
-------
|
|
547
|
+
attributes : Attributes mapping object.
|
|
548
|
+
|
|
549
|
+
Examples
|
|
550
|
+
--------
|
|
551
|
+
|
|
552
|
+
>>> tree = LexborHTMLParser("<div id='a'></div>")
|
|
553
|
+
>>> node = tree.css_first('div')
|
|
554
|
+
>>> node.attrs
|
|
555
|
+
<div attributes, 1 items>
|
|
556
|
+
>>> node.attrs['id']
|
|
557
|
+
'a'
|
|
558
|
+
>>> node.attrs['foo'] = 'bar'
|
|
559
|
+
>>> del node.attrs['id']
|
|
560
|
+
>>> node.attributes
|
|
561
|
+
{'foo': 'bar'}
|
|
562
|
+
>>> node.attrs['id'] = 'new_id'
|
|
563
|
+
>>> node.html
|
|
564
|
+
'<div foo="bar" id="new_id"></div>'
|
|
565
|
+
"""
|
|
566
|
+
if not _is_node_type(self.node, LXB_DOM_NODE_TYPE_ELEMENT):
|
|
567
|
+
raise TypeError("attrs is only available for element nodes")
|
|
568
|
+
cdef LexborAttributes attributes = LexborAttributes.create(<lxb_dom_node_t *> self.node)
|
|
569
|
+
return attributes
|
|
570
|
+
|
|
571
|
+
@property
|
|
572
|
+
def id(self):
|
|
573
|
+
"""Get the id attribute of the node.
|
|
574
|
+
|
|
575
|
+
Returns None if id does not set.
|
|
576
|
+
|
|
577
|
+
Returns
|
|
578
|
+
-------
|
|
579
|
+
text : str
|
|
580
|
+
"""
|
|
581
|
+
cdef char * key = 'id'
|
|
582
|
+
cdef size_t str_len
|
|
583
|
+
cdef lxb_dom_attr_t * attr = lxb_dom_element_attr_by_name(
|
|
584
|
+
<lxb_dom_element_t *> self.node,
|
|
585
|
+
<lxb_char_t *> key, 2
|
|
586
|
+
)
|
|
587
|
+
if attr != NULL:
|
|
588
|
+
value = lxb_dom_attr_value_noi(attr, &str_len)
|
|
589
|
+
return value.decode(_ENCODING) if value else None
|
|
590
|
+
return None
|
|
591
|
+
|
|
592
|
+
def iter(self, bool include_text = False, bool skip_empty = False):
|
|
593
|
+
"""Iterate over direct children of this node.
|
|
594
|
+
|
|
595
|
+
Parameters
|
|
596
|
+
----------
|
|
597
|
+
include_text : bool, optional
|
|
598
|
+
When ``True``, yield text nodes in addition to element nodes. Defaults
|
|
599
|
+
to ``False``.
|
|
600
|
+
skip_empty : bool, optional
|
|
601
|
+
When ``include_text`` is ``True``, ignore text nodes made up solely
|
|
602
|
+
of ASCII whitespace (space, tab, newline, form feed or carriage
|
|
603
|
+
return). Defaults to ``False``.
|
|
604
|
+
|
|
605
|
+
Yields
|
|
606
|
+
------
|
|
607
|
+
LexborNode
|
|
608
|
+
Child nodes on the same tree level as this node, filtered according
|
|
609
|
+
to the provided options.
|
|
610
|
+
"""
|
|
611
|
+
|
|
612
|
+
cdef LexborNode start_node = self._get_node()
|
|
613
|
+
cdef lxb_dom_node_t *node = start_node.node.first_child
|
|
614
|
+
cdef LexborNode next_node
|
|
615
|
+
|
|
616
|
+
while node != NULL:
|
|
617
|
+
if node.type == LXB_DOM_NODE_TYPE_TEXT and not include_text:
|
|
618
|
+
node = node.next
|
|
619
|
+
continue
|
|
620
|
+
if node.type == LXB_DOM_NODE_TYPE_TEXT and include_text and skip_empty and is_empty_text_node(node):
|
|
621
|
+
node = node.next
|
|
622
|
+
continue
|
|
623
|
+
|
|
624
|
+
next_node = LexborNode.new(<lxb_dom_node_t *> node, self.parser)
|
|
625
|
+
yield next_node
|
|
626
|
+
node = node.next
|
|
627
|
+
|
|
628
|
+
def __iter__(self):
|
|
629
|
+
return self.iter()
|
|
630
|
+
|
|
631
|
+
def __next__(self):
|
|
632
|
+
return self.next
|
|
633
|
+
|
|
634
|
+
def unwrap(self, bint delete_empty=False):
|
|
635
|
+
"""Replace node with whatever is inside this node.
|
|
636
|
+
|
|
637
|
+
Does nothing if you perform unwrapping second time on the same node.
|
|
638
|
+
|
|
639
|
+
Parameters
|
|
640
|
+
----------
|
|
641
|
+
delete_empty : bool, default False
|
|
642
|
+
If True, removes empty tags.
|
|
643
|
+
|
|
644
|
+
Examples
|
|
645
|
+
--------
|
|
646
|
+
|
|
647
|
+
>>> tree = LexborHTMLParser("<div>Hello <i>world</i>!</div>")
|
|
648
|
+
>>> tree.css_first('i').unwrap()
|
|
649
|
+
>>> tree.html
|
|
650
|
+
'<html><head></head><body><div>Hello world!</div></body></html>'
|
|
651
|
+
|
|
652
|
+
Note: by default, empty tags are ignored, use "delete_empty" to change this.
|
|
653
|
+
"""
|
|
654
|
+
if self.node.parent == NULL:
|
|
655
|
+
return
|
|
656
|
+
|
|
657
|
+
if node_is_removed(<lxb_dom_node_t *> self.node) == 1:
|
|
658
|
+
logger.error("Attempt to unwrap removed node. Does nothing.")
|
|
659
|
+
return
|
|
660
|
+
|
|
661
|
+
cdef lxb_dom_node_t * current_node = self.node.first_child
|
|
662
|
+
cdef lxb_dom_node_t * next_node
|
|
663
|
+
|
|
664
|
+
if current_node == NULL:
|
|
665
|
+
if delete_empty:
|
|
666
|
+
lxb_dom_node_remove(<lxb_dom_node_t *> self.node)
|
|
667
|
+
return
|
|
668
|
+
|
|
669
|
+
while current_node != NULL:
|
|
670
|
+
next_node = current_node.next
|
|
671
|
+
lxb_dom_node_insert_before(self.node, current_node)
|
|
672
|
+
current_node = next_node
|
|
673
|
+
|
|
674
|
+
lxb_dom_node_remove(<lxb_dom_node_t *> self.node)
|
|
675
|
+
|
|
676
|
+
def unwrap_tags(self, list tags, bint delete_empty = False):
|
|
677
|
+
"""Unwraps specified tags from the HTML tree.
|
|
678
|
+
|
|
679
|
+
Works the same as the ``unwrap`` method, but applied to a list of tags.
|
|
680
|
+
|
|
681
|
+
Parameters
|
|
682
|
+
----------
|
|
683
|
+
tags : list
|
|
684
|
+
List of tags to remove.
|
|
685
|
+
delete_empty : bool, default False
|
|
686
|
+
If True, removes empty tags.
|
|
687
|
+
|
|
688
|
+
Examples
|
|
689
|
+
--------
|
|
690
|
+
|
|
691
|
+
>>> tree = LexborHTMLParser("<div><a href="">Hello</a> <i>world</i>!</div>")
|
|
692
|
+
>>> tree.body.unwrap_tags(['i','a'])
|
|
693
|
+
>>> tree.body.html
|
|
694
|
+
'<body><div>Hello world!</div></body>'
|
|
695
|
+
|
|
696
|
+
Note: by default, empty tags are ignored, use "delete_empty" to change this.
|
|
697
|
+
"""
|
|
698
|
+
cdef LexborNode element
|
|
699
|
+
for tag in tags:
|
|
700
|
+
if self.node.parent == NULL and not _is_node_type(self.node, LXB_DOM_NODE_TYPE_DOCUMENT):
|
|
701
|
+
break
|
|
702
|
+
for element in self.css(tag):
|
|
703
|
+
element.unwrap(delete_empty)
|
|
704
|
+
|
|
705
|
+
def merge_text_nodes(self):
|
|
706
|
+
"""Iterates over all text nodes and merges all text nodes that are close to each other.
|
|
707
|
+
|
|
708
|
+
This is useful for text extraction.
|
|
709
|
+
Use it when you need to strip HTML tags and merge "dangling" text.
|
|
710
|
+
|
|
711
|
+
Examples
|
|
712
|
+
--------
|
|
713
|
+
|
|
714
|
+
>>> tree = LexborHTMLParser("<div><p><strong>J</strong>ohn</p><p>Doe</p></div>")
|
|
715
|
+
>>> node = tree.css_first('div')
|
|
716
|
+
>>> tree.unwrap_tags(["strong"])
|
|
717
|
+
>>> tree.text(deep=True, separator=" ", strip=True)
|
|
718
|
+
"J ohn Doe" # Text extraction produces an extra space because the strong tag was removed.
|
|
719
|
+
>>> node.merge_text_nodes()
|
|
720
|
+
>>> tree.text(deep=True, separator=" ", strip=True)
|
|
721
|
+
"John Doe"
|
|
722
|
+
"""
|
|
723
|
+
_merge_text_nodes(self.node)
|
|
724
|
+
|
|
725
|
+
def traverse(self, bool include_text = False, bool skip_empty = False):
|
|
726
|
+
"""Depth-first traversal starting at the current node.
|
|
727
|
+
|
|
728
|
+
Parameters
|
|
729
|
+
----------
|
|
730
|
+
include_text : bool, optional
|
|
731
|
+
When ``True``, include text nodes in the traversal sequence. Defaults
|
|
732
|
+
to ``False``.
|
|
733
|
+
skip_empty : bool, optional
|
|
734
|
+
Skip text nodes that contain only ASCII whitespace (space, tab,
|
|
735
|
+
newline, form feed or carriage return) when ``include_text`` is
|
|
736
|
+
``True``. Defaults to ``False``.
|
|
737
|
+
|
|
738
|
+
Yields
|
|
739
|
+
------
|
|
740
|
+
LexborNode
|
|
741
|
+
Nodes encountered in depth-first order beginning with the current
|
|
742
|
+
node, filtered according to the provided options.
|
|
743
|
+
"""
|
|
744
|
+
cdef lxb_dom_node_t * root = self.node
|
|
745
|
+
cdef lxb_dom_node_t * node = root
|
|
746
|
+
cdef LexborNode lxb_node
|
|
747
|
+
|
|
748
|
+
while node != NULL:
|
|
749
|
+
if include_text or node.type != LXB_DOM_NODE_TYPE_TEXT:
|
|
750
|
+
if not skip_empty or not is_empty_text_node(node):
|
|
751
|
+
lxb_node = LexborNode.new(<lxb_dom_node_t *> node, self.parser)
|
|
752
|
+
yield lxb_node
|
|
753
|
+
|
|
754
|
+
if node.first_child != NULL:
|
|
755
|
+
node = node.first_child
|
|
756
|
+
else:
|
|
757
|
+
while node != root and node.next == NULL:
|
|
758
|
+
node = node.parent
|
|
759
|
+
if node == root:
|
|
760
|
+
break
|
|
761
|
+
node = node.next
|
|
762
|
+
|
|
763
|
+
def replace_with(self, str_or_LexborNode value):
|
|
764
|
+
"""Replace current Node with specified value.
|
|
765
|
+
|
|
766
|
+
Parameters
|
|
767
|
+
----------
|
|
768
|
+
value : str, bytes or Node
|
|
769
|
+
The text or Node instance to replace the Node with.
|
|
770
|
+
When a text string is passed, it's treated as text. All HTML tags will be escaped.
|
|
771
|
+
Convert and pass the ``Node`` object when you want to work with HTML.
|
|
772
|
+
Does not clone the ``Node`` object.
|
|
773
|
+
All future changes to the passed ``Node`` object will also be taken into account.
|
|
774
|
+
|
|
775
|
+
Examples
|
|
776
|
+
--------
|
|
777
|
+
|
|
778
|
+
>>> tree = LexborHTMLParser('<div>Get <img src="" alt="Laptop"></div>')
|
|
779
|
+
>>> img = tree.css_first('img')
|
|
780
|
+
>>> img.replace_with(img.attributes.get('alt', ''))
|
|
781
|
+
>>> tree.body.child.html
|
|
782
|
+
'<div>Get Laptop</div>'
|
|
783
|
+
|
|
784
|
+
>>> html_parser = LexborHTMLParser('<div>Get <span alt="Laptop"><img src="/jpg"> <div></div></span></div>')
|
|
785
|
+
>>> html_parser2 = LexborHTMLParser('<div>Test</div>')
|
|
786
|
+
>>> img_node = html_parser.css_first('img')
|
|
787
|
+
>>> img_node.replace_with(html_parser2.body.child)
|
|
788
|
+
'<div>Get <span alt="Laptop"><div>Test</div> <div></div></span></div>'
|
|
789
|
+
"""
|
|
790
|
+
cdef lxb_dom_node_t * new_node
|
|
791
|
+
|
|
792
|
+
if isinstance(value, (str, bytes, unicode)):
|
|
793
|
+
bytes_val = to_bytes(value)
|
|
794
|
+
new_node = <lxb_dom_node_t *> lxb_dom_document_create_text_node(
|
|
795
|
+
&self.parser.document.dom_document,
|
|
796
|
+
<lxb_char_t *> bytes_val, len(bytes_val)
|
|
797
|
+
)
|
|
798
|
+
if new_node == NULL:
|
|
799
|
+
raise SelectolaxError("Can't create a new node")
|
|
800
|
+
lxb_dom_node_insert_before(self.node, new_node)
|
|
801
|
+
lxb_dom_node_remove(<lxb_dom_node_t *> self.node)
|
|
802
|
+
elif isinstance(value, LexborNode):
|
|
803
|
+
new_node = lxb_dom_document_import_node(
|
|
804
|
+
&self.parser.document.dom_document,
|
|
805
|
+
<lxb_dom_node_t *> value.node,
|
|
806
|
+
<bint> True
|
|
807
|
+
)
|
|
808
|
+
if new_node == NULL:
|
|
809
|
+
raise SelectolaxError("Can't create a new node")
|
|
810
|
+
lxb_dom_node_insert_before(self.node, <lxb_dom_node_t *> new_node)
|
|
811
|
+
lxb_dom_node_remove(<lxb_dom_node_t *> self.node)
|
|
812
|
+
else:
|
|
813
|
+
raise SelectolaxError("Expected a string or LexborNode instance, but %s found" % type(value).__name__)
|
|
814
|
+
|
|
815
|
+
def insert_before(self, str_or_LexborNode value):
|
|
816
|
+
"""
|
|
817
|
+
Insert a node before the current Node.
|
|
818
|
+
|
|
819
|
+
Parameters
|
|
820
|
+
----------
|
|
821
|
+
value : str, bytes or Node
|
|
822
|
+
The text or Node instance to insert before the Node.
|
|
823
|
+
When a text string is passed, it's treated as text. All HTML tags will be escaped.
|
|
824
|
+
Convert and pass the ``Node`` object when you want to work with HTML.
|
|
825
|
+
Does not clone the ``Node`` object.
|
|
826
|
+
All future changes to the passed ``Node`` object will also be taken into account.
|
|
827
|
+
|
|
828
|
+
Examples
|
|
829
|
+
--------
|
|
830
|
+
|
|
831
|
+
>>> tree = LexborHTMLParser('<div>Get <img src="" alt="Laptop"></div>')
|
|
832
|
+
>>> img = tree.css_first('img')
|
|
833
|
+
>>> img.insert_before(img.attributes.get('alt', ''))
|
|
834
|
+
>>> tree.body.child.html
|
|
835
|
+
'<div>Get Laptop<img src="" alt="Laptop"></div>'
|
|
836
|
+
|
|
837
|
+
>>> html_parser = LexborHTMLParser('<div>Get <span alt="Laptop"><img src="/jpg"> <div></div></span></div>')
|
|
838
|
+
>>> html_parser2 = LexborHTMLParser('<div>Test</div>')
|
|
839
|
+
>>> img_node = html_parser.css_first('img')
|
|
840
|
+
>>> img_node.insert_before(html_parser2.body.child)
|
|
841
|
+
<div>Get <span alt="Laptop"><div>Test</div><img src="/jpg"> <div></div></span></div>'
|
|
842
|
+
"""
|
|
843
|
+
cdef lxb_dom_node_t * new_node
|
|
844
|
+
|
|
845
|
+
if isinstance(value, (str, bytes, unicode)):
|
|
846
|
+
bytes_val = to_bytes(value)
|
|
847
|
+
new_node = <lxb_dom_node_t *> lxb_dom_document_create_text_node(
|
|
848
|
+
&self.parser.document.dom_document,
|
|
849
|
+
<lxb_char_t *> bytes_val, len(bytes_val)
|
|
850
|
+
)
|
|
851
|
+
if new_node == NULL:
|
|
852
|
+
raise SelectolaxError("Can't create a new node")
|
|
853
|
+
lxb_dom_node_insert_before(self.node, new_node)
|
|
854
|
+
elif isinstance(value, LexborNode):
|
|
855
|
+
new_node = lxb_dom_document_import_node(
|
|
856
|
+
&self.parser.document.dom_document,
|
|
857
|
+
<lxb_dom_node_t *> value.node,
|
|
858
|
+
<bint> True
|
|
859
|
+
)
|
|
860
|
+
if new_node == NULL:
|
|
861
|
+
raise SelectolaxError("Can't create a new node")
|
|
862
|
+
lxb_dom_node_insert_before(self.node, <lxb_dom_node_t *> new_node)
|
|
863
|
+
else:
|
|
864
|
+
raise SelectolaxError("Expected a string or LexborNode instance, but %s found" % type(value).__name__)
|
|
865
|
+
|
|
866
|
+
def insert_after(self, str_or_LexborNode value):
|
|
867
|
+
"""
|
|
868
|
+
Insert a node after the current Node.
|
|
869
|
+
|
|
870
|
+
Parameters
|
|
871
|
+
----------
|
|
872
|
+
value : str, bytes or Node
|
|
873
|
+
The text or Node instance to insert after the Node.
|
|
874
|
+
When a text string is passed, it's treated as text. All HTML tags will be escaped.
|
|
875
|
+
Convert and pass the ``Node`` object when you want to work with HTML.
|
|
876
|
+
Does not clone the ``Node`` object.
|
|
877
|
+
All future changes to the passed ``Node`` object will also be taken into account.
|
|
878
|
+
|
|
879
|
+
Examples
|
|
880
|
+
--------
|
|
881
|
+
|
|
882
|
+
>>> tree = LexborHTMLParser('<div>Get <img src="" alt="Laptop"></div>')
|
|
883
|
+
>>> img = tree.css_first('img')
|
|
884
|
+
>>> img.insert_after(img.attributes.get('alt', ''))
|
|
885
|
+
>>> tree.body.child.html
|
|
886
|
+
'<div>Get <img src="" alt="Laptop">Laptop</div>'
|
|
887
|
+
|
|
888
|
+
>>> html_parser = LexborHTMLParser('<div>Get <span alt="Laptop"><img src="/jpg"> <div></div></span></div>')
|
|
889
|
+
>>> html_parser2 = LexborHTMLParser('<div>Test</div>')
|
|
890
|
+
>>> img_node = html_parser.css_first('img')
|
|
891
|
+
>>> img_node.insert_after(html_parser2.body.child)
|
|
892
|
+
<div>Get <span alt="Laptop"><img src="/jpg"><div>Test</div> <div></div></span></div>'
|
|
893
|
+
"""
|
|
894
|
+
cdef lxb_dom_node_t * new_node
|
|
895
|
+
|
|
896
|
+
if isinstance(value, (str, bytes, unicode)):
|
|
897
|
+
bytes_val = to_bytes(value)
|
|
898
|
+
new_node = <lxb_dom_node_t *> lxb_dom_document_create_text_node(
|
|
899
|
+
&self.parser.document.dom_document,
|
|
900
|
+
<lxb_char_t *> bytes_val, len(bytes_val)
|
|
901
|
+
)
|
|
902
|
+
if new_node == NULL:
|
|
903
|
+
raise SelectolaxError("Can't create a new node")
|
|
904
|
+
lxb_dom_node_insert_after(self.node, new_node)
|
|
905
|
+
elif isinstance(value, LexborNode):
|
|
906
|
+
new_node = lxb_dom_document_import_node(
|
|
907
|
+
&self.parser.document.dom_document,
|
|
908
|
+
<lxb_dom_node_t *> value.node,
|
|
909
|
+
<bint> True
|
|
910
|
+
)
|
|
911
|
+
if new_node == NULL:
|
|
912
|
+
raise SelectolaxError("Can't create a new node")
|
|
913
|
+
lxb_dom_node_insert_after(self.node, <lxb_dom_node_t *> new_node)
|
|
914
|
+
else:
|
|
915
|
+
raise SelectolaxError("Expected a string or LexborNode instance, but %s found" % type(value).__name__)
|
|
916
|
+
|
|
917
|
+
def insert_child(self, str_or_LexborNode value):
|
|
918
|
+
"""
|
|
919
|
+
Insert a node inside (at the end of) the current Node.
|
|
920
|
+
|
|
921
|
+
Parameters
|
|
922
|
+
----------
|
|
923
|
+
value : str, bytes or Node
|
|
924
|
+
The text or Node instance to insert inside the Node.
|
|
925
|
+
When a text string is passed, it's treated as text. All HTML tags will be escaped.
|
|
926
|
+
Convert and pass the ``Node`` object when you want to work with HTML.
|
|
927
|
+
Does not clone the ``Node`` object.
|
|
928
|
+
All future changes to the passed ``Node`` object will also be taken into account.
|
|
929
|
+
|
|
930
|
+
Examples
|
|
931
|
+
--------
|
|
932
|
+
|
|
933
|
+
>>> tree = LexborHTMLParser('<div>Get <img src=""></div>')
|
|
934
|
+
>>> div = tree.css_first('div')
|
|
935
|
+
>>> div.insert_child('Laptop')
|
|
936
|
+
>>> tree.body.child.html
|
|
937
|
+
'<div>Get <img src="">Laptop</div>'
|
|
938
|
+
|
|
939
|
+
>>> html_parser = LexborHTMLParser('<div>Get <span alt="Laptop"> <div>Laptop</div> </span></div>')
|
|
940
|
+
>>> html_parser2 = LexborHTMLParser('<div>Test</div>')
|
|
941
|
+
>>> span_node = html_parser.css_first('span')
|
|
942
|
+
>>> span_node.insert_child(html_parser2.body.child)
|
|
943
|
+
<div>Get <span alt="Laptop"> <div>Laptop</div> <div>Test</div> </span></div>'
|
|
944
|
+
"""
|
|
945
|
+
cdef lxb_dom_node_t * new_node
|
|
946
|
+
|
|
947
|
+
if isinstance(value, (str, bytes, unicode)):
|
|
948
|
+
bytes_val = to_bytes(value)
|
|
949
|
+
new_node = <lxb_dom_node_t *> lxb_dom_document_create_text_node(
|
|
950
|
+
&self.parser.document.dom_document,
|
|
951
|
+
<lxb_char_t *> bytes_val, len(bytes_val)
|
|
952
|
+
)
|
|
953
|
+
if new_node == NULL:
|
|
954
|
+
raise SelectolaxError("Can't create a new node")
|
|
955
|
+
lxb_dom_node_insert_child(self.node, new_node)
|
|
956
|
+
elif isinstance(value, LexborNode):
|
|
957
|
+
new_node = lxb_dom_document_import_node(
|
|
958
|
+
&self.parser.document.dom_document,
|
|
959
|
+
<lxb_dom_node_t *> value.node,
|
|
960
|
+
<bint> True
|
|
961
|
+
)
|
|
962
|
+
if new_node == NULL:
|
|
963
|
+
raise SelectolaxError("Can't create a new node")
|
|
964
|
+
lxb_dom_node_insert_child(self.node, <lxb_dom_node_t *> new_node)
|
|
965
|
+
else:
|
|
966
|
+
raise SelectolaxError("Expected a string or LexborNode instance, but %s found" % type(value).__name__)
|
|
967
|
+
|
|
968
|
+
@property
|
|
969
|
+
def raw_value(self):
|
|
970
|
+
"""Return the raw (unparsed, original) value of a node.
|
|
971
|
+
|
|
972
|
+
Currently, works on text nodes only.
|
|
973
|
+
|
|
974
|
+
Returns
|
|
975
|
+
-------
|
|
976
|
+
|
|
977
|
+
raw_value : bytes
|
|
978
|
+
|
|
979
|
+
Examples
|
|
980
|
+
--------
|
|
981
|
+
|
|
982
|
+
>>> html_parser = LexborHTMLParser('<div><test></div>')
|
|
983
|
+
>>> selector = html_parser.css_first('div')
|
|
984
|
+
>>> selector.child.html
|
|
985
|
+
'<test>'
|
|
986
|
+
>>> selector.child.raw_value
|
|
987
|
+
b'<test>'
|
|
988
|
+
"""
|
|
989
|
+
raise NotImplementedError("This features is not supported by the lexbor backend. Please use Modest backend.")
|
|
990
|
+
|
|
991
|
+
def scripts_contain(self, str query):
|
|
992
|
+
"""Returns True if any of the script tags contain specified text.
|
|
993
|
+
|
|
994
|
+
Caches script tags on the first call to improve performance.
|
|
995
|
+
|
|
996
|
+
Parameters
|
|
997
|
+
----------
|
|
998
|
+
query : str
|
|
999
|
+
The query to check.
|
|
1000
|
+
|
|
1001
|
+
"""
|
|
1002
|
+
cdef LexborNode node
|
|
1003
|
+
if self.parser.cached_script_texts is None:
|
|
1004
|
+
nodes = self.parser.selector.find('script', self)
|
|
1005
|
+
text_nodes = []
|
|
1006
|
+
for node in nodes:
|
|
1007
|
+
node_text = node.text(deep=True)
|
|
1008
|
+
if node_text:
|
|
1009
|
+
text_nodes.append(node_text)
|
|
1010
|
+
self.parser.cached_script_texts = text_nodes
|
|
1011
|
+
|
|
1012
|
+
for text in self.parser.cached_script_texts:
|
|
1013
|
+
if query in text:
|
|
1014
|
+
return True
|
|
1015
|
+
return False
|
|
1016
|
+
|
|
1017
|
+
def script_srcs_contain(self, tuple queries):
|
|
1018
|
+
"""Returns True if any of the script SRCs attributes contain on of the specified text.
|
|
1019
|
+
|
|
1020
|
+
Caches values on the first call to improve performance.
|
|
1021
|
+
|
|
1022
|
+
Parameters
|
|
1023
|
+
----------
|
|
1024
|
+
queries : tuple of str
|
|
1025
|
+
|
|
1026
|
+
"""
|
|
1027
|
+
cdef LexborNode node
|
|
1028
|
+
if self.parser.cached_script_srcs is None:
|
|
1029
|
+
nodes = self.parser.selector.find('script', self)
|
|
1030
|
+
src_nodes = []
|
|
1031
|
+
for node in nodes:
|
|
1032
|
+
node_src = node.attrs.get('src')
|
|
1033
|
+
if node_src:
|
|
1034
|
+
src_nodes.append(node_src)
|
|
1035
|
+
self.parser.cached_script_srcs = src_nodes
|
|
1036
|
+
|
|
1037
|
+
for text in self.parser.cached_script_srcs:
|
|
1038
|
+
for query in queries:
|
|
1039
|
+
if query in text:
|
|
1040
|
+
return True
|
|
1041
|
+
return False
|
|
1042
|
+
|
|
1043
|
+
def remove(self, bool recursive=True):
|
|
1044
|
+
"""An alias for the decompose method."""
|
|
1045
|
+
self.decompose(recursive)
|
|
1046
|
+
|
|
1047
|
+
def select(self, query=None):
|
|
1048
|
+
"""Select nodes given a CSS selector.
|
|
1049
|
+
|
|
1050
|
+
Works similarly to the the ``css`` method, but supports chained filtering and extra features.
|
|
1051
|
+
|
|
1052
|
+
Parameters
|
|
1053
|
+
----------
|
|
1054
|
+
query : str or None
|
|
1055
|
+
The CSS selector to use when searching for nodes.
|
|
1056
|
+
|
|
1057
|
+
Returns
|
|
1058
|
+
-------
|
|
1059
|
+
selector : The `Selector` class.
|
|
1060
|
+
"""
|
|
1061
|
+
return LexborSelector(self._get_node(), query)
|
|
1062
|
+
|
|
1063
|
+
def __eq__(self, other):
|
|
1064
|
+
if isinstance(other, str):
|
|
1065
|
+
return self.html == other
|
|
1066
|
+
if not isinstance(other, LexborNode):
|
|
1067
|
+
return False
|
|
1068
|
+
return self.html == other.html
|
|
1069
|
+
|
|
1070
|
+
@property
|
|
1071
|
+
def text_content(self):
|
|
1072
|
+
"""Returns the text of the node if it is a text node.
|
|
1073
|
+
|
|
1074
|
+
Returns None for other nodes.
|
|
1075
|
+
Unlike the ``text`` method, does not include child nodes.
|
|
1076
|
+
|
|
1077
|
+
Returns
|
|
1078
|
+
-------
|
|
1079
|
+
text : str or None.
|
|
1080
|
+
"""
|
|
1081
|
+
cdef unsigned char * text
|
|
1082
|
+
cdef lxb_dom_node_t * node = <lxb_dom_node_t *> self.node.first_child
|
|
1083
|
+
cdef TextContainer container
|
|
1084
|
+
if not _is_node_type(self.node, LXB_DOM_NODE_TYPE_TEXT):
|
|
1085
|
+
return None
|
|
1086
|
+
|
|
1087
|
+
text = <unsigned char *> lexbor_str_data_noi(&(<lxb_dom_character_data_t *> self.node).data)
|
|
1088
|
+
if text != NULL:
|
|
1089
|
+
container = TextContainer.new_with_defaults()
|
|
1090
|
+
py_text = text.decode(_ENCODING)
|
|
1091
|
+
container.append(py_text)
|
|
1092
|
+
return container.text
|
|
1093
|
+
return None
|
|
1094
|
+
|
|
1095
|
+
@property
|
|
1096
|
+
def comment_content(self) -> str | None:
|
|
1097
|
+
"""Extract the textual content of an HTML comment node.
|
|
1098
|
+
|
|
1099
|
+
Returns
|
|
1100
|
+
-------
|
|
1101
|
+
str or None
|
|
1102
|
+
Comment text with surrounding whitespace removed, or ``None`` if
|
|
1103
|
+
the current node is not a comment or the comment markup cannot be
|
|
1104
|
+
parsed.
|
|
1105
|
+
|
|
1106
|
+
Examples
|
|
1107
|
+
--------
|
|
1108
|
+
>>> parse_fragment("<!-- hello -->")[0].comment_content
|
|
1109
|
+
'hello'
|
|
1110
|
+
>>> parse_fragment("<div>not a comment</div>")[0].comment_content is None
|
|
1111
|
+
True
|
|
1112
|
+
"""
|
|
1113
|
+
if not self.is_comment_node:
|
|
1114
|
+
return None
|
|
1115
|
+
try:
|
|
1116
|
+
return extract_html_comment(self.html)
|
|
1117
|
+
except (ValueError, AttributeError, IndexError):
|
|
1118
|
+
return None
|
|
1119
|
+
|
|
1120
|
+
@property
|
|
1121
|
+
def inner_html(self) -> str | None:
|
|
1122
|
+
"""Return HTML representation of the child nodes.
|
|
1123
|
+
|
|
1124
|
+
Works similar to innerHTML in JavaScript.
|
|
1125
|
+
Unlike the `.html` property, does not include the current node.
|
|
1126
|
+
Can be used to set HTML as well. See the setter docstring.
|
|
1127
|
+
|
|
1128
|
+
Returns
|
|
1129
|
+
-------
|
|
1130
|
+
text : str | None
|
|
1131
|
+
"""
|
|
1132
|
+
|
|
1133
|
+
return self._serialize_inner_html(LXB_HTML_SERIALIZE_OPT_UNDEF, 0, False)
|
|
1134
|
+
|
|
1135
|
+
@inner_html.setter
|
|
1136
|
+
def inner_html(self, str html) -> None:
|
|
1137
|
+
"""Set inner HTML to the specified HTML.
|
|
1138
|
+
|
|
1139
|
+
Replaces existing data inside the node.
|
|
1140
|
+
Works similar to innerHTML in JavaScript.
|
|
1141
|
+
|
|
1142
|
+
Parameters
|
|
1143
|
+
----------
|
|
1144
|
+
html : str | None
|
|
1145
|
+
|
|
1146
|
+
"""
|
|
1147
|
+
cdef bytes bytes_val
|
|
1148
|
+
bytes_val = <bytes> html.encode("utf-8")
|
|
1149
|
+
lxb_html_element_inner_html_set(
|
|
1150
|
+
<lxb_html_element_t *> self.node,
|
|
1151
|
+
<lxb_char_t *> bytes_val, len(bytes_val)
|
|
1152
|
+
)
|
|
1153
|
+
|
|
1154
|
+
def clone(self) -> LexborNode:
|
|
1155
|
+
"""Clone the current node.
|
|
1156
|
+
|
|
1157
|
+
You can use to do temporary modifications without affecting the original HTML tree.
|
|
1158
|
+
|
|
1159
|
+
It is tied to the current parser instance.
|
|
1160
|
+
Gets destroyed when parser instance is destroyed.
|
|
1161
|
+
"""
|
|
1162
|
+
cdef lxb_dom_node_t * node
|
|
1163
|
+
node = lxb_dom_node_clone(<lxb_dom_node_t *> self.node, 1)
|
|
1164
|
+
return LexborNode.new(node, self.parser)
|
|
1165
|
+
|
|
1166
|
+
@property
|
|
1167
|
+
def is_element_node(self) -> bool:
|
|
1168
|
+
"""Return True if the node represents an element node."""
|
|
1169
|
+
return _is_node_type(self.node, LXB_DOM_NODE_TYPE_ELEMENT)
|
|
1170
|
+
|
|
1171
|
+
@property
|
|
1172
|
+
def is_text_node(self) -> bool:
|
|
1173
|
+
"""Return True if the node represents a text node."""
|
|
1174
|
+
return _is_node_type(self.node, LXB_DOM_NODE_TYPE_TEXT)
|
|
1175
|
+
|
|
1176
|
+
@property
|
|
1177
|
+
def is_comment_node(self) -> bool:
|
|
1178
|
+
"""Return True if the node represents a comment node."""
|
|
1179
|
+
return _is_node_type(self.node, LXB_DOM_NODE_TYPE_COMMENT)
|
|
1180
|
+
|
|
1181
|
+
@property
|
|
1182
|
+
def is_document_node(self) -> bool:
|
|
1183
|
+
"""Return True if the node represents a document node."""
|
|
1184
|
+
return _is_node_type(self.node, LXB_DOM_NODE_TYPE_DOCUMENT)
|
|
1185
|
+
|
|
1186
|
+
@property
|
|
1187
|
+
def is_empty_text_node(self) -> bool:
|
|
1188
|
+
"""Check whether the current node is an empty text node.
|
|
1189
|
+
|
|
1190
|
+
Returns
|
|
1191
|
+
-------
|
|
1192
|
+
bool
|
|
1193
|
+
``True`` when the node is a text node whose character data consists
|
|
1194
|
+
only of ASCII whitespace characters (space, tab, newline, form feed
|
|
1195
|
+
or carriage return).
|
|
1196
|
+
"""
|
|
1197
|
+
return is_empty_text_node(self.node)
|
|
1198
|
+
|
|
1199
|
+
|
|
1200
|
+
@cython.internal
|
|
1201
|
+
@cython.final
|
|
1202
|
+
cdef class TextContainer:
|
|
1203
|
+
cdef list _parts
|
|
1204
|
+
cdef str separator
|
|
1205
|
+
cdef bint strip
|
|
1206
|
+
|
|
1207
|
+
@staticmethod
|
|
1208
|
+
cdef TextContainer new_with_defaults():
|
|
1209
|
+
cdef TextContainer cls = TextContainer.__new__(TextContainer)
|
|
1210
|
+
cls._parts = []
|
|
1211
|
+
cls.separator = ''
|
|
1212
|
+
cls.strip = False
|
|
1213
|
+
return cls
|
|
1214
|
+
|
|
1215
|
+
def __init__(self, str separator = '', bool strip = False):
|
|
1216
|
+
self._parts = []
|
|
1217
|
+
self.separator = separator
|
|
1218
|
+
self.strip = strip
|
|
1219
|
+
|
|
1220
|
+
def append(self, str node_text):
|
|
1221
|
+
if self.strip:
|
|
1222
|
+
self._parts.append(node_text.strip())
|
|
1223
|
+
else:
|
|
1224
|
+
self._parts.append(node_text)
|
|
1225
|
+
|
|
1226
|
+
@property
|
|
1227
|
+
def text(self):
|
|
1228
|
+
return self.separator.join(self._parts)
|
|
1229
|
+
|
|
1230
|
+
cdef lexbor_action_t text_callback(lxb_dom_node_t *node, void *ctx):
|
|
1231
|
+
cdef unsigned char *text
|
|
1232
|
+
cdef lxb_tag_id_t tag_id = lxb_dom_node_tag_id_noi(node)
|
|
1233
|
+
if tag_id != LXB_TAG__TEXT:
|
|
1234
|
+
return LEXBOR_ACTION_OK
|
|
1235
|
+
|
|
1236
|
+
text = <unsigned char *> lexbor_str_data_noi(&(<lxb_dom_text_t *> node).char_data.data)
|
|
1237
|
+
if not text:
|
|
1238
|
+
return LEXBOR_ACTION_OK
|
|
1239
|
+
|
|
1240
|
+
try:
|
|
1241
|
+
py_str = text.decode(_ENCODING, "replace")
|
|
1242
|
+
|
|
1243
|
+
except Exception as e:
|
|
1244
|
+
PyErr_SetNone(e)
|
|
1245
|
+
return LEXBOR_ACTION_STOP
|
|
1246
|
+
|
|
1247
|
+
cdef TextContainer cls
|
|
1248
|
+
cls = <TextContainer> ctx
|
|
1249
|
+
cls.append(py_str)
|
|
1250
|
+
return LEXBOR_ACTION_OK
|
|
1251
|
+
|
|
1252
|
+
cdef lxb_status_t serialize_fragment(lxb_dom_node_t *node, lexbor_str_t *lxb_str):
|
|
1253
|
+
cdef lxb_status_t status
|
|
1254
|
+
while node != NULL:
|
|
1255
|
+
status = lxb_html_serialize_tree_str(node, lxb_str)
|
|
1256
|
+
if status != LXB_STATUS_OK:
|
|
1257
|
+
return status
|
|
1258
|
+
node = node.next
|
|
1259
|
+
|
|
1260
|
+
return LXB_STATUS_OK
|
|
1261
|
+
|
|
1262
|
+
|
|
1263
|
+
cdef lxb_status_t serialize_fragment_pretty(
|
|
1264
|
+
lxb_dom_node_t *node,
|
|
1265
|
+
lexbor_str_t *lxb_str,
|
|
1266
|
+
lxb_html_serialize_opt_t options,
|
|
1267
|
+
size_t indent,
|
|
1268
|
+
):
|
|
1269
|
+
cdef lxb_status_t status
|
|
1270
|
+
while node != NULL:
|
|
1271
|
+
status = lxb_html_serialize_pretty_tree_str(node, options, indent, lxb_str)
|
|
1272
|
+
if status != LXB_STATUS_OK:
|
|
1273
|
+
return status
|
|
1274
|
+
node = node.next
|
|
1275
|
+
|
|
1276
|
+
return LXB_STATUS_OK
|
|
1277
|
+
|
|
1278
|
+
|
|
1279
|
+
cdef inline lxb_html_serialize_opt_t _html_pretty_options(
|
|
1280
|
+
bint skip_ws_nodes,
|
|
1281
|
+
bint skip_comment,
|
|
1282
|
+
bint raw,
|
|
1283
|
+
bint without_closing,
|
|
1284
|
+
bint tag_with_ns,
|
|
1285
|
+
bint without_text_indent,
|
|
1286
|
+
bint full_doctype,
|
|
1287
|
+
bint html5test,
|
|
1288
|
+
):
|
|
1289
|
+
cdef lxb_html_serialize_opt_t options = LXB_HTML_SERIALIZE_OPT_UNDEF
|
|
1290
|
+
|
|
1291
|
+
if skip_ws_nodes:
|
|
1292
|
+
options = <lxb_html_serialize_opt_t> (options | LXB_HTML_SERIALIZE_OPT_SKIP_WS_NODES)
|
|
1293
|
+
if skip_comment:
|
|
1294
|
+
options = <lxb_html_serialize_opt_t> (options | LXB_HTML_SERIALIZE_OPT_SKIP_COMMENT)
|
|
1295
|
+
if raw:
|
|
1296
|
+
options = <lxb_html_serialize_opt_t> (options | LXB_HTML_SERIALIZE_OPT_RAW)
|
|
1297
|
+
if without_closing:
|
|
1298
|
+
options = <lxb_html_serialize_opt_t> (options | LXB_HTML_SERIALIZE_OPT_WITHOUT_CLOSING)
|
|
1299
|
+
if tag_with_ns:
|
|
1300
|
+
options = <lxb_html_serialize_opt_t> (options | LXB_HTML_SERIALIZE_OPT_TAG_WITH_NS)
|
|
1301
|
+
if without_text_indent:
|
|
1302
|
+
options = <lxb_html_serialize_opt_t> (options | LXB_HTML_SERIALIZE_OPT_WITHOUT_TEXT_INDENT)
|
|
1303
|
+
if full_doctype:
|
|
1304
|
+
options = <lxb_html_serialize_opt_t> (options | LXB_HTML_SERIALIZE_OPT_FULL_DOCTYPE)
|
|
1305
|
+
if html5test:
|
|
1306
|
+
options = <lxb_html_serialize_opt_t> (options | 0x80)
|
|
1307
|
+
|
|
1308
|
+
return options
|
|
1309
|
+
|
|
1310
|
+
cdef inline bint _is_node_type(lxb_dom_node_t *node, lxb_dom_node_type_t expected_type):
|
|
1311
|
+
return node != NULL and node.type == expected_type
|
|
1312
|
+
|
|
1313
|
+
cdef void _merge_text_nodes(lxb_dom_node_t *root):
|
|
1314
|
+
if root == NULL or node_is_removed(root):
|
|
1315
|
+
return
|
|
1316
|
+
|
|
1317
|
+
cdef lxb_dom_node_t *node
|
|
1318
|
+
cdef lxb_dom_node_t *next_node
|
|
1319
|
+
cdef lxb_dom_text_t *new_text_node
|
|
1320
|
+
cdef lxb_char_t *left_text
|
|
1321
|
+
cdef lxb_char_t *right_text
|
|
1322
|
+
cdef size_t left_length, right_length
|
|
1323
|
+
cdef bytes combined
|
|
1324
|
+
|
|
1325
|
+
cdef bint changed = 1
|
|
1326
|
+
while changed:
|
|
1327
|
+
changed = 0
|
|
1328
|
+
node = root.first_child
|
|
1329
|
+
while node != NULL:
|
|
1330
|
+
next_node = node.next
|
|
1331
|
+
if node.type == LXB_DOM_NODE_TYPE_TEXT and next_node != NULL and next_node.type == LXB_DOM_NODE_TYPE_TEXT:
|
|
1332
|
+
left_text = lxb_dom_node_text_content(node, &left_length)
|
|
1333
|
+
right_text = lxb_dom_node_text_content(next_node, &right_length)
|
|
1334
|
+
|
|
1335
|
+
if left_text != NULL and right_text != NULL:
|
|
1336
|
+
combined = (<bytes>left_text[:left_length]) + (<bytes>right_text[:right_length])
|
|
1337
|
+
new_text_node = lxb_dom_document_create_text_node(
|
|
1338
|
+
root.owner_document,
|
|
1339
|
+
<lxb_char_t *>combined,
|
|
1340
|
+
len(combined)
|
|
1341
|
+
)
|
|
1342
|
+
if new_text_node != NULL:
|
|
1343
|
+
lxb_dom_node_insert_before(node, <lxb_dom_node_t *>new_text_node)
|
|
1344
|
+
lxb_dom_node_remove(node)
|
|
1345
|
+
lxb_dom_node_remove(next_node)
|
|
1346
|
+
changed = 1
|
|
1347
|
+
break
|
|
1348
|
+
|
|
1349
|
+
node = next_node
|
|
1350
|
+
|
|
1351
|
+
node = root.first_child
|
|
1352
|
+
while node != NULL:
|
|
1353
|
+
if node.type == LXB_DOM_NODE_TYPE_ELEMENT and node.first_child:
|
|
1354
|
+
_merge_text_nodes(node)
|
|
1355
|
+
node = node.next
|