documentation and code cleanup: auto_update, config, helper

This commit is contained in:
DESKTOP-JVKHS7I\Adam 2020-05-12 11:43:42 +05:30
parent 30b8477d8d
commit bb83a33b82
6 changed files with 98 additions and 76 deletions

View File

@ -1,3 +1,8 @@
"""
auto_update.py
checks version and auto updates
"""
import re import re
import subprocess import subprocess
import sys import sys
@ -9,6 +14,13 @@ from bs4 import BeautifulSoup
def _normalize_version(v): def _normalize_version(v):
"""
converts version string into an "normalized" of versions which is a list of version codes,
eg, input: '0.3.0', output: [0,3,0]
this is done so that, versions can be compared easily
:param v: string
:return: list
"""
rv = [] rv = []
for x in v.split("."): for x in v.split("."):
try: try:
@ -24,6 +36,12 @@ def _normalize_version(v):
def _get_highest_version(index, pkg): def _get_highest_version(index, pkg):
"""
Crawls web for latest version name then returns latest version
:param index: website to check
:param pkg: package name
:return: latest version normalized
"""
url = "{}/{}/".format(index, pkg) url = "{}/{}/".format(index, pkg)
html = urllib.request.urlopen(url) html = urllib.request.urlopen(url)
if html.getcode() != 200: if html.getcode() != 200:
@ -43,10 +61,20 @@ def _get_highest_version(index, pkg):
def _get_current_version(pkg): def _get_current_version(pkg):
"""
Gets the current version of the package installed
:param pkg: name of the installed backage
:return: version normalized
"""
return _normalize_version(pkg_resources.get_distribution(pkg).version) return _normalize_version(pkg_resources.get_distribution(pkg).version)
def auto_upgrade(): def auto_upgrade():
"""
public function,
compares current version with the latest version (from web),
if current version is older, then it updates and restarts the script
"""
index = "https://pypi.python.org/simple" index = "https://pypi.python.org/simple"
pkg = "fishy" pkg = "fishy"
if _get_highest_version(index, pkg) > _get_current_version(pkg): if _get_highest_version(index, pkg) > _get_current_version(pkg):

View File

@ -1,30 +1,56 @@
"""
config.py
Saves configuration in file as json file
"""
import json import json
import os import os
from threading import Thread
# path to save the configuration file
filename = os.path.expanduser(r"~/Documents/fishy_config.json") filename = os.path.expanduser(r"~/Documents/fishy_config.json")
class Config: class Config:
def __init__(self): def __init__(self):
"""
cache the configuration in a dict for faster access,
if file is not found initialize the dict
"""
self.config_dict = json.loads(open(filename).read()) if os.path.exists(filename) else dict() self.config_dict = json.loads(open(filename).read()) if os.path.exists(filename) else dict()
def get(self, key, default=None): def get(self, key, default=None):
if key in self.config_dict: """
return self.config_dict[key] gets a value from configuration,
return default if it is not found, return the default configuration
:param key: key of the config
:param default: default value to return if key is not found
:return: config value
"""
return self.config_dict[key] if key in self.config_dict else default
def set(self, key, value, save=True): def set(self, key, value, save=True):
"""
saves the configuration is cache (and saves it in file if needed)
:param key: key to save
:param value: value to save
:param save: False if don't want to save right away
"""
self.config_dict[key] = value self.config_dict[key] = value
if save: if save:
self.save_config() self.save_config()
def delete(self, key): def delete(self, key):
"""
deletes a key from config
:param key: key to delete
"""
del self.config_dict[key] del self.config_dict[key]
self.save_config() self.save_config()
def save_config(self): def save_config(self):
"""
save the cache to the file
"""
with open(filename, 'w') as f: with open(filename, 'w') as f:
f.write(json.dumps(self.config_dict)) f.write(json.dumps(self.config_dict))

View File

