Skip to content

Commit

Permalink
unit test fix and some self review
Browse files Browse the repository at this point in the history
  • Loading branch information
laracroft37 committed Aug 5, 2024
1 parent 9ceb85e commit d40c948
Show file tree
Hide file tree
Showing 12 changed files with 69 additions and 70 deletions.
4 changes: 0 additions & 4 deletions guibot/calibrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,8 +415,6 @@ def run_performance(self, finder: Finder, **kwargs: dict[str, type]) -> float:
and linear performance penalty.
:param finder: finder with match configuration to use for the run
:param float max_exec_time: maximum execution time before penalizing
the run by increasing the error linearly
:returns: error obtained as unity minus similarity
"""
self._handle_restricted_values(finder)
Expand Down Expand Up @@ -448,8 +446,6 @@ def run_peak(self, finder: Finder, **kwargs: dict[str, type]) -> float:
high similarity of one match and low similarity of all others.
:param finder: finder with match configuration to use for the run
:param peak_location: (x, y) of the match whose similarity should be
maximized while all the rest minimized
:returns: error obtained as unity minus similarity
This run function doesn't just obtain the optimum similarity for the best
Expand Down
8 changes: 4 additions & 4 deletions guibot/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ def preprocess_special_chars(self, value: bool = None) -> bool | None:
handle them internally
.. warning:: The characters will be forcefully preprocessed for the
autopy on linux (capital and special) and vncdotool (capital) backends.
autopy on linux (capital and special) and vncdotool (capital) backends.
"""
if value is None:
return GlobalConfig._preprocess_special_chars
Expand Down Expand Up @@ -343,7 +343,7 @@ def display_control_backend(self, value: str = None) -> str | None:
their calls on the host machine.
.. warning:: To use a particular backend you need to satisfy its dependencies,
i.e. the backend has to be installed or you will have unsatisfied imports.
i.e. the backend has to be installed or you will have unsatisfied imports.
"""
if value is None:
return GlobalConfig._display_control_backend
Expand Down Expand Up @@ -374,14 +374,14 @@ def find_backend(self, value: str = None) -> str | None:
* text - text matching using EAST, ERStat, or custom text detection,
followed by Tesseract or Hidden Markov Model OCR
* tempfeat - a mixture of template and feature matching where the
first is used as necessary and the second as sufficient stage
first is used as necessary and the second as sufficient stage
* deep - deep learning matching using convolutional neural network but
customizable to any type of deep neural network
* hybrid - use a composite approach with any of the above methods
as matching steps in a fallback sequence
.. warning:: To use a particular backend you need to satisfy its dependencies,
i.e. the backend has to be installed or you will have unsatisfied imports.
i.e. the backend has to be installed or you will have unsatisfied imports.
"""
if value is None:
return GlobalConfig._find_backend
Expand Down
6 changes: 3 additions & 3 deletions guibot/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,9 +270,9 @@ def mouse_scroll(self, clicks: int = 10, horizontal: bool = False) -> None:
"""
Scroll the mouse for a number of clicks.
:param int clicks: number of clicks to scroll up (positive) or down (negative)
:param bool horizontal: whether to perform a horizontal scroll instead
(only available on some platforms)
:param clicks: number of clicks to scroll up (positive) or down (negative)
:param horizontal: whether to perform a horizontal scroll instead
(only available on some platforms)
:raises: :py:class:`NotImplementedError` if the base class method is called
"""
raise NotImplementedError("Method is not available for this controller implementation")
Expand Down
39 changes: 21 additions & 18 deletions guibot/finder.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@ def __init__(self, value: bool | int | float,
:param min_val: lower boundary for the parameter range
:param max_val: upper boundary for the parameter range
:param delta: delta for the calibration and random value
(no calibration if `delta` < `tolerance`)
(no calibration if `delta` < `tolerance`)
:param tolerance: tolerance of calibration
:param fixed: whether the parameter is prevented from calibration
:param enumerated: whether the parameter value belongs to an
enumeration or to a range (distance matters)
enumeration or to a range (distance matters)
As a rule of thumb a good choice for the parameter delta is one fourth
of the range since the delta will be used as standard deviation when
Expand Down Expand Up @@ -339,7 +339,7 @@ def __configure_backend(self, backend: str = None, category: str = "find",
log.log(9, "%s %s\n", category, self.params[category])

def configure_backend(self, backend: str = None, category: str = "find",
reset: bool = False) -> None:
reset: bool = False) -> None:
"""
Custom implementation of the base method.
Expand All @@ -348,7 +348,7 @@ def configure_backend(self, backend: str = None, category: str = "find",
self.__configure_backend(backend, category, reset)

def __synchronize_backend(self, backend: str = None, category: str = "find",
reset: bool = False) -> None:
reset: bool = False) -> None:
if category != "find":
raise UnsupportedBackendError("Backend category '%s' is not supported" % category)
if reset:
Expand Down Expand Up @@ -1210,7 +1210,8 @@ def configure_backend(self, backend: str = None, category: str = "feature",
self.__configure_backend(backend, category, reset)

def __configure(self, feature_detect: str = None, feature_extract: str = None,
feature_match: str = None, reset: bool = True, **kwargs: dict[str, type]) -> None:
feature_match: str = None, reset: bool = True,
**kwargs: dict[str, type]) -> None:
"""
Custom implementation of the base method.
Expand All @@ -1224,7 +1225,8 @@ def __configure(self, feature_detect: str = None, feature_extract: str = None,
self.__configure_backend(feature_match, "fmatch")

def configure(self, feature_detect: str = None, feature_extract: str = None,
feature_match: str = None, reset: bool = True, **kwargs: dict[str, type]) -> None:
feature_match: str = None, reset: bool = True,
**kwargs: dict[str, type]) -> None:
"""
Custom implementation of the base method.
Expand Down Expand Up @@ -1364,14 +1366,13 @@ def find(self, needle: "Image", haystack: "Image") -> "list[Match]":
self.imglog.log(40)
return []

def _project_features(self, locations_in_needle: int, ngray: int, hgray: int, similarity: float) -> list[tuple[int, int]] | None:
def _project_features(self, locations_in_needle: int, ngray: int,
hgray: int, similarity: float) -> list[tuple[int, int]] | None:
"""
EXTRA DOCSTRING: Feature matching backend - wrapper.
Wrapper for the internal feature detection, matching and location
projection used by all public feature matching functions.
..todo:: locations_in_needle, ngray, hgray, similarity are not documented
"""
# default logging in case no match is found (further overridden by match stages)
self.imglog.locations.append((0, 0))
Expand Down Expand Up @@ -1414,7 +1415,8 @@ def _project_features(self, locations_in_needle: int, ngray: int, hgray: int, si
self._log_features(30, self.imglog.locations, self.imglog.hotmaps[-1], 3, 0, 0, 255)
return locations_in_haystack

def _detect_features(self, ngray: int, hgray: int, detect: str, extract: str) -> tuple[str, str, str, str]:
def _detect_features(self, ngray: int, hgray: int, detect: str,
extract: str) -> tuple[str, str, str, str]:
"""
EXTRA DOCSTRING: Feature matching backend - detection/extraction stage (1).
Expand Down Expand Up @@ -1466,7 +1468,8 @@ def _detect_features(self, ngray: int, hgray: int, detect: str, extract: str) ->
return (nkeypoints, ndescriptors, hkeypoints, hdescriptors)

def _match_features(self, nkeypoints: str, ndescriptors: str,
hkeypoints: str, hdescriptors: str, match: str) -> tuple[list[str], list[str]]:
hkeypoints: str, hdescriptors: str,
match: str) -> tuple[list[str], list[str]]:
"""
EXTRA DOCSTRING: Feature matching backend - matching stage (2).
Expand Down Expand Up @@ -1571,7 +1574,8 @@ def symmetry_test(nmatches: str, hmatches: str) -> list[str]:

return (match_nkeypoints, match_hkeypoints)

def _project_locations(self, locations_in_needle: int, mnkp: str, mhkp: str) -> list[tuple[int, int]]:
def _project_locations(self, locations_in_needle: int, mnkp: str,
mhkp: str) -> list[tuple[int, int]]:
"""
EXTRA DOCSTRING: Feature matching backend - projecting stage (3).
Expand All @@ -1590,8 +1594,6 @@ def _project_locations(self, locations_in_needle: int, mnkp: str, mhkp: str) ->
i.e. the upper left corner of the image. In case of wild
transformations of the needle in the haystack this has to
be reconsidered and the needle center becomes obligatory.
..todo:: locations_in_needle, mnkp, mhkp are not documented
"""
# check matches consistency
assert len(mnkp) == len(mhkp)
Expand Down Expand Up @@ -1679,9 +1681,9 @@ def log(self, lvl: int) -> None:
self.imglog.clear()
ImageLogger.step += 1

def _log_features(self, lvl: int, locations: Location, hotmap: "Image", radius: int = 0, r: int = 255,
g: int = 255, b: int = 255) -> None:
# ..todo:: locations, hotmap are not documented
def _log_features(self, lvl: int, locations: Location, hotmap: "Image",
radius: int = 0, r: int = 255, g: int = 255,
b: int = 255) -> None:
if lvl < self.imglog.logging_level:
return
import cv2
Expand Down Expand Up @@ -1990,7 +1992,8 @@ def __configure(self, text_detector: str = None, text_recognizer: str = None,

def configure(self, text_detector: str = None, text_recognizer: str = None,
threshold_filter: str = None, threshold_filter2: str = None,
threshold_filter3: str = None, reset: bool = True, **kwargs: dict[str, type]) -> None:
threshold_filter3: str = None, reset: bool = True,
**kwargs: dict[str, type]) -> None:
"""
Custom implementation of the base method.
Expand Down
2 changes: 1 addition & 1 deletion guibot/guibot.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def add_path(self, directory: str) -> None:
Add a path to the list of currently accessible paths
if it wasn't already added.
:param str directory: path to add
:param directory: path to add
"""
self.file_resolver.add_path(directory)

Expand Down
3 changes: 1 addition & 2 deletions guibot/guibot_proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
from .guibot import GuiBot


def serialize_custom_error(class_obj: "classobj") -> dict[str, str | getset_descriptor | dictproxy]:
def serialize_custom_error(class_obj: "classobj") -> dict[str, str | "getset_descriptor" | "dictproxy"]:
"""
Serialization method for the :py:class:`errors.UnsupportedBackendError`
which was chosen just as a sample.
Expand Down Expand Up @@ -90,7 +90,6 @@ def __init__(self, dc: Controller = None, cv: Finder = None) -> None:
register_exception_serialization()

