From a30aa6f4038b0b26ad982ab42e44b91faab4dd73 Mon Sep 17 00:00:00 2001 From: DevilXD Date: Thu, 17 Mar 2022 12:33:53 +0100 Subject: [PATCH] Fix autostart working directory breaking paths --- constants.py | 13 +++++++++---- gui.py | 6 ++---- main.py | 5 ++--- settings.py | 10 +++------- twitch.py | 6 +++--- utils.py | 21 +++++++++++++++------ 6 files changed, 34 insertions(+), 27 deletions(-) diff --git a/constants.py b/constants.py index 390bfea..e9fc030 100644 --- a/constants.py +++ b/constants.py @@ -1,7 +1,9 @@ from __future__ import annotations +import sys import logging from copy import copy +from pathlib import Path from enum import Enum, auto from datetime import timedelta from typing import Any, Dict, Literal, TYPE_CHECKING @@ -14,6 +16,13 @@ if TYPE_CHECKING: from collections import abc # noqa +# Base Paths +SELF_PATH = Path(sys.argv[0]) +WORKING_DIR = SELF_PATH.absolute().parent +# Other Paths +LOG_PATH = Path(WORKING_DIR, "log.txt") +COOKIES_PATH = Path(WORKING_DIR, "cookies.jar") +SETTINGS_PATH = Path(WORKING_DIR, "settings.json") # Typing JsonType = Dict[str, Any] TopicProcess: TypeAlias = "abc.Callable[[int, JsonType], Any]" @@ -27,10 +36,6 @@ USER_AGENT = ( "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/99.0.4844.51 Safari/537.36" ) -# Paths -LOG_PATH = "log.txt" -COOKIES_PATH = "cookies.jar" -SETTINGS_PATH = "settings.json" # Intervals and Delays PING_INTERVAL = timedelta(minutes=3) PING_TIMEOUT = timedelta(seconds=10) diff --git a/gui.py b/gui.py index 90f9123..7a966f4 100644 --- a/gui.py +++ b/gui.py @@ -1,10 +1,8 @@ from __future__ import annotations -import sys import asyncio import logging import tkinter as tk -from pathlib import Path from math import log10, ceil from functools import partial from tkinter.font import Font @@ -19,7 +17,7 @@ except ModuleNotFoundError as exc: from utils import resource_path from registry import RegistryKey, ValueType -from constants import FORMATTER, WS_TOPICS_LIMIT, MAX_WEBSOCKETS, WINDOW_TITLE, State +from constants import SELF_PATH, FORMATTER, WS_TOPICS_LIMIT, MAX_WEBSOCKETS, WINDOW_TITLE, State if TYPE_CHECKING: from twitch import Twitch @@ -1099,7 +1097,7 @@ class SettingsPanel: self._settings.autostart_tray = tray if enabled: # NOTE: we need double quotes in case the path contains spaces - self_path = f'"{Path(sys.argv[0]).resolve()!s}"' + self_path = f'"{SELF_PATH.absolute().resolve()!s}"' if tray: self_path += " --tray" with RegistryKey("HKCU/Software/Microsoft/Windows/CurrentVersion/Run") as key: diff --git a/main.py b/main.py index 94b779a..6e34922 100644 --- a/main.py +++ b/main.py @@ -9,7 +9,6 @@ import logging import argparse import traceback import tkinter as tk -from pathlib import Path from tkinter import messagebox from typing import IO, NoReturn @@ -17,7 +16,7 @@ from twitch import Twitch from settings import Settings from version import __version__ from exceptions import CaptchaRequired -from constants import FORMATTER, LOG_PATH, WINDOW_TITLE +from constants import SELF_PATH, FORMATTER, LOG_PATH, WINDOW_TITLE class Parser(argparse.ArgumentParser): @@ -84,7 +83,7 @@ root.overrideredirect(True) root.withdraw() root.update() parser = Parser( - Path(sys.argv[0]).name, + SELF_PATH.name, description="A program that allows you to mine timed drops on Twitch.", ) parser.add_argument("--version", action="version", version=f"v{__version__}") diff --git a/settings.py b/settings.py index 148b2ac..157f3ad 100644 --- a/settings.py +++ b/settings.py @@ -2,7 +2,6 @@ from __future__ import annotations import json from enum import Enum -from pathlib import Path from typing import Any, TypedDict, TYPE_CHECKING from constants import JsonType, SETTINGS_PATH @@ -11,9 +10,6 @@ if TYPE_CHECKING: from main import ParsedArgs -PATH = Path(SETTINGS_PATH) - - class SettingsFile(TypedDict): autostart: bool exclude: set[str] @@ -72,8 +68,8 @@ class Settings: def __init__(self, args: ParsedArgs): self._settings: SettingsFile = default_settings.copy() - if PATH.exists(): - with open(PATH, 'r') as file: + if SETTINGS_PATH.exists(): + with open(SETTINGS_PATH, 'r') as file: self._settings.update(json.load(file, object_hook=deserialize)) self._args: ParsedArgs = args @@ -98,5 +94,5 @@ class Settings: raise RuntimeError("settings can't be deleted") def save(self) -> None: - with open(PATH, 'w') as file: + with open(SETTINGS_PATH, 'w') as file: json.dump(self._settings, file, default=serialize, sort_keys=True, indent=4) diff --git a/twitch.py b/twitch.py index 1a30b5f..36c24ee 100644 --- a/twitch.py +++ b/twitch.py @@ -1,6 +1,5 @@ from __future__ import annotations -import os import asyncio import logging from yarl import URL @@ -84,7 +83,7 @@ class Twitch: def initialize(self) -> None: cookie_jar = aiohttp.CookieJar() - if os.path.isfile(COOKIES_PATH): + if COOKIES_PATH.exists(): cookie_jar.load(COOKIES_PATH) self._session = aiohttp.ClientSession( cookie_jar=cookie_jar, @@ -101,7 +100,8 @@ class Twitch: self._watching_task = None # close session, save cookies and stop websocket if self._session is not None: - self._session.cookie_jar.save(COOKIES_PATH) # type: ignore + cookie_jar = cast(aiohttp.CookieJar, self._session.cookie_jar) + cookie_jar.save(COOKIES_PATH) await self._session.close() self._session = None await self.websocket.stop() diff --git a/utils.py b/utils.py index 8e50252..5eb274f 100644 --- a/utils.py +++ b/utils.py @@ -1,18 +1,18 @@ from __future__ import annotations -import os import sys import random import string import asyncio import logging +from pathlib import Path from functools import wraps from contextlib import suppress from datetime import datetime, timezone from collections import abc, OrderedDict from typing import Any, Literal, MutableSet, Generic, TypeVar, cast, TYPE_CHECKING -from constants import JsonType +from constants import WORKING_DIR, JsonType if TYPE_CHECKING: from typing_extensions import ParamSpec @@ -30,10 +30,19 @@ logger = logging.getLogger("TwitchDrops") NONCE_CHARS = string.ascii_letters + string.digits -def resource_path(relative_path): - """Get absolute path to resource, works for dev and for PyInstaller""" - base_path = getattr(sys, "_MEIPASS", os.path.dirname(os.path.abspath(__file__))) - return os.path.join(base_path, relative_path) +def resource_path(relative_path: Path | str) -> Path: + """ + Get an absolute path to a bundled resource. + + Works for dev and for PyInstaller. + """ + if hasattr(sys, "_MEIPASS"): + # PyInstaller's folder where the one-file app is unpacked + meipass: str = getattr(sys, "_MEIPASS") + base_path = Path(meipass) + else: + base_path = WORKING_DIR + return base_path.joinpath(relative_path) def timestamp(string: str) -> datetime: