Skip to content

Commit 964c519

Browse files
author
bitdruid
committed
implemented verbosity tiers 'low, default, high'
1 parent a789ef3 commit 964c519

File tree

6 files changed

+131
-22
lines changed

6 files changed

+131
-22
lines changed

README.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,13 @@ Parameters will change the download behavior for snapshots.
178178
- **`-m`**, **`--metadata`**<br>
179179
Folder where metadata will be saved (`cdx`/`db`/`csv`/`log`). If you are downloading into a network share, you SHOULD set this to a local path because sqlite locking mechanism may cause issues with network shares.
180180

181-
- **`--verbose`**:<br>
182-
Increase output verbosity.
181+
- **`-v`**, **`--verbose`** `[level]`:<br>
182+
Set verbosity level. Available levels:
183+
- `low` (or `quiet`, `minimal`, `min`): Essential output only (same as no flag)
184+
- `default` (or `normal`, `verbose`): Standard verbose output (default when flag is set)
185+
- `high` (or `debug`, `detailed`, `max`): Detailed verbose output
186+
187+
Examples: `--verbose`, `--verbose default`, `--verbose high`, `-v high`
183188

184189
- **`--log`** <!-- `<path>` -->:<br>
185190
Saves a log file into the output-dir. `waybackup_<sanitized_url>.log`.
@@ -199,6 +204,9 @@ Parameters will change the download behavior for snapshots.
199204
- **`--delay`** `<seconds>`:<br>
200205
Delay between download requests in seconds. Default is no delay (0).
201206

207+
- **`--wait`** `<seconds>`:<br>
208+
Seconds to wait before renewing connection after HTTP errors or snapshot download errors. Default is 15 seconds.
209+
202210
#### Job Handling:
203211

204212
- **`--reset`**:

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ dependencies = [
1818
"python-magic-bin==0.4.14; sys_platform == 'win32' or sys_platform == 'darwin'",
1919
]
2020
name = "pywaybackup"
21-
version = "4.1.3"
21+
version = "4.1.4"
2222
description = "Query and download archive.org as simple as possible."
2323
authors = [{ name = "bitdruid", email = "bitdruid@outlook.com" }]
2424
license = { file = "LICENSE" }

pywaybackup/Arguments.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,27 @@ def __init__(self):
3333
behavior = parser.add_argument_group("manipulate behavior")
3434
behavior.add_argument("-o", "--output", type=str, metavar="", help="output for all files - defaults to current directory")
3535
behavior.add_argument("-m", "--metadata", type=str, metavar="", help="change directory for db/cdx/csv/log files")
36-
behavior.add_argument("-v", "--verbose", action="store_true", help="overwritten by progress - gives detailed output")
36+
behavior.add_argument(
37+
"-v", "--verbose",
38+
type=str,
39+
nargs="?",
40+
const="default",
41+
metavar="",
42+
help="verbosity level: low, default, high (default if flag set without value)",
43+
)
3744
behavior.add_argument("--log", action="store_true", help="save a log file into the output folder")
3845
behavior.add_argument("--progress", action="store_true", help="show a progress bar")
3946
behavior.add_argument("--no-redirect", action="store_true", help="do not follow redirects by archive.org")
4047
behavior.add_argument("--retry", type=int, default=0, metavar="", help="retry failed downloads (opt tries as int, else infinite)")
4148
behavior.add_argument("--workers", type=int, default=1, metavar="", help="number of workers (simultaneous downloads)")
4249
behavior.add_argument("--delay", type=int, default=0, metavar="", help="delay between each download in seconds")
43-
behavior.add_argument("--wait", type=int, default=15, metavar="", help="seconds to wait before renewing connection after HTTP errors or snapshot download errors (default: 15)",)
50+
behavior.add_argument(
51+
"--wait",
52+
type=int,
53+
default=15,
54+
metavar="",
55+
help="seconds to wait before renewing connection after HTTP errors or snapshot download errors (default: 15)",
56+
)
4457

4558
special = parser.add_argument_group("special")
4659
special.add_argument("--reset", action="store_true", help="reset the job and ignore existing cdx/db/csv files")

pywaybackup/PyWayBackup.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import sys
55
import time
66
from importlib.metadata import version
7+
from typing import Union
78

