pdflinkcheck 1.2.29__tar.gz → 1.3.8__tar.gz
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.
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/LICENSE +3 -3
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/PKG-INFO +19 -16
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/README.md +14 -12
- {pdflinkcheck-1.2.29/src/pdflinkcheck/data → pdflinkcheck-1.3.8}/pyproject.toml +4 -3
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/__init__.py +1 -1
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/cli.py +111 -27
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/LICENSE +3 -3
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/README.md +14 -12
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8/src/pdflinkcheck/data}/pyproject.toml +4 -3
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/environment.py +14 -7
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/gui.py +74 -18
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/helpers.py +47 -1
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/io.py +35 -6
- pdflinkcheck-1.2.29/src/pdflinkcheck/report.py → pdflinkcheck-1.3.8/src/pdflinkcheck/report copy.py +57 -32
- pdflinkcheck-1.3.8/src/pdflinkcheck/report.py +561 -0
- pdflinkcheck-1.3.8/src/pdflinkcheck/spreadsheet.py +271 -0
- pdflinkcheck-1.2.29/src/pdflinkcheck/stdlib_server_alt.py → pdflinkcheck-1.3.8/src/pdflinkcheck/stdlib_server.py +156 -115
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/validate.py +11 -6
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck.egg-info/PKG-INFO +19 -16
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck.egg-info/SOURCES.txt +2 -1
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck.egg-info/requires.txt +5 -4
- pdflinkcheck-1.2.29/src/pdflinkcheck/stdlib_server.py +0 -170
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/LICENSE-AGPL3 +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/LICENSE-MIT +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/MANIFEST.in +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/setup.cfg +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/__main__.py +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/analysis_pdfium.py +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/analysis_pymupdf.py +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/analysis_pypdf.py +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/I Have Questions.md +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/icons/BoxArt-1080x1080.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/icons/Logo-150x150.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/icons/Logo-300x300.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/icons/Logo-71x71.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/icons/PosterArt-720x1080.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/icons/SmallLogo-44x44.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/icons/SplashScreen-620x300.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/icons/StoreLogo-50x50.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/icons/WideLogo-310x150.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/icons/red_pdf_512px.ico +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/border-accent-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/border-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/border-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/border-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/border-invalid.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/card.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/check-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/check-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/check-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/check-tri-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/check-tri-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/check-tri-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/check-unsel-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/check-unsel-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/check-unsel-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/check-unsel-pressed.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/combo-button-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/combo-button-focus.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/combo-button-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/down.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/empty.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/hor-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/hor-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/hor-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/notebook.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/off-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/off-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/off-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/on-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/on-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/on-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/radio-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/radio-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/radio-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/radio-tri-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/radio-tri-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/radio-tri-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/radio-unsel-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/radio-unsel-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/radio-unsel-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/radio-unsel-pressed.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/rect-accent-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/rect-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/rect-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/rect-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/right.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/scale-hor.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/scale-vert.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/separator.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/sizegrip.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/spin-button-down-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/spin-button-down-focus.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/spin-button-up.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/tab-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/tab-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/tab-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/thumb-hor-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/thumb-hor-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/thumb-hor-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/thumb-vert-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/thumb-vert-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/thumb-vert-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/tree-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/tree-pressed.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/up.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/vert-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/vert-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark/vert-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-dark.tcl +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/border-accent-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/border-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/border-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/border-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/border-invalid.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/card.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/check-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/check-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/check-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/check-tri-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/check-tri-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/check-tri-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/check-unsel-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/check-unsel-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/check-unsel-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/check-unsel-pressed.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/combo-button-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/combo-button-focus.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/combo-button-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/down-focus.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/down.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/empty.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/hor-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/hor-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/hor-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/notebook.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/off-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/off-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/off-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/on-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/on-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/on-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/radio-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/radio-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/radio-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/radio-tri-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/radio-tri-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/radio-tri-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/radio-unsel-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/radio-unsel-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/radio-unsel-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/radio-unsel-pressed.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/rect-accent-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/rect-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/rect-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/rect-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/right-focus.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/right.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/scale-hor.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/scale-vert.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/separator.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/sizegrip.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/spin-button-down-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/spin-button-down-focus.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/spin-button-up.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/tab-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/tab-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/tab-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/thumb-hor-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/thumb-hor-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/thumb-hor-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/thumb-vert-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/thumb-vert-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/thumb-vert-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/tree-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/tree-pressed.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/up.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/vert-accent.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/vert-basic.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light/vert-hover.png +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/data/themes/forest/forest-light.tcl +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/datacopy.py +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/dev.py +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/security.py +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/splash.py +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/tk_utils.py +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/update_msix_version.py +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck/version_info.py +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck.egg-info/dependency_links.txt +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck.egg-info/entry_points.txt +0 -0
- {pdflinkcheck-1.2.29 → pdflinkcheck-1.3.8}/src/pdflinkcheck.egg-info/top_level.txt +0 -0
|
@@ -2,11 +2,11 @@ Some distributed binaries of this project include the PyMuPDF library, which is
|
|
|
2
2
|
Any binary that incorporates PyMuPDF is therefore distributed under **AGPL3.0orlater**.
|
|
3
3
|
Other binaries use only the `pypdf` library and do not include PyMuPDF; these binaries are distributed under the **MIT License**.
|
|
4
4
|
|
|
5
|
-
For
|
|
5
|
+
For AGPL-licensed binaries, the complete corresponding source code must be made available to anyone who possesses a copy, upon request.
|
|
6
6
|
This obligation applies only to recipients of those binaries, and hosting the source code in GitHub Releases satisfies this requirement.
|
|
7
7
|
|
|
8
|
-
A binary becomes
|
|
9
|
-
The **source code of pdflinkcheck itself** remains licensed under the **MIT License
|
|
8
|
+
A binary becomes AGPL-licensed only when built with the optional `"full"` dependency group (as defined in `pyproject.toml` under `[project.optional-dependencies]`) or when PyMuPDF is otherwise included in the build environment.
|
|
9
|
+
The **source code of pdflinkcheck itself** remains licensed under the **MIT License**. Only a distributed binary (or a publicly served web app) becomes AGPL-licensed when PyMuPDF is included.
|
|
10
10
|
|
|
11
11
|
Source code for each released version is available in the `pdflinkcheckVERSION.tar.gz` files on the projects GitHub Releases page.
|
|
12
12
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pdflinkcheck
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.8
|
|
4
4
|
Summary: A purpose-built PDF link analysis and reporting tool with GUI and CLI.
|
|
5
5
|
Author-email: George Clayton Bennett <george.bennett@memphistn.gov>
|
|
6
6
|
Maintainer-email: George Clayton Bennett <george.bennett@memphistn.gov>
|
|
@@ -34,12 +34,13 @@ Description-Content-Type: text/markdown
|
|
|
34
34
|
License-File: LICENSE
|
|
35
35
|
License-File: LICENSE-MIT
|
|
36
36
|
License-File: LICENSE-AGPL3
|
|
37
|
-
Requires-Dist:
|
|
37
|
+
Requires-Dist: openpyxl>=3.1.5
|
|
38
|
+
Requires-Dist: pyhabitat>=1.1.6
|
|
38
39
|
Requires-Dist: pypdf>=6.4.2
|
|
39
40
|
Requires-Dist: rich>=14.2.0
|
|
40
41
|
Requires-Dist: typer>=0.20.0
|
|
41
|
-
Provides-Extra:
|
|
42
|
-
Requires-Dist: pymupdf<2.0.0,>=1.24.0; extra == "
|
|
42
|
+
Provides-Extra: pymupdf
|
|
43
|
+
Requires-Dist: pymupdf<2.0.0,>=1.24.0; extra == "pymupdf"
|
|
43
44
|
Provides-Extra: pdfium
|
|
44
45
|
Requires-Dist: pypdfium2<6.0.0,>=5.2.0; extra == "pdfium"
|
|
45
46
|
Provides-Extra: full
|
|
@@ -51,9 +52,11 @@ Dynamic: license-file
|
|
|
51
52
|
|
|
52
53
|
A purpose-built tool for comprehensive analysis of hyperlinks and GoTo links within PDF documents. Users may leverage either the PyMuPDF or the pypdf library. Use the CLI or the GUI.
|
|
53
54
|
|
|
55
|
+
[](https://apps.microsoft.com/store/detail/9n11hxvls1wg)
|
|
56
|
+
|
|
54
57
|
-----
|
|
55
58
|
|
|
56
|
-

|
|
57
60
|
|
|
58
61
|
-----
|
|
59
62
|
|
|
@@ -102,7 +105,7 @@ Ways to launch the GUI interface:
|
|
|
102
105
|
The core functionality is accessed via the `analyze` command.
|
|
103
106
|
|
|
104
107
|
`pdflinkcheck --help`:
|
|
105
|
-

|
|
106
109
|
|
|
107
110
|
|
|
108
111
|
See the Help Tree by unlocking the help-tree CLI command, using the DEV_TYPER_HELP_TREE env var.
|
|
@@ -112,7 +115,7 @@ DEV_TYPER_HELP_TREE=1 pdflinkcheck help-tree` # bash
|
|
|
112
115
|
$env:DEV_TYPER_HELP_TREE = "1"; pdflinkcheck help-tree` # PowerShell
|
|
113
116
|
```
|
|
114
117
|
|
|
115
|
-

|
|
116
119
|
|
|
117
120
|
|
|
118
121
|
|
|
@@ -132,7 +135,7 @@ $env:DEV_TYPER_HELP_TREE = "1"; pdflinkcheck help-tree` # PowerShell
|
|
|
132
135
|
|---|---|---|
|
|
133
136
|
|`<PDF_PATH>`|**Required.** The path to the PDF file to analyze.|N/A|
|
|
134
137
|
|`--pdf-library / -p`|Select engine: `pymupdf` or `pypdf`.|`pypdf`|
|
|
135
|
-
|`--
|
|
138
|
+
|`--format / -f`|Export to `JSON`, `TXT`, `XLSX`, and/or `None` to suppress file output.|`JSON`|
|
|
136
139
|
|
|
137
140
|
### `gui` Command Options
|
|
138
141
|
|
|
@@ -143,8 +146,8 @@ $env:DEV_TYPER_HELP_TREE = "1"; pdflinkcheck help-tree` # PowerShell
|
|
|
143
146
|
#### Example Runs
|
|
144
147
|
|
|
145
148
|
```bash
|
|
146
|
-
# Analyze a document, show all links, and save the report as JSON and TXT
|
|
147
|
-
pdflinkcheck analyze "TE Maxson WWTF O&M Manual.pdf" --
|
|
149
|
+
# Analyze a document, show all links, and save the report as XLSX, JSON, and TXT
|
|
150
|
+
pdflinkcheck analyze "TE Maxson WWTF O&M Manual.pdf" --format xlsx -f json -f txt
|
|
148
151
|
|
|
149
152
|
# Show the GUI for only a moment, like in a build check
|
|
150
153
|
pdflinkcheck gui --auto-close 3000
|
|
@@ -177,8 +180,8 @@ from pdflinkcheck import ( run_report,
|
|
|
177
180
|
|
|
178
181
|
file = "document1.pdf"
|
|
179
182
|
report_data = run_report(file)
|
|
180
|
-
|
|
181
|
-
links_pypdf =
|
|
183
|
+
links_pdfium = analyze_pdf_pdfium(file)
|
|
184
|
+
links_pypdf = analyze_pdf_pypdf(file)
|
|
182
185
|
```
|
|
183
186
|
|
|
184
187
|
-----
|
|
@@ -254,7 +257,7 @@ Expecte that all binaries and artifacts contain PyMuPDF, unlss they are built on
|
|
|
254
257
|
To install the complete version use one of these options:
|
|
255
258
|
|
|
256
259
|
```bash
|
|
257
|
-
pip install "pdflinkcheck[
|
|
260
|
+
pip install "pdflinkcheck[pymupdf]"
|
|
258
261
|
pipx install "pdflinkcheck[pdfium]"
|
|
259
262
|
uv tool install "pdflinkcheck[pdfium]"
|
|
260
263
|
uv add "pdflinkcheck[pdfium]"
|
|
@@ -279,12 +282,12 @@ git clone http://github.com/city-of-memphis-wastewater/pdflinkcheck.git
|
|
|
279
282
|
cd pdflinkcheck
|
|
280
283
|
|
|
281
284
|
# To include the PyMuPDF dependency in the installation:
|
|
282
|
-
uv sync --extras
|
|
285
|
+
uv sync --extras pdfium --extra pymupdf
|
|
283
286
|
|
|
284
287
|
# On Termux, to not include PyMuPDF:
|
|
285
|
-
uv sync
|
|
288
|
+
uv sync --extra pdfium
|
|
286
289
|
|
|
287
|
-
# To include developer
|
|
290
|
+
# To include developer dependencies:
|
|
288
291
|
uv sync --all-extras --group dev
|
|
289
292
|
|
|
290
293
|
# Run the CLI
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
A purpose-built tool for comprehensive analysis of hyperlinks and GoTo links within PDF documents. Users may leverage either the PyMuPDF or the pypdf library. Use the CLI or the GUI.
|
|
4
4
|
|
|
5
|
+
[](https://apps.microsoft.com/store/detail/9n11hxvls1wg)
|
|
6
|
+
|
|
5
7
|
-----
|
|
6
8
|
|
|
7
|
-

|
|
8
10
|
|
|
9
11
|
-----
|
|
10
12
|
|
|
@@ -53,7 +55,7 @@ Ways to launch the GUI interface:
|
|
|
53
55
|
The core functionality is accessed via the `analyze` command.
|
|
54
56
|
|
|
55
57
|
`pdflinkcheck --help`:
|
|
56
|
-

|
|
57
59
|
|
|
58
60
|
|
|
59
61
|
See the Help Tree by unlocking the help-tree CLI command, using the DEV_TYPER_HELP_TREE env var.
|
|
@@ -63,7 +65,7 @@ DEV_TYPER_HELP_TREE=1 pdflinkcheck help-tree` # bash
|
|
|
63
65
|
$env:DEV_TYPER_HELP_TREE = "1"; pdflinkcheck help-tree` # PowerShell
|
|
64
66
|
```
|
|
65
67
|
|
|
66
|
-

|
|
67
69
|
|
|
68
70
|
|
|
69
71
|
|
|
@@ -83,7 +85,7 @@ $env:DEV_TYPER_HELP_TREE = "1"; pdflinkcheck help-tree` # PowerShell
|
|
|
83
85
|
|---|---|---|
|
|
84
86
|
|`<PDF_PATH>`|**Required.** The path to the PDF file to analyze.|N/A|
|
|
85
87
|
|`--pdf-library / -p`|Select engine: `pymupdf` or `pypdf`.|`pypdf`|
|
|
86
|
-
|`--
|
|
88
|
+
|`--format / -f`|Export to `JSON`, `TXT`, `XLSX`, and/or `None` to suppress file output.|`JSON`|
|
|
87
89
|
|
|
88
90
|
### `gui` Command Options
|
|
89
91
|
|
|
@@ -94,8 +96,8 @@ $env:DEV_TYPER_HELP_TREE = "1"; pdflinkcheck help-tree` # PowerShell
|
|
|
94
96
|
#### Example Runs
|
|
95
97
|
|
|
96
98
|
```bash
|
|
97
|
-
# Analyze a document, show all links, and save the report as JSON and TXT
|
|
98
|
-
pdflinkcheck analyze "TE Maxson WWTF O&M Manual.pdf" --
|
|
99
|
+
# Analyze a document, show all links, and save the report as XLSX, JSON, and TXT
|
|
100
|
+
pdflinkcheck analyze "TE Maxson WWTF O&M Manual.pdf" --format xlsx -f json -f txt
|
|
99
101
|
|
|
100
102
|
# Show the GUI for only a moment, like in a build check
|
|
101
103
|
pdflinkcheck gui --auto-close 3000
|
|
@@ -128,8 +130,8 @@ from pdflinkcheck import ( run_report,
|
|
|
128
130
|
|
|
129
131
|
file = "document1.pdf"
|
|
130
132
|
report_data = run_report(file)
|
|
131
|
-
|
|
132
|
-
links_pypdf =
|
|
133
|
+
links_pdfium = analyze_pdf_pdfium(file)
|
|
134
|
+
links_pypdf = analyze_pdf_pypdf(file)
|
|
133
135
|
```
|
|
134
136
|
|
|
135
137
|
-----
|
|
@@ -205,7 +207,7 @@ Expecte that all binaries and artifacts contain PyMuPDF, unlss they are built on
|
|
|
205
207
|
To install the complete version use one of these options:
|
|
206
208
|
|
|
207
209
|
```bash
|
|
208
|
-
pip install "pdflinkcheck[
|
|
210
|
+
pip install "pdflinkcheck[pymupdf]"
|
|
209
211
|
pipx install "pdflinkcheck[pdfium]"
|
|
210
212
|
uv tool install "pdflinkcheck[pdfium]"
|
|
211
213
|
uv add "pdflinkcheck[pdfium]"
|
|
@@ -230,12 +232,12 @@ git clone http://github.com/city-of-memphis-wastewater/pdflinkcheck.git
|
|
|
230
232
|
cd pdflinkcheck
|
|
231
233
|
|
|
232
234
|
# To include the PyMuPDF dependency in the installation:
|
|
233
|
-
uv sync --extras
|
|
235
|
+
uv sync --extras pdfium --extra pymupdf
|
|
234
236
|
|
|
235
237
|
# On Termux, to not include PyMuPDF:
|
|
236
|
-
uv sync
|
|
238
|
+
uv sync --extra pdfium
|
|
237
239
|
|
|
238
|
-
# To include developer
|
|
240
|
+
# To include developer dependencies:
|
|
239
241
|
uv sync --all-extras --group dev
|
|
240
242
|
|
|
241
243
|
# Run the CLI
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "pdflinkcheck"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.3.8"
|
|
4
4
|
description = "A purpose-built PDF link analysis and reporting tool with GUI and CLI."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.9"
|
|
7
7
|
dependencies = [
|
|
8
|
-
"
|
|
8
|
+
"openpyxl>=3.1.5",
|
|
9
|
+
"pyhabitat>=1.1.6",
|
|
9
10
|
"pypdf>=6.4.2",
|
|
10
11
|
"rich>=14.2.0",
|
|
11
12
|
"typer>=0.20.0",
|
|
@@ -56,7 +57,7 @@ pdflinkcheck = "pdflinkcheck.cli:app"
|
|
|
56
57
|
|
|
57
58
|
[project.optional-dependencies]
|
|
58
59
|
# If you choose to include PyMuPDF, you must comply with the AGPL3
|
|
59
|
-
|
|
60
|
+
pymupdf = ["pymupdf>=1.24.0,<2.0.0"] # fails on termux
|
|
60
61
|
pdfium = ["pypdfium2>=5.2.0,<6.0.0"]
|
|
61
62
|
full = ["pymupdf>=1.24.0,<2.0.0", "pypdfium2>=5.2.0,<6.0.0"]
|
|
62
63
|
|
|
@@ -49,7 +49,7 @@ def analyze_pdf_pymupdf(path):
|
|
|
49
49
|
except ImportError:
|
|
50
50
|
raise ImportError(
|
|
51
51
|
"PyMuPDF engine is not installed. "
|
|
52
|
-
"Install with the [
|
|
52
|
+
"Install with the [pymupdf] extra to enable PyMuPDF support."
|
|
53
53
|
)
|
|
54
54
|
return _analyze(path)
|
|
55
55
|
analyze_pdf_pymupdf.__doc__ = (
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# src/pdflinkcheck/cli.py
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
import typer
|
|
6
|
-
from typing import Literal
|
|
6
|
+
from typing import Literal, List
|
|
7
7
|
from typer.models import OptionInfo
|
|
8
8
|
from rich.console import Console
|
|
9
9
|
from pathlib import Path
|
|
@@ -13,10 +13,10 @@ import pyhabitat
|
|
|
13
13
|
import sys
|
|
14
14
|
import os
|
|
15
15
|
from importlib.resources import files
|
|
16
|
+
from enum import Enum
|
|
16
17
|
|
|
17
18
|
from pdflinkcheck.version_info import get_version_from_pyproject
|
|
18
|
-
from pdflinkcheck.
|
|
19
|
-
from pdflinkcheck.environment import is_in_git_repo, assess_default_pdf_library
|
|
19
|
+
from pdflinkcheck.environment import is_in_git_repo, assess_default_pdf_library, pymupdf_is_available, pdfium_is_available
|
|
20
20
|
from pdflinkcheck.io import get_first_pdf_in_cwd
|
|
21
21
|
|
|
22
22
|
console = Console() # to be above the tkinter check, in case of console.print
|
|
@@ -37,6 +37,13 @@ app = typer.Typer(
|
|
|
37
37
|
"help_option_names": ["-h", "--help"]},
|
|
38
38
|
)
|
|
39
39
|
|
|
40
|
+
class ExportFormat(str, Enum):
|
|
41
|
+
json = "json"
|
|
42
|
+
txt = "txt"
|
|
43
|
+
xlsx = "xlsx"
|
|
44
|
+
none = "none"
|
|
45
|
+
|
|
46
|
+
ALLOWED_EXPORTS = {"json", "txt", "xlsx", "none"}
|
|
40
47
|
|
|
41
48
|
def debug_callback(value: bool):
|
|
42
49
|
#def debug_callback(ctx: typer.Context, value: bool):
|
|
@@ -50,8 +57,36 @@ def debug_callback(value: bool):
|
|
|
50
57
|
typer.echo(f"command:\n{command_string}\n")
|
|
51
58
|
return value
|
|
52
59
|
|
|
53
|
-
if "--show-command" in sys.argv or "--debug" in sys.argv:
|
|
60
|
+
if "--show-command" in sys.argv or "--debug" in sys.argv: # requires that --show-command flag be used before the sub command
|
|
54
61
|
debug_callback(True)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _parse_export_formats(value: str) -> List[str]:
|
|
66
|
+
"""
|
|
67
|
+
Parse a comma-separated string of export formats, validate allowed values.
|
|
68
|
+
Converts everything to lowercase.
|
|
69
|
+
"""
|
|
70
|
+
if not value:
|
|
71
|
+
return []
|
|
72
|
+
|
|
73
|
+
# Split by comma and normalize
|
|
74
|
+
parts = [v.strip().lower() for v in value.split(",")]
|
|
75
|
+
|
|
76
|
+
# Validate
|
|
77
|
+
invalid = [v for v in parts if v not in ALLOWED_EXPORTS]
|
|
78
|
+
if invalid:
|
|
79
|
+
raise typer.BadParameter(
|
|
80
|
+
f"Invalid export format(s): {', '.join(invalid)}. "
|
|
81
|
+
f"Allowed values: {', '.join(sorted(ALLOWED_EXPORTS))}"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# If 'none' is included, return empty list to suppress exports
|
|
85
|
+
if "none" in parts:
|
|
86
|
+
return []
|
|
87
|
+
|
|
88
|
+
return parts
|
|
89
|
+
|
|
55
90
|
|
|
56
91
|
@app.callback()
|
|
57
92
|
def main(ctx: typer.Context,
|
|
@@ -136,8 +171,8 @@ def docs_command(
|
|
|
136
171
|
|
|
137
172
|
# Exit successfully if any flag was processed
|
|
138
173
|
raise typer.Exit(code=0)
|
|
139
|
-
|
|
140
|
-
@app.command(name="
|
|
174
|
+
"""
|
|
175
|
+
@app.command(name="tools_defunct", help= "Additional features, hamburger menu.")
|
|
141
176
|
def tools_command(
|
|
142
177
|
clear_cache: bool = typer.Option(
|
|
143
178
|
False,
|
|
@@ -149,6 +184,34 @@ def tools_command(
|
|
|
149
184
|
from pdflinkcheck.environment import clear_all_caches
|
|
150
185
|
if clear_cache:
|
|
151
186
|
clear_all_caches()
|
|
187
|
+
"""
|
|
188
|
+
# Create the sub-group
|
|
189
|
+
tools_app = typer.Typer(help="Additional utility features and maintenance tools.")
|
|
190
|
+
app.add_typer(tools_app, name="tools")
|
|
191
|
+
|
|
192
|
+
@tools_app.command(name="clear-cache")
|
|
193
|
+
def tools_clear_cache():
|
|
194
|
+
"""Clear the environment and engine discovery caches."""
|
|
195
|
+
from pdflinkcheck.environment import clear_all_caches
|
|
196
|
+
clear_all_caches()
|
|
197
|
+
console.print("[green]Discovery caches cleared.[/green]")
|
|
198
|
+
console.print(f"pymupdf_is_available: {pymupdf_is_available()}")
|
|
199
|
+
console.print(f"pymupdf_is_available: {pdfium_is_available()}")
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
@tools_app.command(name="browse-exports")
|
|
203
|
+
def tools_browse_exports():
|
|
204
|
+
"""Open the system file explorer at the report output directory."""
|
|
205
|
+
from pdflinkcheck.helpers import show_system_explorer, get_export_path
|
|
206
|
+
|
|
207
|
+
target_dir = get_export_path()
|
|
208
|
+
console.print(f"Opening: [bold cyan]{target_dir}[/bold cyan]")
|
|
209
|
+
|
|
210
|
+
try:
|
|
211
|
+
show_system_explorer()
|
|
212
|
+
except Exception as e:
|
|
213
|
+
console.print(f"[bold red]Error:[/bold red] {e}")
|
|
214
|
+
raise typer.Exit(code=1)
|
|
152
215
|
|
|
153
216
|
@app.command(name="analyze") # Added a command name 'analyze' for clarity
|
|
154
217
|
def analyze_pdf( # Renamed function for clarity
|
|
@@ -161,11 +224,25 @@ def analyze_pdf( # Renamed function for clarity
|
|
|
161
224
|
resolve_path=True,
|
|
162
225
|
help="Path to the PDF file to analyze. If omitted, searches current directory."
|
|
163
226
|
),
|
|
164
|
-
export_format: Optional[Literal["JSON", "TXT", "JSON,TXT", "NONE"]] = typer.Option(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
227
|
+
#export_format: Optional[Literal["JSON", "TXT", "XLSX", "JSON,TXT,XLSX", "NONE"]] = typer.Option(
|
|
228
|
+
#export_format: str = typer.Option(
|
|
229
|
+
# "json,txt,xlsx",
|
|
230
|
+
# "--format","-f",
|
|
231
|
+
# case_sensitive=False,
|
|
232
|
+
# help="Export format. Use 'None' to suppress file export.",
|
|
233
|
+
#),
|
|
234
|
+
#export_format: List[str] = typer.Option(
|
|
235
|
+
# ["json", "txt", "xlsx"],
|
|
236
|
+
# "--format", "-f",
|
|
237
|
+
# case_sensitive=False,
|
|
238
|
+
# callback=_parse_export_formats,
|
|
239
|
+
# help="Comma-separated list of export formats. Allowed: json, txt, xlsx, none."
|
|
240
|
+
#),
|
|
241
|
+
export_format: List[ExportFormat] = typer.Option(
|
|
242
|
+
[ExportFormat.json, ExportFormat.txt, ExportFormat.xlsx],
|
|
243
|
+
"--format", "-f",
|
|
244
|
+
case_sensitive=False,
|
|
245
|
+
help="Export formats (repeatable). Use --format none to suppress all exports."
|
|
169
246
|
),
|
|
170
247
|
|
|
171
248
|
pdf_library: Literal["auto","pdfium","pypdf", "pymupdf"] = typer.Option(
|
|
@@ -213,44 +290,49 @@ def analyze_pdf( # Renamed function for clarity
|
|
|
213
290
|
raise typer.Exit(code=1)
|
|
214
291
|
console.print(f"[dim]No file specified — using: {Path(pdf_path).name}[/dim]")
|
|
215
292
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
293
|
+
|
|
294
|
+
if ExportFormat.none in export_format:
|
|
295
|
+
export_formats = []
|
|
296
|
+
else:
|
|
297
|
+
export_formats = [f.name.upper() for f in export_format]
|
|
298
|
+
export_format="".join(export_formats)
|
|
299
|
+
"""#VALID_FORMATS = ("JSON","TXT") # extend later
|
|
219
300
|
requested_formats = [fmt.strip().upper() for fmt in export_format.split(",")]
|
|
220
301
|
if "NONE" in requested_formats or not export_format.strip() or export_format == "0":
|
|
221
302
|
export_formats = ""
|
|
222
303
|
else:
|
|
223
304
|
# Filter for valid ones: ("JSON", "TXT")
|
|
224
305
|
# This allows "JSON,TXT" to become "JSONTXT" which run_report logic can handle
|
|
225
|
-
valid = [f for f in requested_formats if f in ("JSON", "TXT")]
|
|
306
|
+
valid = [f for f in requested_formats if f in ("JSON", "TXT", "XLSX")]
|
|
226
307
|
export_formats = "".join(valid)
|
|
227
308
|
|
|
228
309
|
if not valid and "NONE" not in requested_formats:
|
|
229
310
|
typer.echo(f"Warning: No valid formats found in '{export_format}'. Supported: JSON, TXT.")
|
|
230
|
-
|
|
311
|
+
"""
|
|
231
312
|
|
|
232
313
|
# The meat and potatoes
|
|
233
314
|
report_results = run_report_and_call_exports(
|
|
234
315
|
pdf_path=str(pdf_path),
|
|
235
|
-
export_format =
|
|
316
|
+
export_format = export_format,
|
|
236
317
|
pdf_library = pdf_library,
|
|
237
318
|
print_bool = print_bool,
|
|
319
|
+
concise_print = True, # ideal for CLI, to not overwhelm the terminal.
|
|
238
320
|
)
|
|
239
321
|
|
|
240
322
|
if not report_results or not report_results.get("data"):
|
|
241
323
|
console.print("[yellow]No links or TOC found — nothing to validate.[/yellow]")
|
|
242
324
|
raise typer.Exit(code=0)
|
|
243
325
|
|
|
244
|
-
validation_results = report_results["data"]["validation"]
|
|
326
|
+
#validation_results = report_results["data"]["validation"]
|
|
245
327
|
# Optional: fail on broken links
|
|
246
|
-
broken_page_count = validation_results["summary-stats"]["broken-page"] + validation_results["summary-stats"]["broken-file"]
|
|
328
|
+
#broken_page_count = validation_results["summary-stats"]["broken-page"] + validation_results["summary-stats"]["broken-file"]
|
|
247
329
|
|
|
248
|
-
if broken_page_count > 0:
|
|
330
|
+
#if broken_page_count > 0:
|
|
249
331
|
console.print(f"\n[bold yellow]Warning:[/bold yellow] {broken_page_count} broken link(s) found.")
|
|
250
332
|
#else:
|
|
251
333
|
# console.print(f"\n[bold green]Success:[/bold green] No broken links or TOC issues!\n")
|
|
252
334
|
|
|
253
|
-
raise typer.Exit(code=0 if broken_page_count == 0 else 1)
|
|
335
|
+
#raise typer.Exit(code=0 if broken_page_count == 0 else 1)
|
|
254
336
|
|
|
255
337
|
@app.command(name="serve")
|
|
256
338
|
def serve(
|
|
@@ -270,13 +352,14 @@ def serve(
|
|
|
270
352
|
console.print(" → [yellow]Reload mode enabled[/yellow]")
|
|
271
353
|
|
|
272
354
|
# Import here to avoid slow imports on other commands
|
|
273
|
-
from pdflinkcheck.
|
|
355
|
+
from pdflinkcheck.stdlib_server import main as stdlib_server_main# ThreadedHTTPServer, PDFLinkCheckHandler
|
|
274
356
|
import socketserver
|
|
275
357
|
|
|
276
358
|
try:
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
359
|
+
stdlib_server_main()
|
|
360
|
+
#with ThreadedTCPServer((host, port), PDFLinkCheckHandler) as httpd:
|
|
361
|
+
# console.print(f"[green]Server running — press Ctrl+C to stop[/green]\n")
|
|
362
|
+
# httpd.serve_forever()
|
|
280
363
|
except OSError as e:
|
|
281
364
|
if "Address already in use" in str(e):
|
|
282
365
|
console.print(f"[red]Error: Port {port} is already in use.[/red]")
|
|
@@ -314,8 +397,7 @@ def gui_command(
|
|
|
314
397
|
if not pyhabitat.tkinter_is_available():
|
|
315
398
|
_gui_failure_msg()
|
|
316
399
|
return
|
|
317
|
-
|
|
318
|
-
#from pdflinkcheck.gui_alt import start_gui
|
|
400
|
+
|
|
319
401
|
from pdflinkcheck.gui import start_gui
|
|
320
402
|
start_gui(time_auto_close = assured_auto_close_value)
|
|
321
403
|
|
|
@@ -329,6 +411,8 @@ def _gui_failure_msg():
|
|
|
329
411
|
console.print(f"pyhabitat.tkinter_is_available() = {pyhabitat.tkinter_is_available()}")
|
|
330
412
|
pass
|
|
331
413
|
|
|
414
|
+
|
|
415
|
+
|
|
332
416
|
if __name__ == "__main__":
|
|
333
417
|
app()
|
|
334
418
|
|
|
@@ -2,11 +2,11 @@ Some distributed binaries of this project include the PyMuPDF library, which is
|
|
|
2
2
|
Any binary that incorporates PyMuPDF is therefore distributed under **AGPL3.0orlater**.
|
|
3
3
|
Other binaries use only the `pypdf` library and do not include PyMuPDF; these binaries are distributed under the **MIT License**.
|
|
4
4
|
|
|
5
|
-
For
|
|
5
|
+
For AGPL-licensed binaries, the complete corresponding source code must be made available to anyone who possesses a copy, upon request.
|
|
6
6
|
This obligation applies only to recipients of those binaries, and hosting the source code in GitHub Releases satisfies this requirement.
|
|
7
7
|
|
|
8
|
-
A binary becomes
|
|
9
|
-
The **source code of pdflinkcheck itself** remains licensed under the **MIT License
|
|
8
|
+
A binary becomes AGPL-licensed only when built with the optional `"full"` dependency group (as defined in `pyproject.toml` under `[project.optional-dependencies]`) or when PyMuPDF is otherwise included in the build environment.
|
|
9
|
+
The **source code of pdflinkcheck itself** remains licensed under the **MIT License**. Only a distributed binary (or a publicly served web app) becomes AGPL-licensed when PyMuPDF is included.
|
|
10
10
|
|
|
11
11
|
Source code for each released version is available in the `pdflinkcheckVERSION.tar.gz` files on the projects GitHub Releases page.
|
|
12
12
|
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
A purpose-built tool for comprehensive analysis of hyperlinks and GoTo links within PDF documents. Users may leverage either the PyMuPDF or the pypdf library. Use the CLI or the GUI.
|
|
4
4
|
|
|
5
|
+
[](https://apps.microsoft.com/store/detail/9n11hxvls1wg)
|
|
6
|
+
|
|
5
7
|
-----
|
|
6
8
|
|
|
7
|
-

|
|
8
10
|
|
|
9
11
|
-----
|
|
10
12
|
|
|
@@ -53,7 +55,7 @@ Ways to launch the GUI interface:
|
|
|
53
55
|
The core functionality is accessed via the `analyze` command.
|
|
54
56
|
|
|
55
57
|
`pdflinkcheck --help`:
|
|
56
|
-

|
|
57
59
|
|
|
58
60
|
|
|
59
61
|
See the Help Tree by unlocking the help-tree CLI command, using the DEV_TYPER_HELP_TREE env var.
|
|
@@ -63,7 +65,7 @@ DEV_TYPER_HELP_TREE=1 pdflinkcheck help-tree` # bash
|
|
|
63
65
|
$env:DEV_TYPER_HELP_TREE = "1"; pdflinkcheck help-tree` # PowerShell
|
|
64
66
|
```
|
|
65
67
|
|
|
66
|
-

|
|
67
69
|
|
|
68
70
|
|
|
69
71
|
|
|
@@ -83,7 +85,7 @@ $env:DEV_TYPER_HELP_TREE = "1"; pdflinkcheck help-tree` # PowerShell
|
|
|
83
85
|
|---|---|---|
|
|
84
86
|
|`<PDF_PATH>`|**Required.** The path to the PDF file to analyze.|N/A|
|
|
85
87
|
|`--pdf-library / -p`|Select engine: `pymupdf` or `pypdf`.|`pypdf`|
|
|
86
|
-
|`--
|
|
88
|
+
|`--format / -f`|Export to `JSON`, `TXT`, `XLSX`, and/or `None` to suppress file output.|`JSON`|
|
|
87
89
|
|
|
88
90
|
### `gui` Command Options
|
|
89
91
|
|
|
@@ -94,8 +96,8 @@ $env:DEV_TYPER_HELP_TREE = "1"; pdflinkcheck help-tree` # PowerShell
|
|
|
94
96
|
#### Example Runs
|
|
95
97
|
|
|
96
98
|
```bash
|
|
97
|
-
# Analyze a document, show all links, and save the report as JSON and TXT
|
|
98
|
-
pdflinkcheck analyze "TE Maxson WWTF O&M Manual.pdf" --
|
|
99
|
+
# Analyze a document, show all links, and save the report as XLSX, JSON, and TXT
|
|
100
|
+
pdflinkcheck analyze "TE Maxson WWTF O&M Manual.pdf" --format xlsx -f json -f txt
|
|
99
101
|
|
|
100
102
|
# Show the GUI for only a moment, like in a build check
|
|
101
103
|
pdflinkcheck gui --auto-close 3000
|
|
@@ -128,8 +130,8 @@ from pdflinkcheck import ( run_report,
|
|
|
128
130
|
|
|
129
131
|
file = "document1.pdf"
|
|
130
132
|
report_data = run_report(file)
|
|
131
|
-
|
|
132
|
-
links_pypdf =
|
|
133
|
+
links_pdfium = analyze_pdf_pdfium(file)
|
|
134
|
+
links_pypdf = analyze_pdf_pypdf(file)
|
|
133
135
|
```
|
|
134
136
|
|
|
135
137
|
-----
|
|
@@ -205,7 +207,7 @@ Expecte that all binaries and artifacts contain PyMuPDF, unlss they are built on
|
|
|
205
207
|
To install the complete version use one of these options:
|
|
206
208
|
|
|
207
209
|
```bash
|
|
208
|
-
pip install "pdflinkcheck[
|
|
210
|
+
pip install "pdflinkcheck[pymupdf]"
|
|
209
211
|
pipx install "pdflinkcheck[pdfium]"
|
|
210
212
|
uv tool install "pdflinkcheck[pdfium]"
|
|
211
213
|
uv add "pdflinkcheck[pdfium]"
|
|
@@ -230,12 +232,12 @@ git clone http://github.com/city-of-memphis-wastewater/pdflinkcheck.git
|
|
|
230
232
|
cd pdflinkcheck
|
|
231
233
|
|
|
232
234
|
# To include the PyMuPDF dependency in the installation:
|
|
233
|
-
uv sync --extras
|
|
235
|
+
uv sync --extras pdfium --extra pymupdf
|
|
234
236
|
|
|
235
237
|
# On Termux, to not include PyMuPDF:
|
|
236
|
-
uv sync
|
|
238
|
+
uv sync --extra pdfium
|
|
237
239
|
|
|
238
|
-
# To include developer
|
|
240
|
+
# To include developer dependencies:
|
|
239
241
|
uv sync --all-extras --group dev
|
|
240
242
|
|
|
241
243
|
# Run the CLI
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "pdflinkcheck"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.3.8"
|
|
4
4
|
description = "A purpose-built PDF link analysis and reporting tool with GUI and CLI."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.9"
|
|
7
7
|
dependencies = [
|
|
8
|
-
"
|
|
8
|
+
"openpyxl>=3.1.5",
|
|
9
|
+
"pyhabitat>=1.1.6",
|
|
9
10
|
"pypdf>=6.4.2",
|
|
10
11
|
"rich>=14.2.0",
|
|
11
12
|
"typer>=0.20.0",
|
|
@@ -56,7 +57,7 @@ pdflinkcheck = "pdflinkcheck.cli:app"
|
|
|
56
57
|
|
|
57
58
|
[project.optional-dependencies]
|
|
58
59
|
# If you choose to include PyMuPDF, you must comply with the AGPL3
|
|
59
|
-
|
|
60
|
+
pymupdf = ["pymupdf>=1.24.0,<2.0.0"] # fails on termux
|
|
60
61
|
pdfium = ["pypdfium2>=5.2.0,<6.0.0"]
|
|
61
62
|
full = ["pymupdf>=1.24.0,<2.0.0", "pypdfium2>=5.2.0,<6.0.0"]
|
|
62
63
|
|