Skip to content

Commit

Permalink
Fix pytest-xdist entrypoint with custom caching
Browse files Browse the repository at this point in the history
Also, add `tesseract` in the testing environment

Add coverage for `conf.py` and make necessary changes as per suggestion

Co-authored-by: Akashdeep Dhar <[email protected]>
Co-authored-by: Shounak Dey <[email protected]>
  • Loading branch information
gridhead and sdglitched committed Oct 8, 2024
1 parent 12e8f44 commit 59e2b41
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 56 deletions.
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ jobs:
xcb-util-keysyms \
xcb-util-wm \
xorg-x11-server-Xvfb \
tesseract \
--assumeyes
- name: Install the base dependencies
Expand Down
15 changes: 11 additions & 4 deletions gi_loadouts/conf.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
from platform import system

if system() == "Windows":
tessexec = "C:\\Program Files\\Tesseract-OCR\\tesseract.exe"
else:
tessexec = "/usr/bin/tesseract"

def get_tessexec_path():
if system() == "Windows":
return "C:\\Program Files\\Tesseract-OCR\\tesseract.exe"
else:
return "/usr/bin/tesseract"

tessexec = get_tessexec_path()

tempname = ""
temppath = ""
stattime = 5000

data_prefix = "gi-loadouts-"
data_suffix = ".traineddata"
6 changes: 3 additions & 3 deletions gi_loadouts/face/rsrc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def make_temp_file() -> None:
Remove the residual cache data from the temporary directory left over during previous sessions
due to unsuccessful termination before instantiating the same for this session.
"""
ptrn = r"gi-loadouts-[a-z0-9_]+\.traineddata"
ptrn = fr"{conf.data_prefix}[a-z0-9_]+\{conf.data_suffix}"
temp = Path(gettempdir())
resi = [temp / file.name for file in temp.iterdir() if file.is_file() if match(ptrn, file.name)]

Expand All @@ -45,10 +45,10 @@ def make_temp_file() -> None:
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.
"""
temp = NamedTemporaryFile(prefix="gi-loadouts-", suffix=".traineddata", delete=False, mode="w+b")
temp = NamedTemporaryFile(prefix=conf.data_prefix, suffix=conf.data_suffix, delete=False, mode="w+b")
temp.write(cont)
temp.close()
conf.tempname = Path(temp.name).name.replace(".traineddata", "")
conf.tempname = Path(temp.name).name.replace(conf.data_suffix, "")
conf.temppath = temp.name


Expand Down
2 changes: 1 addition & 1 deletion gi_loadouts/face/scan/work.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def __init__(self, snap: ImageFile):
super().__init__()
self.snap = snap

def scan_artifact(self) -> None: # pragma: no cover
def scan_artifact(self) -> None: # pragma: no cover
"""
Scan the screenshot for computing artifact information using Tesseract OCR
Expand Down
2 changes: 1 addition & 1 deletion gi_loadouts/face/wind/calc.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@


class Assess:
def __init__(self) -> None: # pragma: no cover
def __init__(self) -> None: # pragma: no cover
self.collection = Collection()
self.c_team = None
self.c_weap = None
Expand Down
5 changes: 2 additions & 3 deletions test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ def runner(qtbot):
@pytest.fixture
def scantest(qtbot):
"""
The codebase will automatically detect the part
once the artifact is changed manually in the window
or changed by the after the scan
The codebase will automatically detect the part once the artifact is changed manually in the
window or changed by the after the scan
"""
testscan = ScanDialog("fwol")
qtbot.addWidget(testscan)
Expand Down
107 changes: 63 additions & 44 deletions test/face/scan/test_scan.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from os import path, remove
from pathlib import Path
from os import remove
from random import choice, randbytes
from tempfile import NamedTemporaryFile, gettempdir
from tempfile import NamedTemporaryFile
from uuid import uuid4

import pytest
from PySide6.QtCore import Qt
Expand All @@ -10,7 +10,7 @@

from gi_loadouts import __versdata__, conf
from gi_loadouts.data.arti import __artilist__
from gi_loadouts.face.rsrc import make_temp_file
from gi_loadouts.face.rsrc import kill_temp_file, make_temp_file
from gi_loadouts.face.scan import file
from gi_loadouts.face.util import truncate_text
from gi_loadouts.type.arti import ArtiLevl, base
Expand Down Expand Up @@ -42,27 +42,27 @@ def test_scan_window(scantest, _) -> None:
"name, rare, part, part_type",
[
pytest.param(
name, team.rare, team.fwol, "Flower of Life", id=f"face.scan.rule: Configuration Flower of Life artifact - {name}"
name, team.rare, team.fwol, "Flower of Life", id=f"face.scan.rule: Configuring Flower of Life artifact - {name}"
) for name, team in __artilist__.items()
] +
[
pytest.param(
name, team.rare, team.pmod, "Plume of Death", id=f"face.scan.rule: Configuration Plume of Death artifact - {name}"
name, team.rare, team.pmod, "Plume of Death", id=f"face.scan.rule: Configuring Plume of Death artifact - {name}"
) for name, team in __artilist__.items()
] +
[
pytest.param(
name, team.rare, team.sdoe, "Sands of Eon", id=f"face.scan.rule: Configuration Sands of Eon artifact - {name}"
name, team.rare, team.sdoe, "Sands of Eon", id=f"face.scan.rule: Configuring Sands of Eon artifact - {name}"
) for name, team in __artilist__.items()
] +
[
pytest.param(
name, team.rare, team.gboe, "Goblet of Eonothem", id=f"face.scan.rule: Configuration Goblet of Eonothem artifact - {name}"
name, team.rare, team.gboe, "Goblet of Eonothem", id=f"face.scan.rule: Configuring Goblet of Eonothem artifact - {name}"
) for name, team in __artilist__.items()
] +
[
pytest.param(
name, team.rare, team.ccol, "Circlet of Logos", id=f"face.scan.rule: Configuration Circlet of Logos artifact - {name}"
name, team.rare, team.ccol, "Circlet of Logos", id=f"face.scan.rule: Configuring Circlet of Logos artifact - {name}"
) for name, team in __artilist__.items()
]
)
Expand All @@ -88,6 +88,7 @@ def test_scan_arti_drop(scantest, name, rare, part, part_type) -> None:
scantest.arti_levl.setCurrentText(conf["levl"].value.name)
conf["stat"] = choice([item for item in getattr(base, __dist__[conf["dist"]]["list"].__name__) if item.value != STAT.none])
scantest.arti_name_main.setCurrentText(conf["stat"].value.value)

"""
Confirm if the user interface elements change accordingly
"""
Expand Down Expand Up @@ -142,20 +143,20 @@ def test_scan_arti_load(scantest, qtbot, mocker, _) -> None:
"""

