add progress bar

This commit is contained in:
rmanach 2025-10-22 11:11:46 +02:00
parent 846e7cc4b4
commit 1144dae60b
6 changed files with 73 additions and 18 deletions

View File

@ -22,6 +22,7 @@ check: format lint check-type
build: check
@rm -rf dist/*
$(PYTHON) build-deps.py
$(PYTHON) -m hatch -v build -t wheel
install: build

47
build-deps.py Normal file
View File

@ -0,0 +1,47 @@
import argparse
import os
import re
DEPS_REGEX = "dependencies = \[[^\]]*\]"
PYPROJECT_FILENAME = "pyproject.toml"
if __name__ == "__main__":
"""
build-deps retrieves all mandatory requirements in `requirements.txt`
and copies them in `pyproject.toml` dependencies list.
"""
parser = argparse.ArgumentParser()
parser.add_argument("-d", "--dry-run", action="store_true")
args = parser.parse_args()
# read and store requirements
requirements: list[str] = []
with open("requirements.txt", "r") as f:
for d in f.readlines():
d = d.replace("\n", "")
requirements.append(f'"{d}"')
# format requirements for pryproject.toml
deps: str = "dependencies = ["
deps += "\n" if len(requirements) >= 1 else ""
for dep in requirements:
deps += f"\t{dep},\n"
deps += "]"
# get and replace the pyproject.toml content
content: str = ""
with open(PYPROJECT_FILENAME, "r") as f:
content = f.read()
content = re.sub(DEPS_REGEX, deps, content, 1)
# write the new content in a temp file
with open(f"{PYPROJECT_FILENAME}.tmp", "w") as f:
f.write(content)
# if not dry run, override the original pyproject.toml
if not args.dry_run:
try:
os.rename(f"{PYPROJECT_FILENAME}.tmp", PYPROJECT_FILENAME)
except Exception as e:
print(f"error occurred while overriding pyproject file: {e}")
os.remove(f"{PYPROJECT_FILENAME}.tmp")

View File

@ -6,7 +6,9 @@ build-backend = "hatchling.build"
name = "optimg"
dynamic = ["version"]
description = "Optimize JPEG and PNG files from a directory."
dependencies = []
dependencies = [
"tqdm==4.67.1",
]
[project.scripts]
optimg = "optimg.__main__:main"

1
requirements.txt Normal file
View File

@ -0,0 +1 @@
tqdm==4.67.1

View File

@ -113,7 +113,7 @@ def main():
try:
result = optimizer.optimize(fg)
except KeyboardInterrupt:
logging.info("optimizer stopped gracefully")
logging.error("oops, you stopped the optimizer abrutly...")
exit(0)
except Exception as e:
logging.fatal(

View File

@ -3,10 +3,12 @@ import os
import signal
import subprocess
import time
from concurrent.futures import ProcessPoolExecutor
from concurrent.futures import ProcessPoolExecutor, as_completed
from dataclasses import dataclass
from typing import Optional
from tqdm import tqdm
from .files import File, FileGroup, FileImgMimetype
__all__ = ["ImgOptimizer", "OptimizerResult"]
@ -33,7 +35,7 @@ def _jpeg_optim(dest_dir: str, file: File) -> tuple["File", Optional["File"]] |
try:
_ = subprocess.run(cmd, shell=True, check=True)
except subprocess.CalledProcessError as e:
logging.error("error while running command: %s, err: %s", cmd, e.output)
logging.error("error while running command: %s, err: %s", cmd, e.stderr or "?")
return None
except Exception:
logging.error("unexpected error while running command: %s", cmd, exc_info=True)
@ -130,20 +132,22 @@ class ImgOptimizer:
p.submit(_optim, self.dest_dir, f) for f in file_group.get_files()
]
file_group_optim = FileGroup()
optimized = 0
for f in futures:
if (res := f.result()) and res is not None:
match res:
case (orig, None):
logging.debug(f"no optimization for file: {orig}")
file_group_optim.add(orig)
case (orig, opti):
optimized += 1
logging.debug(
f"optimization for file: {orig} -> {(1 - (opti.size / orig.size)) * 100:.2f}%" # noqa
)
file_group_optim.add(opti)
file_group_optim = FileGroup()
optimized = 0
for f in tqdm(
as_completed(futures), total=len(futures), desc="Optimizing..."
):
if (res := f.result()) and res is not None:
match res:
case (orig, None):
logging.debug(f"no optimization for file: {orig}")
file_group_optim.add(orig)
case (orig, opti):
optimized += 1
logging.debug(
f"optimization for file: {orig} -> {(1 - (opti.size / orig.size)) * 100:.2f}%" # noqa
)
file_group_optim.add(opti)
logging.info(f"optimization finished in {time.perf_counter() - start:.2f}s")
return OptimizerResult(file_group, file_group_optim, optimized)