From 41696aced5a480bb8412e047127edd44b74e49d5 Mon Sep 17 00:00:00 2001 From: Akashdeep Dhar Date: Thu, 5 Sep 2024 20:01:06 +0530 Subject: [PATCH] Use context manager protocol for temporary files Signed-off-by: Akashdeep Dhar --- gi_loadouts/face/scan/rule.py | 6 +- gi_loadouts/face/scan/util.py | 151 ++++++++++++++++++---------------- 2 files changed, 83 insertions(+), 74 deletions(-) diff --git a/gi_loadouts/face/scan/rule.py b/gi_loadouts/face/scan/rule.py index d7956369..d94705af 100644 --- a/gi_loadouts/face/scan/rule.py +++ b/gi_loadouts/face/scan/rule.py @@ -5,7 +5,7 @@ from gi_loadouts.data.arti import ArtiList from gi_loadouts.face.scan.file import file from gi_loadouts.face.scan.scan import Ui_scan -from gi_loadouts.face.scan.util import scanworker +from gi_loadouts.face.scan.util import scan_artifact from gi_loadouts.face.util import truncate_text from gi_loadouts.face.wind.talk import Dialog from gi_loadouts.type import arti @@ -171,9 +171,11 @@ def load_reader(self) -> None: :return: """ try: + self.arti_text.setText("Inspecting screenshot...") self.shot, self.path = file.load_screenshot(self, "Select location to load artifact screenshot") self.arti_shot.setPixmap(self.shot) - area, main, seco, team, levl, rare, duration = scanworker.scan_artifact(self.path) + area, main, seco, team, levl, rare, duration = scan_artifact(self.path) + self.arti_text.setText("Browse your local storage to load a high quality screenshot of your artifact and the statistics will automatically be computed from there.") print(area, main, seco, team, levl, rare, duration) except Exception as expt: self.show_dialog( diff --git a/gi_loadouts/face/scan/util.py b/gi_loadouts/face/scan/util.py index 6f3346d0..96189746 100644 --- a/gi_loadouts/face/scan/util.py +++ b/gi_loadouts/face/scan/util.py @@ -1,3 +1,4 @@ +from os import remove from os.path import realpath from pathlib import Path, PurePath from re import search @@ -16,82 +17,88 @@ from gi_loadouts.type.stat import ATTR, STAT -class ScanWorker: - def __init__(self) -> None: - file = QFile(":data/data/best.traineddata") - if not file.open(QIODevice.ReadOnly): - raise FileNotFoundError("Training data for Tesseract OCR could not be initialized") - cont = file.readAll() - file.close() - self.temp = NamedTemporaryFile(delete=False, prefix="gi-loadouts-", suffix=".traineddata") - self.temp.write(cont) - self.name = Path(self.temp.name).name.replace(".traineddata", "") - print(self.name) - - def scan_artifact(self, path: str = "") -> tuple: - """ - Scan the screenshot for computing artifact information using Tesseract OCR - - :return: Collection of artifact information and duration of computation - """ - strttime = time() - pytesseract.tesseract_cmd = conf.tessexec - imej = Image.open(path) - w, h = imej.size - l, t, r, b = w // 2, 0, w, h # noqa: E741 - imej = imej.crop((l, t, r, b)) - location = PurePath(realpath(gettempdir())).as_posix() - text = image_to_string(imej, lang=self.name, config=f"--tessdata-dir {location}") - - area, main, seco, team, levl, rare = None, ATTR(), list(), "", 0, "Star 0" - - # DISTRIBUTION AREA - for ptrn, name in areaiden.items(): +def scan_artifact(path: str = "") -> tuple: + """ + Scan the screenshot for computing artifact information using Tesseract OCR + + :return: Collection of artifact information and duration of computation + """ + file = QFile(":data/data/best.traineddata") + if not file.open(QIODevice.ReadOnly): + raise FileNotFoundError("Training data for Tesseract OCR could not be initialized") + cont = file.readAll() + file.close() + + area, main, seco, team, levl, rare = None, ATTR(), list(), "", 0, "Star 0" + + """ + When a file is marked for deletion on Windows, the file cannot be reliably opened. Therefore, + the context manager protocol for `NamedTemporaryFile` cannot be used here. The temporary file + have to be created and deleted manually. On UNIX based operating systems like GNU/Linux or + MacOS, files can be reliably opened even when they have been marked for deletion. + """ + + strttime = time() + temp = NamedTemporaryFile(prefix="gi-loadouts-", suffix=".traineddata", delete=False, mode="w+b") + temp.write(cont) + name = Path(temp.name).name.replace(".traineddata", "") + + pytesseract.tesseract_cmd = conf.tessexec + imej = Image.open(path) + w, h = imej.size + l, t, r, b = w // 2, 0, w, h # noqa: E741 + imej = imej.crop((l, t, r, b)) + location = PurePath(realpath(gettempdir())).as_posix() + text = image_to_string(imej, lang=name, config=f"--tessdata-dir {location}") + + # DISTRIBUTION AREA + for ptrn, name in areaiden.items(): + mtch = search(ptrn, text) + if mtch: + area = name + + # TEAM IDENTITY + teamdict = {} + for item, coll in teamiden.items(): + teamdict[item] = 0 + for sbst in coll: + if sbst in text: + teamdict[item] += 1 + sortkeys = sorted(teamdict, key=lambda item: teamdict[item], reverse=True) + team = sortkeys[0] + + # RARITY + if team.strip() != "": + teamobjc = getattr(ArtiList, team.replace(" ", "_").replace("'", "").replace("-", "_")) + rare = teamobjc.value.rare[0].value.name + + # MAINSTAT + if area == FWOL: + main = ATTR(stat_name=STAT.health_points, stat_data=0.0) + elif area == PMOD: + main = ATTR(stat_name=STAT.attack, stat_data=0.0) + elif area in [SDOE, GBOE, CCOL]: + for ptrn, name in mainstat[area].items(): mtch = search(ptrn, text) if mtch: - area = name - - # TEAM IDENTITY - teamdict = {} - for item, coll in teamiden.items(): - teamdict[item] = 0 - for sbst in coll: - if sbst in text: - teamdict[item] += 1 - sortkeys = sorted(teamdict, key=lambda item: teamdict[item], reverse=True) - team = sortkeys[0] - - # RARITY - if team.strip() != "": - teamobjc = getattr(ArtiList, team.replace(" ", "_").replace("'", "").replace("-", "_")) - rare = teamobjc.value.rare[0].value.name - - # MAINSTAT - if area == FWOL: - main = ATTR(stat_name=STAT.health_points, stat_data=0.0) - elif area == PMOD: - main = ATTR(stat_name=STAT.attack, stat_data=0.0) - elif area in [SDOE, GBOE, CCOL]: - for ptrn, name in mainstat[area].items(): - mtch = search(ptrn, text) - if mtch: - main = ATTR(stat_name=name, stat_data=0.0) - - # SUBSTATS - for ptrn, name in substats.items(): - mtch = search(ptrn, text) - if mtch and len(seco) < 4: - data = search(r"\b\d+(\.\d+)?\b", mtch.group()).group() - seco.append(ATTR(stat_name=name, stat_data=float(data))) + main = ATTR(stat_name=name, stat_data=0.0) - # LEVELS - mtch = search(levliden, text) - if mtch: - levl = f"Level {mtch.group()}" + # SUBSTATS + for ptrn, name in substats.items(): + mtch = search(ptrn, text) + if mtch and len(seco) < 4: + data = search(r"\b\d+(\.\d+)?\b", mtch.group()).group() + seco.append(ATTR(stat_name=name, stat_data=float(data))) + + # LEVELS + mtch = search(levliden, text) + if mtch: + levl = f"Level {mtch.group()}" - stoptime = time() + stoptime = time() - return area, main, seco, team, levl, rare, (stoptime - strttime) + temp.close() + remove(temp.name) -scanworker = ScanWorker() + return area, main, seco, team, levl, rare, (stoptime - strttime)