@ -1,4 +1,5 @@
""" """
fishing_event.py
Defines different fishing modes (states) which acts as state for state machine Defines different fishing modes (states) which acts as state for state machine
also implements callbacks which is called when states are changed also implements callbacks which is called when states are changed
""" """
@ -10,7 +11,6 @@ import pyautogui
from fishy.systems import web from fishy.systems import web
from fishy.systems.globals import G from fishy.systems.globals import G
from fishy.systems.helper import round_float
class FishEvent(ABC): class FishEvent(ABC):
@ -41,7 +41,7 @@ class HookEvent(FishEvent):
timeToHook = time.time() - G.stickInitTime timeToHook = time.time() - G.stickInitTime
G.fish_times.append(timeToHook) G.fish_times.append(timeToHook)
logging.info("HOOOOOOOOOOOOOOOOOOOOOOOK....... " + str(G.fishCaught) + " caught " + "in " + str( logging.info("HOOOOOOOOOOOOOOOOOOOOOOOK....... " + str(G.fishCaught) + " caught " + "in " + str(
round_float(timeToHook)) + " secs. " + "Total: " + str(G.totalFishCaught)) round(timeToHook, 2)) + " secs. " + "Total: " + str(G.totalFishCaught))
pyautogui.press(self.action_key) pyautogui.press(self.action_key)
if self.collect_r: if self.collect_r:

View File

@ -74,7 +74,7 @@ class GUI:
self.root.title("Fiishybot for Elder Scrolls Online") self.root.title("Fiishybot for Elder Scrolls Online")
self.root.geometry('650x550') self.root.geometry('650x550')
self.root.iconbitmap(helper.get_data_file_path('icon.ico')) self.root.iconbitmap(helper.manifest_file('icon.ico'))
# region menu # region menu
menubar = Menu(self.root) menubar = Menu(self.root)

View File