"""
Create the tesseract training data
Create the Tesseract training data
"""
mocker.patch("gi_loadouts.conf.data_prefix", f"{uuid4().hex.upper()[0:8]}-")
make_temp_file()

"""
Perform the action of loading the artifact information
"""
temp_prm = ""
tempfile = "test/static/img/gi-loadouts-ocr-test.webp"
savefile = str(Path(gettempdir()) / "gi-loadouts-ocr-test.webp")
savefile = NamedTemporaryFile(prefix="gi-loadouts-ocr-test", suffix=".webp", delete=False, mode="wb")
with open(tempfile, "rb") as src_file:
with open(savefile, "wb") as dest_file:
dest_file.write(src_file.read())
mocker.patch.object(QFileDialog, "getOpenFileName", return_value=(savefile, temp_prm))
savefile.write(src_file.read())
savefile.close()
mocker.patch.object(QFileDialog, "getOpenFileName", return_value=(savefile.name, ""))
qtbot.mouseClick(scantest.arti_cnvs_load, Qt.LeftButton)

"""
Expand Down Expand Up @@ -183,10 +184,9 @@ def check_label():
qtbot.waitUntil(check_label)

"""
Clear the copied file from temp directory
Cleanup the temporary files from temp directory
"""
if path.exists(savefile):
remove(savefile)
remove(savefile.name)


@pytest.mark.parametrize(
Expand Down Expand Up @@ -259,13 +259,17 @@ def test_scan_arti_load_fail(scantest, qtbot, mocker, _) -> None:
"""

"""
Perform the action of loading the artifact snapshot
Create a temporary file filled with random data to simulate a failure when trying to open an
image using PIL.Image.open().
"""
temp_prm = ""
savefile = NamedTemporaryFile(prefix="gi-loadouts-", suffix=".webp", delete=False, mode="wb")
savefile.write(randbytes(512*1024))
savefile.close()
mocker.patch.object(QFileDialog, "getOpenFileName", return_value=(savefile.name, temp_prm))

"""
Perform the action of loading the artifact snapshot
"""
mocker.patch.object(QFileDialog, "getOpenFileName", return_value=(savefile.name, ""))
qtbot.mouseClick(scantest.arti_cnvs_load, Qt.LeftButton)