def _proxify(self, obj: str) -> str:
#..todo:: obj is not documented
if isinstance(obj, (int, float, bool, str)) or obj is None:
return obj
if obj not in self._pyroDaemon.objectsById.values():
Expand Down
32 changes: 16 additions & 16 deletions guibot/guibot_simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def sample(*args: tuple[type, ...], **kwargs: dict[str, type]) -> float:
return guibot.sample(*args, **kwargs)


def exists(*args: tuple[type, ...], **kwargs: dict[str, type]) -> Match:
def exists(*args: tuple[type, ...], **kwargs: dict[str, type]) -> "Match":
"""See :py:class:`guibot.guibot.GuiBot` and its inherited :py:class:`guibot.region.Region` for details."""
check_initialized()
return guibot.exists(*args, **kwargs)
Expand All @@ -109,7 +109,7 @@ def wait_vanish(*args: tuple[type, ...], **kwargs: dict[str, type]) -> Region:
return guibot.wait_vanish(*args, **kwargs)


def get_mouse_location(*args: tuple[type, ...], **kwargs: dict[str, type]) -> Location:
def get_mouse_location(*args: tuple[type, ...], **kwargs: dict[str, type]) -> "Location":
"""See :py:class:`guibot.guibot.GuiBot` and its inherited :py:class:`guibot.region.Region` for details."""
check_initialized()
return guibot.get_mouse_location(*args, **kwargs)
Expand All @@ -121,79 +121,79 @@ def idle(*args: tuple[type, ...], **kwargs: dict[str, type]) -> Region:
return guibot.idle(*args, **kwargs)