@ -1,16 +1,12 @@
import logging import logging
import os import os
import shutil
import sys import sys
import threading import threading
import traceback import traceback
import webbrowser import webbrowser
from decimal import Decimal
from threading import Thread from threading import Thread
from zipfile import ZipFile from zipfile import ZipFile
import cv2
import numpy as np
from uuid import uuid1 from uuid import uuid1
from hashlib import md5 from hashlib import md5
@ -18,52 +14,22 @@ from win32com.client import Dispatch
import fishy import fishy
import winshell import winshell
import functools
from fishy.systems.gui import GUIFunction
def round_float(v, ndigits=2, rt_str=False):
"""
Rounds float
:param v: float ot round off
:param ndigits: round off to ndigits decimal points
:param rt_str: true to return string
:return: rounded float or strings
"""
d = Decimal(v)
v_str = ("{0:.%sf}" % ndigits).format(round(d, ndigits))
if rt_str:
return v_str
return Decimal(v_str)
def draw_keypoints(vis, keypoints, color=(0, 0, 255)):
"""
draws a point on cv2 image array
:param vis: cv2 image array to draw
:param keypoints: keypoints array to draw
:param color: color of the point
"""
for kp in keypoints:
x, y = kp.pt
cv2.circle(vis, (int(x), int(y)), 5, color, -1)
def enable_full_array_printing():
"""
Used to enable full array logging
(summarized arrays are printed by default)
"""
np.set_printoptions(threshold=sys.maxsize)
def open_web(website): def open_web(website):
"""
Opens a website on browser,
uses multi-threading so that current thread doesnt get blocked
:param website: url
"""
logging.debug("opening web, please wait...") logging.debug("opening web, please wait...")
Thread(target=lambda: webbrowser.open(website, new=2)).start() Thread(target=lambda: webbrowser.open(website, new=2)).start()
def create_new_uid(): def create_new_uid():
"""
Creates a unique id for user
"""
return md5(str(uuid1()).encode()).hexdigest() return md5(str(uuid1()).encode()).hexdigest()
@ -95,50 +61,52 @@ def unhandled_exception_logging(*exc_info):
logging.error("Unhandled exception: %s", text) logging.error("Unhandled exception: %s", text)
def get_data_file_path(rel_path): def manifest_file(rel_path):
"""
returns a file from the manifest files,
used to get the files which are installed along with the scripts
:param rel_path: relative path from `__init__.py`
:return: abs path of the file
"""
return os.path.join(os.path.dirname(fishy.__file__), rel_path) return os.path.join(os.path.dirname(fishy.__file__), rel_path)
def create_shortcut(gui): def create_shortcut(gui):
"""
creates a new shortcut on desktop
:param gui: does nothing todo
"""
try: try:
user = os.path.expanduser("~") desktop = winshell.desktop()
if os.path.exists(os.path.join(user, "Desktop")): path = os.path.join(desktop, "Fishybot ESO.lnk")
path = os.path.join(user, "Desktop", "Fishybot ESO.lnk")
_copy_shortcut(path)
else:
gui.call(GUIFunction.ASK_DIRECTORY, (_copy_shortcut,
"Could not find Desktop please specify path to create shortcut"))
except Exception:
logging.info("Couldn't create shortcut")
traceback.print_exc()
shell = Dispatch('WScript.Shell')
shortcut = shell.CreateShortCut(path)
shortcut.Targetpath = os.path.join(os.path.dirname(sys.executable), "python.exe")
shortcut.Arguments = "-m fishy"
shortcut.IconLocation = manifest_file("icon.ico")
shortcut.save()
def _copy_shortcut(path): logging.info("Shortcut created")
desktop = winshell.desktop() except:
path = os.path.join(desktop, "Fishybot ESO.lnk") logging.error("Couldn't create shortcut")
shell = Dispatch('WScript.Shell')
shortcut = shell.CreateShortCut(path)
shortcut.Targetpath = os.path.join(os.path.dirname(sys.executable), "python.exe")
shortcut.Arguments = "-m fishy"
shortcut.IconLocation = get_data_file_path("icon.ico")
shortcut.save()
logging.info("Shortcut created")
def check_addon(): def check_addon():
"""
Extracts the addon from zip and installs it into the AddOn folder of eso
"""
try: try:
user = os.path.expanduser("~") user = os.path.expanduser("~")
addon_dir = os.path.join(user, "Documents", "Elder Scrolls Online", "live", "Addons") addon_dir = os.path.join(user, "Documents", "Elder Scrolls Online", "live", "Addons")
if not os.path.exists(os.path.join(addon_dir, 'ProvisionsChalutier')): if not os.path.exists(os.path.join(addon_dir, 'ProvisionsChalutier')):
logging.info("Addon not found, installing it...") logging.info("Addon not found, installing it...")
with ZipFile(get_data_file_path("ProvisionsChalutier.zip"), 'r') as zip: with ZipFile(manifest_file("ProvisionsChalutier.zip"), 'r') as zip:
zip.extractall(path=addon_dir) zip.extractall(path=addon_dir)
logging.info("Please make sure you enable \"Allow outdated addons\" in-game\n" logging.info("Please make sure you enable \"Allow outdated addons\" in-game\n"
"Also, make sure the addon is visible clearly on top left corner of the game window") "Also, make sure the addon is visible clearly on top left corner of the game window")
except Exception: except Exception:
print("couldn't install addon, try doing it manually") logging.error("couldn't install addon, try doing it manually")
def restart(): def restart():

View File

@ -31,12 +31,12 @@ def _run_terms_window(config: Config):
message = f'I agree to the [Terms of Service and Privacy Policy]({web.get_terms_page()})' message = f'I agree to the [Terms of Service and Privacy Policy]({web.get_terms_page()})'
root.title("EULA") root.title("EULA")
root.resizable(False, False) root.resizable(False, False)
root.iconbitmap(helper.get_data_file_path('icon.ico')) root.iconbitmap(helper.manifest_file('icon.ico'))
f = Frame(root) f = Frame(root)
canvas = Canvas(f, width=300, height=200) canvas = Canvas(f, width=300, height=200)
canvas.pack() canvas.pack()
root.image = Image.open(helper.get_data_file_path('fishybot_logo.png')).resize((300, 200)) root.image = Image.open(helper.manifest_file('fishybot_logo.png')).resize((300, 200))
root.image = ImageTk.PhotoImage(root.image) root.image = ImageTk.PhotoImage(root.image)
canvas.create_image(0, 0, anchor=NW, image=root.image) canvas.create_image(0, 0, anchor=NW, image=root.image)