pdflinkcheck 1.1.7__py3-none-any.whl → 1.1.47__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 +31 -0
- pdflinkcheck/analyze.py +306 -128
- pdflinkcheck/cli.py +97 -20
- pdflinkcheck/data/LICENSE +680 -0
- pdflinkcheck/gui.py +157 -29
- pdflinkcheck/io.py +106 -0
- pdflinkcheck-1.1.47.dist-info/METADATA +266 -0
- pdflinkcheck-1.1.47.dist-info/RECORD +13 -0
- {pdflinkcheck-1.1.7.dist-info → pdflinkcheck-1.1.47.dist-info}/entry_points.txt +0 -1
- pdflinkcheck-1.1.47.dist-info/licenses/LICENSE +680 -0
- pdflinkcheck-1.1.7.dist-info/METADATA +0 -109
- pdflinkcheck-1.1.7.dist-info/RECORD +0 -10
- {pdflinkcheck-1.1.7.dist-info → pdflinkcheck-1.1.47.dist-info}/WHEEL +0 -0
- {pdflinkcheck-1.1.7.dist-info → pdflinkcheck-1.1.47.dist-info}/top_level.txt +0 -0
pdflinkcheck/cli.py
CHANGED
|
@@ -1,17 +1,64 @@
|
|
|
1
|
-
# src/
|
|
1
|
+
# src/bug_record/cli.py
|
|
2
2
|
import typer
|
|
3
|
+
from typer.models import OptionInfo
|
|
3
4
|
from rich.console import Console
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
from pdflinkcheck.analyze import run_analysis # Assuming core logic moves here
|
|
6
7
|
from typing import Dict
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
import pyhabitat
|
|
9
|
+
import sys
|
|
10
|
+
from importlib.resources import files
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
console = Console() # to be above the tkinter check, in case of console.print
|
|
14
|
+
|
|
9
15
|
app = typer.Typer(
|
|
10
16
|
name="pdflinkcheck",
|
|
11
17
|
help="A command-line tool for comprehensive PDF link analysis and reporting.",
|
|
12
|
-
add_completion=False
|
|
18
|
+
add_completion=False,
|
|
19
|
+
invoke_without_command = True,
|
|
20
|
+
no_args_is_help = False,
|
|
13
21
|
)
|
|
14
22
|
|
|
23
|
+
@app.callback()
|
|
24
|
+
def main(ctx: typer.Context):
|
|
25
|
+
"""
|
|
26
|
+
If no subcommand is provided, launch the GUI.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
if ctx.invoked_subcommand is None:
|
|
30
|
+
gui_command()
|
|
31
|
+
raise typer.Exit(code=0)
|
|
32
|
+
|
|
33
|
+
# 1. Access the list of all command-line arguments
|
|
34
|
+
full_command_list = sys.argv
|
|
35
|
+
# 2. Join the list into a single string to recreate the command
|
|
36
|
+
command_string = " ".join(full_command_list)
|
|
37
|
+
# 3. Print the command
|
|
38
|
+
typer.echo(f"command:\n{command_string}\n")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@app.command(name="license", help="Show the full license (AGPLv3) for this software.")
|
|
42
|
+
def license_command():
|
|
43
|
+
"""
|
|
44
|
+
Reads and prints the contents of the embedded LICENSE file.
|
|
45
|
+
"""
|
|
46
|
+
try:
|
|
47
|
+
# Use importlib.resources.files to locate the LICENSE file within the installed package
|
|
48
|
+
license_path = files("pdflinkcheck.data") / "LICENSE"
|
|
49
|
+
license_text = license_path.read_text(encoding="utf-8")
|
|
50
|
+
|
|
51
|
+
# Use rich console for clean, direct output
|
|
52
|
+
console.print('='*70)
|
|
53
|
+
console.print(license_text, highlight=False)
|
|
54
|
+
|
|
55
|
+
except FileNotFoundError:
|
|
56
|
+
# This handles cases where the license file might be missing (e.g., failed sdist build)
|
|
57
|
+
console.print("[bold red]Error:[/bold red] The embedded license file could not be found.")
|
|
58
|
+
raise typer.Exit(code=1)
|
|
59
|
+
|
|
60
|
+
raise typer.Exit(code=0)
|
|
61
|
+
|
|
15
62
|
@app.command(name="analyze") # Added a command name 'analyze' for clarity
|
|
16
63
|
def analyze_pdf( # Renamed function for clarity
|
|
17
64
|
pdf_path: Path = typer.Argument(
|
|
@@ -23,16 +70,18 @@ def analyze_pdf( # Renamed function for clarity
|
|
|
23
70
|
resolve_path=True,
|
|
24
71
|
help="The path to the PDF file to analyze."
|
|
25
72
|
),
|
|
26
|
-
|
|
27
|
-
True,
|
|
28
|
-
"--check-remnants/--no-check-remnants",
|
|
29
|
-
help="Toggle checking for unlinked URLs/Emails in the text layer."
|
|
73
|
+
export_format: str = typer.Option("JSON", "--export-format","-e", help="Set the export format for the report. Currently supported: json. When None, the report wll be printed but not exported. "
|
|
30
74
|
),
|
|
31
75
|
max_links: int = typer.Option(
|
|
32
|
-
|
|
76
|
+
0,
|
|
33
77
|
"--max-links",
|
|
34
78
|
min=0,
|
|
35
|
-
help="Maximum number of links/remnants to display in the report. Use 0 to show all."
|
|
79
|
+
help="Maximum number of links/remnants to display in the report, if an overwhelming amount is expected. Use 0 to show all."
|
|
80
|
+
),
|
|
81
|
+
check_remnants: bool = typer.Option(
|
|
82
|
+
True,
|
|
83
|
+
"--check-remnants/--no-check-remnants",
|
|
84
|
+
help="Toggle checking for unlinked URLs/Emails in the text layer."
|
|
36
85
|
)
|
|
37
86
|
):
|
|
38
87
|
"""
|
|
@@ -42,22 +91,50 @@ def analyze_pdf( # Renamed function for clarity
|
|
|
42
91
|
run_analysis(
|
|
43
92
|
pdf_path=str(pdf_path),
|
|
44
93
|
check_remnants=check_remnants,
|
|
45
|
-
max_links=max_links
|
|
94
|
+
max_links=max_links,
|
|
95
|
+
export_format = export_format
|
|
46
96
|
)
|
|
47
97
|
|
|
48
98
|
@app.command(name="gui")
|
|
49
|
-
def
|
|
99
|
+
def gui_command(
|
|
100
|
+
auto_close: int = typer.Option(0,
|
|
101
|
+
"--auto-close", "-c",
|
|
102
|
+
help = "Delay in milliseconds after which the GUI window will close (for automated testing). Use 0 (default) to disable auto-closing.",
|
|
103
|
+
min=0)
|
|
104
|
+
)->None:
|
|
50
105
|
"""
|
|
51
106
|
Launch tkinter-based GUI.
|
|
52
107
|
"""
|
|
108
|
+
|
|
109
|
+
# --- START FIX ---
|
|
110
|
+
assured_auto_close_value = 0
|
|
111
|
+
|
|
112
|
+
if isinstance(auto_close, OptionInfo):
|
|
113
|
+
# Case 1: Called implicitly from main() (pdflinkcheck with no args)
|
|
114
|
+
# We received the metadata object, so use the function's default value (0).
|
|
115
|
+
# We don't need to do anything here since final_auto_close_value is already 0.
|
|
116
|
+
pass
|
|
117
|
+
else:
|
|
118
|
+
# Case 2: Called explicitly by Typer (pdflinkcheck gui -c 3000)
|
|
119
|
+
# Typer has successfully converted the command line argument, and auto_close is an int.
|
|
120
|
+
assured_auto_close_value = int(auto_close)
|
|
121
|
+
# --- END FIX ---
|
|
122
|
+
|
|
123
|
+
if not pyhabitat.tkinter_is_available():
|
|
124
|
+
_gui_failure_msg()
|
|
125
|
+
return
|
|
53
126
|
from pdflinkcheck.gui import start_gui
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
127
|
+
start_gui(time_auto_close = assured_auto_close_value)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
# --- Helper, consistent gui failure message. ---
|
|
131
|
+
def _gui_failure_msg():
|
|
132
|
+
console.print("[bold red]GUI failed to launch[/bold red]")
|
|
133
|
+
console.print("Ensure pdflinkcheck dependecies are installed and the venv is activated (the dependecies are managed by uv).")
|
|
134
|
+
console.print("The dependecies for pdflinkcheck are managed by uv.")
|
|
135
|
+
console.print("Ensure tkinter is available, especially if using WSLg.")
|
|
136
|
+
console.print(f"pyhabitat.tkinter_is_available() = {pyhabitat.tkinter_is_available()}")
|
|
137
|
+
pass
|
|
60
138
|
|
|
61
|
-
# Placeholder for running the app
|
|
62
139
|
if __name__ == "__main__":
|
|
63
|
-
app()
|
|
140
|
+
app()
|