"""
Expand All @@ -278,37 +282,52 @@ def test_scan_arti_load_fail(scantest, qtbot, mocker, _) -> None:
assert scantest.dialog.isVisible()

"""
Cleanup the temporary files
Cleanup the temporary files from temp directory
"""
remove(savefile.name)


@pytest.mark.parametrize(
"_",
"platform, tempexec",
[
pytest.param(None, id="face.scan.rule: Actual loading of Tesseract OCR executable")
pytest.param("Linux", "/usr/bin/tesseract", id="face.scan.rule: Actual loading of Tesseract OCR executable in Linux"),
pytest.param("Windows", "C:\\Program Files\\Tesseract-OCR\\tesseract.exe", id="face.scan.rule: Actual loading of Tesseract OCR executable in Windows")
]
)
def test_scan_tessexec_load(scantest, qtbot, mocker, _) -> None:
def test_scan_tessexec_load(scantest, qtbot, mocker, platform, tempexec) -> None:
"""
Attempt actual loading of Tesseract OCR executable
:return:
"""

"""
Store the initial conf.tessexec so that after this test it can be restored to the original value
"""
temp = conf.tessexec

"""
Mock the system environment and reload the tessexec variable to apply the mocked path
"""
mocker.patch("gi_loadouts.conf.system", return_value=platform)
conf.tessexec = conf.get_tessexec_path()

"""
Perform the action of loading the actual Tesseract OCR executable
"""
tempexec = "/usr/bin/tesseract"
temp_prm = ""
mocker.patch.object(QFileDialog, "getOpenFileName", return_value=(tempexec, temp_prm))
mocker.patch.object(QFileDialog, "getOpenFileName", return_value=(tempexec, ""))
qtbot.mouseClick(scantest.arti_cnvs_conf, Qt.LeftButton)

"""
Confirm if the user interface elements change accordingly
"""
assert conf.tessexec == tempexec

"""
Reinstate the path for Tesseract OCR executable
"""
conf.tessexec = temp


@pytest.mark.parametrize(
"_",
Expand Down Expand Up @@ -356,18 +375,18 @@ def test_scan_register_fail(scantest, qtbot, mocker, expt) -> None:
"""
Create the tesseract training data
"""
mocker.patch("gi_loadouts.conf.data_prefix", f"{uuid4().hex.upper()[0:8]}-")
make_temp_file()

"""
Perform the action of loading the artifact information
"""
temp_prm = ""
tempfile = "test/static/img/gi-loadouts-ocr-test.webp"
savefile = str(Path(gettempdir()) / "gi-loadouts-ocr-test.webp")
savefile = NamedTemporaryFile(prefix="gi-loadouts-ocr-test", suffix=".webp", delete=False, mode="wb")
with open(tempfile, "rb") as src_file:
with open(savefile, "wb") as dest_file:
dest_file.write(src_file.read())
mocker.patch.object(QFileDialog, "getOpenFileName", return_value=(savefile, temp_prm))
savefile.write(src_file.read())
savefile.close()
mocker.patch.object(QFileDialog, "getOpenFileName", return_value=(savefile.name, ""))
mocker.patch("gi_loadouts.face.scan.work.image_to_string", side_effect=expt)
qtbot.mouseClick(scantest.arti_cnvs_load, Qt.LeftButton)

Expand All @@ -389,10 +408,10 @@ def check_label():
qtbot.waitUntil(check_label)

"""
Clear the copied file from temp directory
Cleanup the temporary files from temp directory
"""
if path.exists(savefile):
remove(savefile)
kill_temp_file()
remove(savefile.name)


@pytest.mark.parametrize(
Expand Down Expand Up @@ -435,18 +454,18 @@ def test_scan_import_arti(scantest, qtbot, mocker, _) -> None:
"""
Create the tesseract training data
"""
mocker.patch("gi_loadouts.conf.data_prefix", f"{uuid4().hex.upper()[0:8]}-")
make_temp_file()

"""
Perform the action of loading the artifact information
"""
temp_prm = ""
tempfile = "test/static/img/gi-loadouts-ocr-test.webp"
savefile = str(Path(gettempdir()) / "gi-loadouts-ocr-test.webp")
savefile = NamedTemporaryFile(prefix="gi-loadouts-ocr-test", suffix=".webp", delete=False, mode="wb")
with open(tempfile, "rb") as src_file:
with open(savefile, "wb") as dest_file:
dest_file.write(src_file.read())
mocker.patch.object(QFileDialog, "getOpenFileName", return_value=(savefile, temp_prm))
savefile.write(src_file.read())
savefile.close()
mocker.patch.object(QFileDialog, "getOpenFileName", return_value=(savefile.name, ""))
qtbot.mouseClick(scantest.arti_cnvs_load, Qt.LeftButton)

init = scantest.arti_type.currentText()
Expand All @@ -463,7 +482,7 @@ def test_scan_import_arti(scantest, qtbot, mocker, _) -> None:
assert scantest.keep_info() == __rtrn__

"""
Clear the copied file from temp directory
Cleanup the temporary files from temp directory
"""
if path.exists(savefile):
remove(savefile)
kill_temp_file()
remove(savefile.name)

0 comments on commit 59e2b41

Please sign in to comment.