def hover(*args: tuple[type, ...], **kwargs: dict[str, type]) -> Match:
def hover(*args: tuple[type, ...], **kwargs: dict[str, type]) -> "Match":
"""See :py:class:`guibot.guibot.GuiBot` and its inherited :py:class:`guibot.region.Region` for details."""
check_initialized()
return guibot.hover(*args, **kwargs)


def click(*args: tuple[type, ...], **kwargs: dict[str, type]) -> Match:
def click(*args: tuple[type, ...], **kwargs: dict[str, type]) -> "Match":
"""See :py:class:`guibot.guibot.GuiBot` and its inherited :py:class:`guibot.region.Region` for details."""
check_initialized()
return guibot.click(*args, **kwargs)


def right_click(*args: tuple[type, ...], **kwargs: dict[str, type]) -> Match:
def right_click(*args: tuple[type, ...], **kwargs: dict[str, type]) -> "Match":
"""See :py:class:`guibot.guibot.GuiBot` and its inherited :py:class:`guibot.region.Region` for details."""
check_initialized()
return guibot.right_click(*args, **kwargs)


def middle_click(*args: tuple[type, ...], **kwargs: dict[str, type]) -> Match:
def middle_click(*args: tuple[type, ...], **kwargs: dict[str, type]) -> "Match":
"""See :py:class:`guibot.guibot.GuiBot` and its inherited :py:class:`guibot.region.Region` for details."""
check_initialized()
return guibot.middle_click(*args, **kwargs)


def double_click(*args: tuple[type, ...], **kwargs: dict[str, type]) -> Match:
def double_click(*args: tuple[type, ...], **kwargs: dict[str, type]) -> "Match":
"""See :py:class:`guibot.guibot.GuiBot` and its inherited :py:class:`guibot.region.Region` for details."""
check_initialized()
return guibot.double_click(*args, **kwargs)


