diff --git a/katrain/KataGo/analysis_config.cfg b/katrain/KataGo/analysis_config.cfg index 6c8bba0..7a9510a 100644 --- a/katrain/KataGo/analysis_config.cfg +++ b/katrain/KataGo/analysis_config.cfg @@ -5,7 +5,7 @@ # Logs------------------------------------------------------------------------------------ # Where to output log? -logFile = gtp.log +logFile = "~/.katrain/katago_log.txt" # Controls the number of moves after the first move in a variation. # analysisPVLen = 15 diff --git a/katrain/__main__.py b/katrain/__main__.py index 30dfeb4..163a94f 100644 --- a/katrain/__main__.py +++ b/katrain/__main__.py @@ -3,7 +3,7 @@ import os # isort:skip os.environ["KCFG_KIVY_LOG_LEVEL"] = os.environ.get("KCFG_KIVY_LOG_LEVEL", "warning") # isort:skip surpress info output from kivy.config import Config # isort:skip -ICON = "img/icon.png" # isort:skip # set icon +ICON = "img/icon.ico" # isort:skip # set icon Config.set("kivy", "window_icon", ICON) # isort:skip # set icon Config.set("input", "mouse", "mouse,multitouch_on_demand") # isort:skip # no red dots on right click Config.set("graphics", "width", 1300) # isort:skip @@ -27,7 +27,7 @@ from katrain.core.utils import ( DEFAULT_LANGUAGE, find_package_resource, ) -from katrain.core.constants import OUTPUT_ERROR, OUTPUT_KATAGO_STDERR, OUTPUT_INFO, OUTPUT_DEBUG, OUTPUT_EXTRA_DEBUG, MODE_PLAY, AI_STRATEGIES_RECOMMENDED_ORDER, HOMEPAGE +from katrain.core.constants import OUTPUT_ERROR, OUTPUT_KATAGO_STDERR, OUTPUT_INFO, OUTPUT_DEBUG, OUTPUT_EXTRA_DEBUG, MODE_PLAY, HOMEPAGE, VERSION from katrain.gui.popups import ConfigTeacherPopup, ConfigTimerPopup, I18NPopup from katrain.core.base_katrain import KaTrainBase from katrain.core.engine import KataGoEngine @@ -41,7 +41,6 @@ from katrain.gui.controlspanel import ControlsPanel from katrain.gui.popups import ConfigPopup, LoadSGFPopup, NewGamePopup, AIPopup from katrain.gui.style import ENGINE_BUSY_COL, ENGINE_DOWN_COL, ENGINE_READY_COL -__version__ = "1.1.0" class KaTrainGui(Screen, KaTrainBase): @@ -367,7 +366,7 @@ class KaTrainApp(MDApp): def build(self): self.icon = ICON # how you're supposed to set an icon self.gui = KaTrainGui() - self.title = f"KaTrain v{__version__}" + self.title = f"KaTrain v{VERSION}" self.theme_cls.theme_style = "Dark" self.theme_cls.primary_palette = "Blue" diff --git a/katrain/config.json b/katrain/config.json index 174fb96..ac0bf8b 100644 --- a/katrain/config.json +++ b/katrain/config.json @@ -17,7 +17,8 @@ "sgf_save": "./sgfout", "anim_pv_time": 0.5, "debug_level": 0, - "lang": "en" + "lang": "en", + "version": "1.1.0" }, "timer": { "byo_length": 30, @@ -64,7 +65,7 @@ true ], "eval_off_show_last": 3, - "eval_show_ai": false, + "eval_show_ai": true, "lock_ai": true }, "ai": { diff --git a/katrain/core/base_katrain.py b/katrain/core/base_katrain.py index ebd61e4..db52555 100644 --- a/katrain/core/base_katrain.py +++ b/katrain/core/base_katrain.py @@ -1,7 +1,7 @@ from kivy import Config from kivy.properties import ObjectProperty from kivy.storage.jsonstore import JsonStore -import os, sys +import os, sys, shutil from katrain.core.constants import * from katrain.core.utils import find_package_resource @@ -38,7 +38,8 @@ class Player: class KaTrainBase: - CONFIG_FILE = "katrain/config.json" + USER_CONFIG_FILE = os.path.expanduser("~/.katrain/config.json") + PACKAGE_CONFIG_FILE = "katrain/config.json" """Settings, logging, and players functionality, so other classes like bots who need a katrain instance can be used without a GUI""" @@ -66,15 +67,38 @@ class KaTrainBase: print(message) def _load_config(self): - config_file = os.path.abspath(sys.argv[1] if len(sys.argv) > 1 and sys.argv[1].endswith(".json") else find_package_resource(self.CONFIG_FILE)) + if len(sys.argv) > 1 and sys.argv[1].endswith(".json"): + config_file = os.path.abspath(sys.argv[1]) + self.log(f"Using command line config file {config_file}", OUTPUT_INFO) + else: + user_config_file = find_package_resource(self.USER_CONFIG_FILE) + package_config_file = find_package_resource(self.PACKAGE_CONFIG_FILE) + try: + if not os.path.exists(user_config_file): + os.makedirs(os.path.split(user_config_file)[0], exist_ok=True) + shutil.copyfile(package_config_file,user_config_file) + config_file = user_config_file + self.log(f"Copied package config to local file {config_file}", OUTPUT_INFO) + else: # user file exists + version = JsonStore(user_config_file, indent=4).get("general")["version"] + if version != VERSION: + backup = user_config_file+f".{version}.backup" + shutil.copyfile(user_config_file,backup) + shutil.copyfile(package_config_file, user_config_file) + self.log(f"Copied package config file to {user_config_file} as user file is outdated (<{VERSION}). Old version stored as {backup}", OUTPUT_INFO) + config_file = user_config_file + self.log(f"Using user config file {config_file}", OUTPUT_INFO) + except Exception as e: + config_file = package_config_file + self.log(f"Using package config file {config_file} (exception {e} occurred when finding or creating user config)", OUTPUT_INFO) try: - self.log(f"Using config file {config_file}", OUTPUT_INFO) self._config_store = JsonStore(config_file, indent=4) - self._config = dict(self._config_store) - return config_file except Exception as e: self.log(f"Failed to load config {config_file}: {e}", OUTPUT_ERROR) sys.exit(1) + self._config = dict(self._config_store) + return config_file + def save_config(self): for k, v in self._config.items(): diff --git a/katrain/core/constants.py b/katrain/core/constants.py index eff89c0..4be237b 100644 --- a/katrain/core/constants.py +++ b/katrain/core/constants.py @@ -1,3 +1,4 @@ +VERSION = "1.1.0" HOMEPAGE = "https://github.com/sanderland/katrain" PLAYER_HUMAN, PLAYER_AI = "player:human", "player:ai" diff --git a/katrain/core/engine.py b/katrain/core/engine.py index fbe72b4..2b3df32 100644 --- a/katrain/core/engine.py +++ b/katrain/core/engine.py @@ -55,7 +55,10 @@ class KataGoEngine: def start(self): try: self.katrain.log(f"Starting KataGo with {self.command}", OUTPUT_DEBUG) - self.katago_process = subprocess.Popen(self.command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + self.katago_process = subprocess.Popen(self.command, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, + shell=True) except (FileNotFoundError, PermissionError, OSError) as e: if not self.config["katago"].strip(): self.katrain.log( diff --git a/katrain/img/icon.ico b/katrain/img/icon.ico new file mode 100644 index 0000000..b1d9a37 Binary files /dev/null and b/katrain/img/icon.ico differ diff --git a/katrain/img/icon.png b/katrain/img/icon.png deleted file mode 100644 index 204ec05..0000000 Binary files a/katrain/img/icon.png and /dev/null differ diff --git a/setup.py b/setup.py index 0e138df..76d1550 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ from setuptools import find_packages, setup package_data = {"": ["*.json", "*.kv"], "katrain": [], "tests": []} packages = find_packages(exclude=["tests"]) -version = re.search('^__version__\s*=\s*"(.*)"', open("katrain/__main__.py").read(), re.M).group(1) +version = re.search('^VERSION\s*=\s*"(.*)"', open("katrain/core/constants.py").read(), re.M).group(1) def include_data_files(directory): diff --git a/spec/KaTrain.spec b/spec/KaTrain.spec index 45c4ca1..6fa2e14 100644 --- a/spec/KaTrain.spec +++ b/spec/KaTrain.spec @@ -1,50 +1,85 @@ # -*- mode: python ; coding: utf-8 -*- from kivy_deps import sdl2, glew +from kivymd import hooks_path as kivymd_hooks_path block_cipher = None # pyinstaller spec/katrain.spec --noconfirm # --upx-dir my -a = Analysis(['..\\katrain\\__main__.py'], - pathex=['C:\\Users\\sande\\Desktop\\katrain\\spec'], - binaries=[], - datas=[('..\\katrain\\gui.kv','katrain'),('..\\katrain\\config.json','katrain'), - ('..\\katrain\\KataGo','katrain\KataGo'),('..\\katrain\img','katrain\img'), - ('..\\katrain\\models','katrain\models')], - hiddenimports=["win32file","win32timezone"], # FileChooser in kivy loads this conditionally - hookspath=[], - runtime_hooks=[], - excludes=['scipy','pandas','numpy','matplotlib','docutils','mkl'], - win_no_prefer_redirects=False, - win_private_assemblies=False, - cipher=block_cipher, - noarchive=False) +a = Analysis( + ["..\\katrain\\__main__.py"], + pathex=["C:\\Users\\sande\\Desktop\\katrain\\spec"], + binaries=[], + datas=[ + ("..\\katrain\\gui.kv", "katrain"), + ("..\\katrain\\popups.kv", "katrain"), + ("..\\katrain\\config.json", "katrain"), + ("..\\katrain\\KataGo", "katrain\\KataGo"), + ("..\\katrain\img", "katrain\\img"), + ("..\\katrain\\models", "katrain\\models"), + ("..\\katrain\\i18n", "katrain\\i18n"), + ("..\\katrain\\fonts", "katrain\\fonts"), + ], + hiddenimports=["win32file", "win32timezone"], # FileChooser in kivy loads this conditionally + hookspath=[kivymd_hooks_path], + excludes=["scipy", "pandas", "numpy", "matplotlib", "docutils", "mkl"], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=None, + noarchive=False, +) -print("SCRIPTS",a.scripts) +print("SCRIPTS", len(a.scripts), "BIN", len(a.binaries), "ZIP", len(a.zipfiles), "DATA", len(a.datas)) -pyz = PYZ(a.pure, a.zipped_data, - cipher=block_cipher) -exe = EXE(pyz, - a.scripts, - [], - exclude_binaries=True, - name='KaTrain', - debug=False, - bootloader_ignore_signals=False, - strip=False, - upx=True, - console=True) # , icon='..\\icon.png' +EXCLUDE_SUFFIX = ["katago"] +EXCLUDE = ["KataGoData", "anim_", "screenshot_", "__pycache__", "locales/haha"] +a.datas = [ + (ff, ft, tp) + for ff, ft, tp in a.datas + if not any(ff.endswith(suffix) for suffix in EXCLUDE_SUFFIX) and not any(kw in ff for kw in EXCLUDE) +] -EXCLUDE_SUFFIX = ['katago'] -EXCLUDE = ['KataGoData','anim_','screenshot_','__pycache__'] -a.datas = [(ff,ft,tp) for ff,ft,tp in a.datas if not any(ff.endswith(suffix) for suffix in EXCLUDE_SUFFIX) and not any(kw in ff for kw in EXCLUDE)] -coll = COLLECT(exe, - a.binaries, - a.zipfiles, - a.datas, - *[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)], - strip=False, - upx=True, - upx_exclude=[], - name='KaTrain') +print("DATA FILTERED", len(a.datas)) + +pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) +exe = EXE( + pyz, + a.scripts, + [], + exclude_binaries=True, + name="KaTrain", + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + console=False, + icon="C:\\icon.ico", +) + +coll = COLLECT( + exe, + a.binaries, + a.zipfiles, + a.datas, + *[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)], + strip=False, + upx=True, + upx_exclude=[], + name="KaTrain", +) + +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.zipfiles, + a.datas, + *[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)], + debug=False, + strip=False, + upx=True, + name="KaTrain", + console=False, + icon="C:\\icon.ico", +)