pdflinkcheck 1.1.73__py3-none-any.whl → 1.2.29__py3-none-any.whl
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/__init__.py +88 -21
- pdflinkcheck/__main__.py +6 -0
- pdflinkcheck/analysis_pdfium.py +131 -0
- pdflinkcheck/{analyze_pymupdf.py → analysis_pymupdf.py} +109 -145
- pdflinkcheck/{analyze_pypdf.py → analysis_pypdf.py} +67 -37
- pdflinkcheck/cli.py +111 -116
- pdflinkcheck/data/I Have Questions.md +51 -0
- pdflinkcheck/data/LICENSE +20 -654
- pdflinkcheck/data/README.md +65 -67
- pdflinkcheck/data/icons/BoxArt-1080x1080.png +0 -0
- pdflinkcheck/data/icons/Logo-150x150.png +0 -0
- pdflinkcheck/data/icons/Logo-300x300.png +0 -0
- pdflinkcheck/data/icons/Logo-71x71.png +0 -0
- pdflinkcheck/data/icons/PosterArt-720x1080.png +0 -0
- pdflinkcheck/data/icons/SmallLogo-44x44.png +0 -0
- pdflinkcheck/data/icons/SplashScreen-620x300.png +0 -0
- pdflinkcheck/data/icons/StoreLogo-50x50.png +0 -0
- pdflinkcheck/data/icons/WideLogo-310x150.png +0 -0
- pdflinkcheck/data/icons/red_pdf_512px.ico +0 -0
- pdflinkcheck/data/pyproject.toml +25 -37
- pdflinkcheck/data/themes/forest/forest-dark/border-accent-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/border-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/border-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/border-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/border-invalid.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/card.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/check-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/check-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/check-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/check-tri-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/check-tri-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/check-tri-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/check-unsel-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/check-unsel-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/check-unsel-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/check-unsel-pressed.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/combo-button-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/combo-button-focus.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/combo-button-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/down.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/empty.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/hor-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/hor-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/hor-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/notebook.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/off-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/off-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/off-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/on-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/on-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/on-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/radio-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/radio-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/radio-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/radio-tri-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/radio-tri-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/radio-tri-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/radio-unsel-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/radio-unsel-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/radio-unsel-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/radio-unsel-pressed.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/rect-accent-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/rect-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/rect-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/rect-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/right.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/scale-hor.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/scale-vert.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/separator.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/sizegrip.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/spin-button-down-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/spin-button-down-focus.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/spin-button-up.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/tab-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/tab-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/tab-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/thumb-hor-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/thumb-hor-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/thumb-hor-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/thumb-vert-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/thumb-vert-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/thumb-vert-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/tree-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/tree-pressed.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/up.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/vert-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/vert-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark/vert-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-dark.tcl +536 -0
- pdflinkcheck/data/themes/forest/forest-light/border-accent-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/border-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/border-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/border-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/border-invalid.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/card.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/check-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/check-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/check-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/check-tri-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/check-tri-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/check-tri-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/check-unsel-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/check-unsel-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/check-unsel-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/check-unsel-pressed.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/combo-button-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/combo-button-focus.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/combo-button-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/down-focus.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/down.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/empty.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/hor-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/hor-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/hor-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/notebook.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/off-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/off-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/off-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/on-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/on-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/on-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/radio-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/radio-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/radio-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/radio-tri-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/radio-tri-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/radio-tri-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/radio-unsel-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/radio-unsel-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/radio-unsel-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/radio-unsel-pressed.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/rect-accent-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/rect-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/rect-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/rect-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/right-focus.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/right.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/scale-hor.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/scale-vert.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/separator.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/sizegrip.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/spin-button-down-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/spin-button-down-focus.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/spin-button-up.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/tab-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/tab-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/tab-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/thumb-hor-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/thumb-hor-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/thumb-hor-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/thumb-vert-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/thumb-vert-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/thumb-vert-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/tree-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/tree-pressed.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/up.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/vert-accent.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/vert-basic.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light/vert-hover.png +0 -0
- pdflinkcheck/data/themes/forest/forest-light.tcl +544 -0
- pdflinkcheck/datacopy.py +18 -1
- pdflinkcheck/dev.py +12 -25
- pdflinkcheck/environment.py +76 -0
- pdflinkcheck/gui.py +366 -457
- pdflinkcheck/helpers.py +88 -0
- pdflinkcheck/io.py +27 -23
- pdflinkcheck/report.py +692 -121
- pdflinkcheck/security.py +189 -0
- pdflinkcheck/splash.py +38 -0
- pdflinkcheck/stdlib_server.py +14 -20
- pdflinkcheck/stdlib_server_alt.py +571 -0
- pdflinkcheck/tk_utils.py +188 -0
- pdflinkcheck/update_msix_version.py +49 -0
- pdflinkcheck/validate.py +129 -218
- pdflinkcheck/version_info.py +6 -3
- {pdflinkcheck-1.1.73.dist-info → pdflinkcheck-1.2.29.dist-info}/METADATA +84 -81
- pdflinkcheck-1.2.29.dist-info/RECORD +183 -0
- pdflinkcheck-1.2.29.dist-info/WHEEL +5 -0
- {pdflinkcheck-1.1.73.dist-info → pdflinkcheck-1.2.29.dist-info}/entry_points.txt +0 -1
- pdflinkcheck-1.2.29.dist-info/licenses/LICENSE +27 -0
- pdflinkcheck-1.2.29.dist-info/licenses/LICENSE-MIT +9 -0
- pdflinkcheck-1.2.29.dist-info/top_level.txt +1 -0
- pdflinkcheck/analyze_pypdf_v2.py +0 -218
- pdflinkcheck-1.1.73.dist-info/RECORD +0 -21
- pdflinkcheck-1.1.73.dist-info/WHEEL +0 -4
- /pdflinkcheck-1.1.73.dist-info/licenses/LICENSE → /pdflinkcheck-1.2.29.dist-info/licenses/LICENSE-AGPL3 +0 -0
pdflinkcheck/helpers.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# src/pdflinkcheck/helpers.py
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
from pprint import pprint
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
Helper functions
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
def debug_head(label: str, data: Any, n: int = 3):
|
|
11
|
+
"""Helper to cleanly print the first N items of a list or dict."""
|
|
12
|
+
print(f"\n--- [DEBUG: {label}] ---")
|
|
13
|
+
if isinstance(data, list):
|
|
14
|
+
pprint(data[:n], indent=2, compact=True, width=100)
|
|
15
|
+
elif isinstance(data, dict):
|
|
16
|
+
# Print first N keys
|
|
17
|
+
head_dict = {k: data[k] for k in list(data.keys())[:n]}
|
|
18
|
+
pprint(head_dict, indent=2, compact=True, width=100)
|
|
19
|
+
else:
|
|
20
|
+
print(data)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class PageRef:
|
|
24
|
+
"""
|
|
25
|
+
A simple translator to handle the 0-to-1 index conversion
|
|
26
|
+
without the 'Double Bump' risk.
|
|
27
|
+
"""
|
|
28
|
+
def __init__(self, index: int):
|
|
29
|
+
self.index = index # The 0-based physical index
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def human(self) -> int:
|
|
33
|
+
"""The 1-based page number for humans."""
|
|
34
|
+
return self.index + 1
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def machine(self) -> int:
|
|
38
|
+
"""Alias for index. The 0-based page number for machines."""
|
|
39
|
+
return self.index
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@classmethod
|
|
43
|
+
def corrected_down(cls, human_num: int) -> "PageRef":
|
|
44
|
+
"""Explicitly compensates for 1-based data (e.g., PyMuPDF TOC)."""
|
|
45
|
+
return cls.from_human(human_num)
|
|
46
|
+
|
|
47
|
+
@classmethod
|
|
48
|
+
def from_pymupdf_total_page_count(cls, total_pages: int) -> "PageRef":
|
|
49
|
+
"""
|
|
50
|
+
Converts PyMuPDF's doc.page_count into a PageRef
|
|
51
|
+
representing the final valid machine-facing index.
|
|
52
|
+
"""
|
|
53
|
+
return cls.from_human(total_pages)
|
|
54
|
+
|
|
55
|
+
@classmethod
|
|
56
|
+
def from_human(cls, human_num: int) -> "PageRef":
|
|
57
|
+
"""Creates a PageRef from a 1-based human page number (e.g., from TOC)."""
|
|
58
|
+
return cls(human_num - 1)
|
|
59
|
+
|
|
60
|
+
@classmethod
|
|
61
|
+
def from_index(cls, physical_index: int) -> "PageRef":
|
|
62
|
+
"""Creates a PageRef from a 0-based physical index (e.g., from links)."""
|
|
63
|
+
return cls(physical_index)
|
|
64
|
+
|
|
65
|
+
def __int__(self):
|
|
66
|
+
return self.index
|
|
67
|
+
|
|
68
|
+
def __str__(self):
|
|
69
|
+
return str(self.human)
|
|
70
|
+
|
|
71
|
+
def __repr__(self):
|
|
72
|
+
return f"PageRef(index={self.index}, human={self.human})"
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
"""
|
|
76
|
+
### Indexing Map: Physical (0) vs. Logical (1)
|
|
77
|
+
|
|
78
|
+
| **File** | **Context** | **Index Rule** | **Reasoning** |
|
|
79
|
+
| --------------------- | ---------------- | ------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
80
|
+
| `ffi.py` (Rust bridge)| Data Extraction | **0-indexing only** | Rust's `pdf-extract` and `lopdf` crates are 0-indexed. Data should stay raw. |
|
|
81
|
+
| `analysis_pypdf.py` | Data Extraction | **0-indexing only** | `pypdf` is 0-indexed. Your previous `+ 1` hacks have been removed. |
|
|
82
|
+
| `analysis_pymupdf.py` | Data Extraction | **Mixed** | **Internal:** 0-indexed. **TOC:** `get_toc()` is natively 1-indexed. Needs normalization. |
|
|
83
|
+
| `validate.py` | Logic/Validation | **Mixed** | **Logic:** Uses `START_INDEX=0` for boundary checks. **Strings:** Formats error messages as 1-indexed. |
|
|
84
|
+
| `report.py` | Output/Reporting | **Mixed** | **Data:** Keeps dictionary values at 0. **Display:** Formats CLI tables as 1-indexed. |
|
|
85
|
+
| `helpers.py` | Translation | **Mixed** | The `PageRef` class acts as the "Border Control" between 0 and 1. |
|
|
86
|
+
| `__init__.py` | API Surface | **0-indexing only** | If exposing a library, users expect 0-indexed lists of pages/links. |
|
|
87
|
+
|
|
88
|
+
"""
|
pdflinkcheck/io.py
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
1
3
|
# src/pdflinkcheck/io.py
|
|
4
|
+
from __future__ import annotations
|
|
2
5
|
import logging
|
|
3
6
|
import json
|
|
4
7
|
import sys
|
|
5
8
|
from pathlib import Path
|
|
6
9
|
from typing import Dict, Any, Union, List, Optional
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
import time
|
|
7
12
|
|
|
8
13
|
# --- Configuration ---
|
|
9
14
|
|
|
@@ -112,13 +117,15 @@ def export_report_json(
|
|
|
112
117
|
pdf_library: str
|
|
113
118
|
) -> Path:
|
|
114
119
|
"""Exports structured dictionary results to a .json file."""
|
|
120
|
+
|
|
115
121
|
base_name = Path(pdf_filename).stem
|
|
116
|
-
output_path = PDFLINKCHECK_HOME / f"{base_name}_{pdf_library}_report.json"
|
|
122
|
+
output_path = PDFLINKCHECK_HOME / f"{base_name}_{pdf_library}_{get_unique_unix_time()}_report.json"
|
|
117
123
|
|
|
124
|
+
print("For more details, explore the exported file(s).")
|
|
118
125
|
try:
|
|
119
126
|
with open(output_path, 'w', encoding='utf-8') as f:
|
|
120
127
|
json.dump(report_data, f, indent=4)
|
|
121
|
-
print(f"
|
|
128
|
+
print(f"JSON report exported: {get_friendly_path(output_path)}")
|
|
122
129
|
return output_path
|
|
123
130
|
except Exception as e:
|
|
124
131
|
error_logger.error(f"JSON export failed: {e}", exc_info=True)
|
|
@@ -130,35 +137,18 @@ def export_report_txt(
|
|
|
130
137
|
pdf_library: str
|
|
131
138
|
) -> Path:
|
|
132
139
|
"""Exports the formatted string buffer to a .txt file."""
|
|
140
|
+
#pdf_filename = implement_non_redundant_naming(pdf_filename)
|
|
133
141
|
base_name = Path(pdf_filename).stem
|
|
134
|
-
output_path = PDFLINKCHECK_HOME / f"{base_name}_{pdf_library}_report.txt"
|
|
142
|
+
output_path = PDFLINKCHECK_HOME / f"{base_name}_{pdf_library}_{get_unique_unix_time()}_report.txt"
|
|
135
143
|
|
|
136
144
|
try:
|
|
137
145
|
output_path.write_text(report_text, encoding='utf-8')
|
|
138
|
-
print(f"
|
|
146
|
+
print(f"TXT report exported: {get_friendly_path(output_path)}")
|
|
139
147
|
return output_path
|
|
140
148
|
except Exception as e:
|
|
141
149
|
error_logger.error(f"TXT export failed: {e}", exc_info=True)
|
|
142
150
|
raise RuntimeError(f"TXT export failed: {e}")
|
|
143
151
|
|
|
144
|
-
def export_validation_json(
|
|
145
|
-
report_data: Dict[str, Any],
|
|
146
|
-
pdf_filename: str,
|
|
147
|
-
pdf_library: str
|
|
148
|
-
) -> Path:
|
|
149
|
-
"""Exports structured dictionary validation results to a .json file."""
|
|
150
|
-
base_name = Path(pdf_filename).stem
|
|
151
|
-
output_path = PDFLINKCHECK_HOME / f"{base_name}_{pdf_library}_validation.json"
|
|
152
|
-
|
|
153
|
-
try:
|
|
154
|
-
with open(output_path, 'w', encoding='utf-8') as f:
|
|
155
|
-
json.dump(report_data, f, indent=4)
|
|
156
|
-
print(f"\nJSON validation exported: {get_friendly_path(output_path)}")
|
|
157
|
-
return output_path
|
|
158
|
-
except Exception as e:
|
|
159
|
-
error_logger.error(f"JSON validation export failed: {e}", exc_info=True)
|
|
160
|
-
raise RuntimeError(f"JSON validation export failed: {e}")
|
|
161
|
-
|
|
162
152
|
# --- helpers ---
|
|
163
153
|
def get_friendly_path(full_path: str) -> str:
|
|
164
154
|
p = Path(full_path).resolve()
|
|
@@ -168,6 +158,20 @@ def get_friendly_path(full_path: str) -> str:
|
|
|
168
158
|
except ValueError:
|
|
169
159
|
return str(p)
|
|
170
160
|
|
|
161
|
+
def get_unique_unix_time():
|
|
162
|
+
"""
|
|
163
|
+
Get the unix time for right now.
|
|
164
|
+
Purpose: When added to a filename, this ensures a unique filename, to avoid overwrites for otherwise identical filenames.
|
|
165
|
+
Pros:
|
|
166
|
+
- cheap, easy, no reason to check for collision
|
|
167
|
+
|
|
168
|
+
Cons:
|
|
169
|
+
- Longer than YYYYMMDDalpha
|
|
170
|
+
- not human readable
|
|
171
|
+
"""
|
|
172
|
+
return int(time.mktime(datetime.now().timetuple()))
|
|
173
|
+
|
|
174
|
+
|
|
171
175
|
def get_first_pdf_in_cwd() -> Optional[str]:
|
|
172
176
|
"""
|
|
173
177
|
Scans the current working directory (CWD) for the first file ending
|
|
@@ -210,4 +214,4 @@ def get_first_pdf_in_cwd() -> Optional[str]:
|
|
|
210
214
|
except Exception as e:
|
|
211
215
|
# Handle potential permissions errors or other issues
|
|
212
216
|
print(f"Error while searching for PDF in CWD: {e}", file=sys.stderr)
|
|
213
|
-
return None
|
|
217
|
+
return None
|