def multi_click(*args: tuple[type, ...], **kwargs: dict[str, type]) -> Match:
def multi_click(*args: tuple[type, ...], **kwargs: dict[str, type]) -> "Match":
"""See :py:class:`guibot.guibot.GuiBot` and its inherited :py:class:`guibot.region.Region` for details."""
check_initialized()
return guibot.multi_click(*args, **kwargs)


def click_expect(*args: tuple[type, ...], **kwargs: dict[str, type]) -> Match:
def click_expect(*args: tuple[type, ...], **kwargs: dict[str, type]) -> "Match":
"""See :py:class:`guibot.guibot.GuiBot` and its inherited :py:class:`guibot.region.Region` for details."""
check_initialized()
return guibot.click_expect(*args, **kwargs)


def click_vanish(*args: tuple[type, ...], **kwargs: dict[str, type]) -> Match:
def click_vanish(*args: tuple[type, ...], **kwargs: dict[str, type]) -> "Match":
"""See :py:class:`guibot.guibot.GuiBot` and its inherited :py:class:`guibot.region.Region` for details."""
check_initialized()
return guibot.click_vanish(*args, **kwargs)


def click_at_index(*args: tuple[type, ...], **kwargs: dict[str, type]) -> Match:
def click_at_index(*args: tuple[type, ...], **kwargs: dict[str, type]) -> "Match":
"""See :py:class:`guibot.guibot.GuiBot` and its inherited :py:class:`guibot.region.Region` for details."""
check_initialized()
return guibot.click_at_index(*args, **kwargs)


def mouse_down(*args: tuple[type, ...], **kwargs: dict[str, type]) -> Match:
def mouse_down(*args: tuple[type, ...], **kwargs: dict[str, type]) -> "Match":
"""See :py:class:`guibot.guibot.GuiBot` and its inherited :py:class:`guibot.region.Region` for details."""
check_initialized()
return guibot.mouse_down(*args, **kwargs)


def mouse_up(*args: tuple[type, ...], **kwargs: dict[str, type]) -> Match:
def mouse_up(*args: tuple[type, ...], **kwargs: dict[str, type]) -> "Match":
"""See :py:class:`guibot.guibot.GuiBot` and its inherited :py:class:`guibot.region.Region` for details."""
check_initialized()
return guibot.mouse_up(*args, **kwargs)


def mouse_scroll(*args: tuple[type, ...], **kwargs: dict[str, type]) -> Match:
def mouse_scroll(*args: tuple[type, ...], **kwargs: dict[str, type]) -> "Match":
"""See :py:class:`guibot.guibot.GuiBot` and its inherited :py:class:`guibot.region.Region` for details."""
check_initialized()
return guibot.mouse_scroll(*args, **kwargs)


def drag_drop(*args: tuple[type, ...], **kwargs: dict[str, type]) -> Match:
def drag_drop(*args: tuple[type, ...], **kwargs: dict[str, type]) -> "Match":
"""See :py:class:`guibot.guibot.GuiBot` and its inherited :py:class:`guibot.region.Region` for details."""
check_initialized()
return guibot.drag_drop(*args, **kwargs)
Expand All @@ -205,7 +205,7 @@ def drag_from(*args: tuple[type, ...], **kwargs: dict[str, type]) -> Region:
return guibot.drag_from(*args, **kwargs)


def drop_at(*args: tuple[type, ...], **kwargs: dict[str, type]) -> Match:
def drop_at(*args: tuple[type, ...], **kwargs: dict[str, type]) -> "Match":
"""See :py:class:`guibot.guibot.GuiBot` and its inherited :py:class:`guibot.region.Region` for details."""
check_initialized()
return guibot.drop_at(*args, **kwargs)
Expand Down
4 changes: 2 additions & 2 deletions guibot/location.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ def __init__(self, xpos: int = 0, ypos: int = 0) -> None:
"""
Build a location object.
:param int xpos: x coordinate of the location
:param int ypos: y coordinate of the location
:param xpos: x coordinate of the location
:param ypos: y coordinate of the location
"""
self._xpos = xpos
self._ypos = ypos
Expand Down
5 changes: 3 additions & 2 deletions guibot/match.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ class Match(Region):
of matches on a screen.
"""

def __init__(self, xpos: int, ypos: int, width: int, height: int, dx: int = 0, dy: int = 0,
similarity: float = 0.0, dc: Controller = None, cv: "Finder" = None) -> None:
def __init__(self, xpos: int, ypos: int, width: int, height: int,
dx: int = 0, dy: int = 0, similarity: float = 0.0,
dc: Controller = None, cv: "Finder" = None) -> None:
"""
Build a match object.
Expand Down
Loading

0 comments on commit d40c948

Please sign in to comment.