89
import pywaybackup.archive_save as archive_save
910
from pywaybackup.archive_download import DownloadArchive
@@ -122,7 +123,7 @@ def __init__(
122123
statuscode: str = None,
123124
output: str = None,
124125
metadata: str = None,
125-
verbose: bool = False,
126+
verbose: Union[bool, str, int] = None,
126127
log: bool = False,
127128
progress: bool = False,
128129
no_redirect: bool = False,

pywaybackup/Verbosity.py

Lines changed: 98 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,99 @@
1+
from enum import IntEnum
12
from tqdm import tqdm
23
from typing import Union
34

45

6+
# outside enum to avoid cls membership
7+
_VERBOSITY_ALIASES = {
8+
"NORMAL": "DEFAULT",
9+
"VERBOSE": "DEFAULT",
10+
"DETAIL": "HIGH",
11+
"DETAILED": "HIGH",
12+
"MAX": "HIGH",
13+
"QUIET": "LOW",
14+
"MINIMAL": "LOW",
15+
"MIN": "LOW",
16+
}
17+
18+
19+
class VerbosityLevel(IntEnum):
20+
"""
21+
Verbosity levels for output control.
22+
23+
- LOW: Essential output only (no verbose flag)
24+
- DEFAULT: Standard verbose output (--verbose or --verbose default)
25+
- HIGH: Detailed verbose output (--verbose high)
26+
"""
27+
28+
LOW = 0
29+
DEFAULT = 1
30+
HIGH = 2
31+
32+
@classmethod
33+
def from_value(cls, value) -> "VerbosityLevel":
34+
"""
35+
Convert various input types to VerbosityLevel.
36+
37+
Args:
38+
value: Can be:
39+
- None/False: LOW
40+
- True: DEFAULT
41+
- str: "low", "default", "high" (+ aliases: normal, info, debug, quiet, etc.)
42+
- int: 0, 1, 2
43+
- VerbosityLevel: returned as-is
44+
45+
Returns:
46+
VerbosityLevel enum value
47+
48+
Raises:
49+
ValueError: If string value is not a valid level or alias
50+
"""
51+
if value is None or value is False:
52+
return cls.LOW
53+
if value is True:
54+
return cls.DEFAULT
55+
if isinstance(value, cls):
56+
return value
57+
if isinstance(value, int):
58+
try:
59+
return cls(value)
60+
except ValueError:
61+
raise ValueError(f"Invalid verbosity level: {value}. Valid levels: 0 (low), 1 (default), 2 (high)")
62+
if isinstance(value, str):
63+
upper_value = value.upper()
64+
# check for aliases first
65+
if upper_value in _VERBOSITY_ALIASES:
66+
upper_value = _VERBOSITY_ALIASES[upper_value]
67+
# try to get the enum member
68+
try:
69+
return cls[upper_value]
70+
except KeyError:
71+
valid = ", ".join([m.name.lower() for m in cls] + list(set(a.lower() for a in _VERBOSITY_ALIASES)))
72+
raise ValueError(f"Invalid verbosity level: '{value}'. Valid levels: {valid}")
73+
return cls.LOW
74+
75+
576
class Verbosity:
677
"""
778
A class to manage verbosity levels, logging, progress and output.
79+
80+
Verbosity tiers:
81+
- LOW (0): Essential output only - no verbose flag set
82+
- DEFAULT (1): Standard verbose - --verbose or --verbose default
83+
- HIGH (2): Detailed verbose - --verbose high
884
"""
985

10-
verbose = False
86+
level = VerbosityLevel.LOW
1187

1288
PROGRESS = None
1389
pbar = None
1490

1591
log = None
1692

1793
@classmethod
18-
def init(cls, logfile=None, silent: bool = False, verbose: bool = False, progress=None):
94+
def init(cls, logfile=None, silent: bool = False, verbose: Union[bool, str, int] = False, progress=None):
1995
cls.silent = silent
20-
cls.verbose = verbose
96+
cls.level = VerbosityLevel.from_value(verbose)
2197
cls.logfile = open(logfile, "w", encoding="utf-8") if logfile else None
2298
cls.PROGRESS = progress
2399

@@ -30,17 +106,19 @@ def fini(cls):
30106
cls.logfile.close()
31107

32108
@classmethod
33-
def write(cls, verbose: bool = None, content: Union[str, list] = None):
109+
def write(cls, verbose: Union[bool, str, int, None] = None, content: Union[str, list] = None):
34110
"""
35111
Writes log entries to stdout or logfile based on verbosity level and progress-bar status.
36112
37113
Determines if the message should be printed based on verbosity level.
38-
- If None, the message is always printed.
39114
40-
Content is a list and is filtered and concatenated to a single block of loglines.
41-
It should contain dictionaries with keys:
42-
- 'verbose': The verbosity level of the message (True/False).
43-
- 'content': The actual message to be logged.
115+
Args:
116+
verbose: The required verbosity level for this message:
117+
- None: Always printed (essential output)
118+
- False/0/"low": Printed at LOW level and above
119+
- True/1/"default": Printed at DEFAULT level and above
120+
- 2/"high": Printed at HIGH level only
121+
content: The message string or list of message dicts to log.
44122
"""
45123
if not cls.silent:
46124
if isinstance(content, str):
@@ -80,16 +158,23 @@ def filter_verbosity(cls, message: list):
80158
"""
81159
Removes messages from the list that do not match the verbosity level.
82160
83-
- True if message is verbose None (print always)
84-
- True if message has same verbosity as configured
161+
Messages are printed if:
162+
- verbose is None (always print - essential output)
163+
- The message's required level <= configured level
85164
86165
Returns a string containing the filtered messages, joined by newlines.
87166
"""
88167
filtered_message = []
89168
for msg in message:
90-
verbose = msg.get("verbose", None)
91-
if verbose is None or verbose == cls.verbose:
169+
msg_verbose = msg.get("verbose", None)
170+
if msg_verbose is None:
171+
# NONE is always printed
92172
filtered_message.append(msg["content"])
173+
else:
174+
# convert message verbosity and compare
175+
msg_level = VerbosityLevel.from_value(msg_verbose)
176+
if msg_level <= cls.level:
177+
filtered_message.append(msg["content"])
93178
return "\n".join(filtered_message)
94179

95180

pywaybackup/archive_download.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,11 @@ def _download_loop(self, worker: Worker):
156156
while worker.attempt <= retry_max_attempt: # retry as given by user
157157
worker.message.store(
158158
verbose=True,
159-
content=f"\n-----> Worker: {worker.id} \
160-
- Attempt: [{worker.attempt}/{retry_max_attempt}] \
161-
Snapshot ID: [{worker.snapshot.counter}/{self.sc._snapshot_total}]",
159+
content=(
160+
f"\n-----> Worker: {worker.id}"
161+
f" - Attempt: [{worker.attempt}/{retry_max_attempt}]"
162+
f" Snapshot ID: [{worker.snapshot.counter}/{self.sc._snapshot_total}]"
163+
),
162164
)
163165
download_attempt = 1
164166
download_max_attempt = 3

0 commit comments

Comments
 (0)