Compare commits

..

11 Commits

Author SHA1 Message Date
dw-0
8170057434 fix(moonraker): correctly patch trusted_clients options
fixes #711 #709

Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2025-08-03 10:07:13 +02:00
Maksym Pyrozhok
985b66d41f chore: fix typos (#695)
Fix typo.
2025-07-12 19:36:38 +02:00
dw-0
f95d2586bf fix(webclient): add config.json to moonraker persistent files (#699)
fixes #694

Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2025-06-28 10:12:28 +02:00
dw-0
f5141e7eff fix(mainsail): check for json configured as instanceDB (#698)
fix(mainsail): check for json configures as instanceDB

Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2025-06-27 22:37:44 +02:00
dw-0
33113e72e9 fix: exception raised on pip warning (#688)
pip seems to write to stderr on warnings, caused by retries. even if the process exits with 0.

Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2025-05-31 17:44:02 +02:00
dw-0
6f59fd06aa fix: do not upgrade pip before installing packages (#680)
pip 25 seems to introduce some compatibility issues.

Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2025-05-02 20:08:32 +02:00
dw-0
56ea43ccb6 refactor: improve typesafety KiauhSettings
Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2025-04-14 21:19:38 +02:00
dw-0
25e22c993f chore(scp): update SimpleConfigParser
Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2025-04-14 21:15:12 +02:00
dw-0
ead521b377 refactor: replace mypy with pyright
Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2025-04-14 21:07:56 +02:00
dw-0
3c952ccc12 refactor: use sane fallbacks on missing kiauh config options
for some options a warning is print if the fallback is used

Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2025-04-12 15:12:11 +02:00
dw-0
c8f713c00e fix: no validation of optional_speedups option
Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2025-04-12 00:36:34 +02:00
15 changed files with 225 additions and 199 deletions

View File

@@ -126,7 +126,7 @@ def create_example_moonraker_conf(
scp.read_file(target) scp.read_file(target)
trusted_clients: List[str] = [ trusted_clients: List[str] = [
f" {'.'.join(ip)}\n", f" {'.'.join(ip)}\n",
*scp.getval("authorization", "trusted_clients"), *scp.getvals("authorization", "trusted_clients"),
] ]
scp.set_option("server", "port", str(port)) scp.set_option("server", "port", str(port))

View File

@@ -102,6 +102,7 @@ def install_client(
section=f"update_manager {client.name}", section=f"update_manager {client.name}",
instances=mr_instances, instances=mr_instances,
options=[ options=[
("persistent_files", ["config.json"]),
("type", "web"), ("type", "web"),
("channel", "stable"), ("channel", "stable"),
("repo", str(client.repo_path)), ("repo", str(client.repo_path)),

View File

@@ -118,8 +118,8 @@ def enable_mainsail_remotemode() -> None:
c_json = MainsailData().client_dir.joinpath("config.json") c_json = MainsailData().client_dir.joinpath("config.json")
with open(c_json, "r") as f: with open(c_json, "r") as f:
config_data = json.load(f) config_data = json.load(f)
if config_data["instancesDB"] == "browser": if config_data["instancesDB"] == "browser" or config_data["instancesDB"] == "json":
Logger.print_info("Remote mode already configured. Skipped ...") Logger.print_info("Remote mode already configured. Skipped ...")
return return

View File

@@ -8,14 +8,15 @@
# ======================================================================= # # ======================================================================= #
from __future__ import annotations from __future__ import annotations
import shutil
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Any, List from typing import Any, Callable, List, TypeVar
from components.klipper import KLIPPER_REPO_URL
from components.moonraker import MOONRAKER_REPO_URL
from core.backup_manager.backup_manager import BackupManager from core.backup_manager.backup_manager import BackupManager
from core.logger import DialogType, Logger from core.logger import DialogType, Logger
from core.submodules.simple_config_parser.src.simple_config_parser.simple_config_parser import ( from core.submodules.simple_config_parser.src.simple_config_parser.simple_config_parser import (
NoOptionError,
NoSectionError,
SimpleConfigParser, SimpleConfigParser,
) )
from utils.input_utils import get_confirm from utils.input_utils import get_confirm
@@ -26,13 +27,7 @@ from kiauh import PROJECT_ROOT
DEFAULT_CFG = PROJECT_ROOT.joinpath("default.kiauh.cfg") DEFAULT_CFG = PROJECT_ROOT.joinpath("default.kiauh.cfg")
CUSTOM_CFG = PROJECT_ROOT.joinpath("kiauh.cfg") CUSTOM_CFG = PROJECT_ROOT.joinpath("kiauh.cfg")
T = TypeVar("T")
class NoValueError(Exception):
"""Raised when a required value is not defined for an option"""
def __init__(self, section: str, option: str):
msg = f"Missing value for option '{option}' in section '{section}'"
super().__init__(msg)
class InvalidValueError(Exception): class InvalidValueError(Exception):
@@ -53,17 +48,20 @@ class Repository:
url: str url: str
branch: str branch: str
@dataclass @dataclass
class KlipperSettings: class KlipperSettings:
repositories: List[Repository] | None = field(default=None) repositories: List[Repository] | None = field(default=None)
use_python_binary: str | None = field(default=None) use_python_binary: str | None = field(default=None)
@dataclass @dataclass
class MoonrakerSettings: class MoonrakerSettings:
optional_speedups: bool | None = field(default=None) optional_speedups: bool | None = field(default=None)
repositories: List[Repository] | None = field(default=None) repositories: List[Repository] | None = field(default=None)
use_python_binary: str | None = field(default=None) use_python_binary: str | None = field(default=None)
@dataclass @dataclass
class WebUiSettings: class WebUiSettings:
port: int | None = field(default=None) port: int | None = field(default=None)
@@ -74,6 +72,7 @@ class WebUiSettings:
# noinspection PyMethodMayBeStatic # noinspection PyMethodMayBeStatic
class KiauhSettings: class KiauhSettings:
__instance = None __instance = None
__initialized = False
def __new__(cls, *args, **kwargs) -> "KiauhSettings": def __new__(cls, *args, **kwargs) -> "KiauhSettings":
if cls.__instance is None: if cls.__instance is None:
@@ -91,11 +90,10 @@ class KiauhSettings:
return getattr(self, item) return getattr(self, item)
def __init__(self) -> None: def __init__(self) -> None:
if not hasattr(self, "__initialized"):
self.__initialized = False
if self.__initialized: if self.__initialized:
return return
self.__initialized = True self.__initialized = True
self.config = SimpleConfigParser() self.config = SimpleConfigParser()
self.kiauh = AppSettings() self.kiauh = AppSettings()
self.klipper = KlipperSettings() self.klipper = KlipperSettings()
@@ -103,8 +101,9 @@ class KiauhSettings:
self.mainsail = WebUiSettings() self.mainsail = WebUiSettings()
self.fluidd = WebUiSettings() self.fluidd = WebUiSettings()
self._load_config() self.__read_config_set_internal_state()
# todo: refactor this, at least rename to something else!
def get(self, section: str, option: str) -> str | int | bool: def get(self, section: str, option: str) -> str | int | bool:
""" """
Get a value from the settings state by providing the section and option name as Get a value from the settings state by providing the section and option name as
@@ -122,135 +121,175 @@ class KiauhSettings:
raise raise
def save(self) -> None: def save(self) -> None:
self._set_config_options_state() self.__write_internal_state_to_cfg()
self.config.write_file(CUSTOM_CFG) self.__read_config_set_internal_state()
self._load_config()
def _load_config(self) -> None: def __read_config_set_internal_state(self) -> None:
if not CUSTOM_CFG.exists() and not DEFAULT_CFG.exists(): if not CUSTOM_CFG.exists() and not DEFAULT_CFG.exists():
self.__kill() Logger.print_dialog(
DialogType.ERROR,
cfg = CUSTOM_CFG if CUSTOM_CFG.exists() else DEFAULT_CFG [
self.config.read_file(cfg) "No KIAUH configuration file found! Please make sure you have at least "
"one of the following configuration files in KIAUH's root directory:",
needs_migration = self._check_deprecated_repo_config() "● default.kiauh.cfg",
if needs_migration: "● kiauh.cfg",
self._prompt_migration_dialog() ],
return )
else:
# Only validate if no migration was needed
self._validate_cfg()
self.__set_internal_state()
def _validate_cfg(self) -> None:
def __err_and_kill(error: str) -> None:
Logger.print_error(f"Error validating kiauh.cfg: {error}")
kill() kill()
try: # copy default config to custom config if it does not exist
self._validate_bool("kiauh", "backup_before_update") if not CUSTOM_CFG.exists():
shutil.copyfile(DEFAULT_CFG, CUSTOM_CFG)
self._validate_repositories("klipper", "repositories") self.config.read_file(CUSTOM_CFG)
self._validate_repositories("moonraker", "repositories")
self._validate_int("mainsail", "port") # check if there are deprecated repo_url and branch options in the kiauh.cfg
self._validate_bool("mainsail", "unstable_releases") if self._check_deprecated_repo_config():
self._prompt_migration_dialog()
self._validate_int("fluidd", "port") self.__set_internal_state()
self._validate_bool("fluidd", "unstable_releases")
self._validate_bool("moonraker", "optional_speedups")
except ValueError:
err = f"Invalid value for option '{self._v_option}' in section '{self._v_section}'"
__err_and_kill(err)
except NoSectionError:
err = f"Missing section '{self._v_section}' in config file"
__err_and_kill(err)
except NoOptionError:
err = f"Missing option '{self._v_option}' in section '{self._v_section}'"
__err_and_kill(err)
except NoValueError:
err = f"Missing value for option '{self._v_option}' in section '{self._v_section}'"
__err_and_kill(err)
def _validate_bool(self, section: str, option: str) -> None:
self._v_section, self._v_option = (section, option)
(bool(self.config.getboolean(section, option)))
def _validate_int(self, section: str, option: str) -> None:
self._v_section, self._v_option = (section, option)
int(self.config.getint(section, option))
def _validate_str(self, section: str, option: str) -> None:
self._v_section, self._v_option = (section, option)
v = self.config.getval(section, option)
if not v:
raise ValueError
def _validate_repositories(self, section: str, option: str) -> None:
self._v_section, self._v_option = (section, option)
repos = self.config.getval(section, option)
if not repos:
raise NoValueError(section, option)
for repo in repos:
if repo.strip().startswith("#") or repo.strip().startswith(";"):
continue
try:
if "," in repo:
url, branch = repo.strip().split(",")
if not url:
raise InvalidValueError(section, option, repo)
else:
url = repo.strip()
if not url:
raise InvalidValueError(section, option, repo)
except ValueError:
raise InvalidValueError(section, option, repo)
def __set_internal_state(self) -> None: def __set_internal_state(self) -> None:
self.kiauh.backup_before_update = self.config.getboolean( # parse Kiauh options
"kiauh", "backup_before_update" self.kiauh.backup_before_update = self.__read_from_cfg(
"kiauh",
"backup_before_update",
self.config.getboolean,
False,
) )
self.moonraker.optional_speedups = self.config.getboolean("moonraker", "optional_speedups", True) # parse Klipper options
self.klipper.use_python_binary = self.__read_from_cfg(
kl_repos = self.config.getval("klipper", "repositories") "klipper",
self.klipper.repositories = self.__set_repo_state(kl_repos) "use_python_binary",
self.config.getval,
mr_repos = self.config.getval("moonraker", "repositories") None,
self.moonraker.repositories = self.__set_repo_state(mr_repos) True,
self.klipper.use_python_binary = self.config.getval("klipper", "use_python_binary", None)
self.moonraker.use_python_binary = self.config.getval("moonraker", "use_python_binary", None)
self.mainsail.port = self.config.getint("mainsail", "port")
self.mainsail.unstable_releases = self.config.getboolean(
"mainsail", "unstable_releases"
) )
self.fluidd.port = self.config.getint("fluidd", "port") kl_repos: List[str] = self.__read_from_cfg(
self.fluidd.unstable_releases = self.config.getboolean( "klipper",
"fluidd", "unstable_releases" "repositories",
self.config.getvals,
[KLIPPER_REPO_URL],
)
self.klipper.repositories = self.__set_repo_state("klipper", kl_repos)
# parse Moonraker options
self.moonraker.use_python_binary = self.__read_from_cfg(
"moonraker",
"use_python_binary",
self.config.getval,
None,
True,
)
self.moonraker.optional_speedups = self.__read_from_cfg(
"moonraker",
"optional_speedups",
self.config.getboolean,
True,
)
mr_repos: List[str] = self.__read_from_cfg(
"moonraker",
"repositories",
self.config.getvals,
[MOONRAKER_REPO_URL],
)
self.moonraker.repositories = self.__set_repo_state("moonraker", mr_repos)
# parse Mainsail options
self.mainsail.port = self.__read_from_cfg(
"mainsail",
"port",
self.config.getint,
80,
)
self.mainsail.unstable_releases = self.__read_from_cfg(
"mainsail",
"unstable_releases",
self.config.getboolean,
False,
) )
def __set_repo_state(self, repos: List[str]) -> List[Repository]: # parse Fluidd options
self.fluidd.port = self.__read_from_cfg(
"fluidd",
"port",
self.config.getint,
80,
)
self.fluidd.unstable_releases = self.__read_from_cfg(
"fluidd",
"unstable_releases",
self.config.getboolean,
False,
)
def __check_option_exists(
self, section: str, option: str, fallback: Any, silent: bool = False
) -> bool:
has_section = self.config.has_section(section)
has_option = self.config.has_option(section, option)
if not (has_section and has_option):
if not silent:
Logger.print_warn(
f"Option '{option}' in section '{section}' not defined. Falling back to '{fallback}'."
)
return False
return True
def __read_bool_from_cfg(
self,
section: str,
option: str,
fallback: bool | None = None,
silent: bool = False,
) -> bool | None:
if not self.__check_option_exists(section, option, fallback, silent):
return fallback
return self.config.getboolean(section, option, fallback)
def __read_from_cfg(
self,
section: str,
option: str,
getter: Callable[[str, str, T | None], T],
fallback: T = None,
silent: bool = False,
) -> T:
if not self.__check_option_exists(section, option, fallback, silent):
return fallback
return getter(section, option, fallback)
def __set_repo_state(self, section: str, repos: List[str]) -> List[Repository]:
_repos: List[Repository] = [] _repos: List[Repository] = []
for repo in repos: for repo in repos:
if repo.strip().startswith("#") or repo.strip().startswith(";"): try:
continue if repo.strip().startswith("#") or repo.strip().startswith(";"):
if "," in repo: continue
url, branch = repo.strip().split(",") if "," in repo:
if not branch: url, branch = repo.strip().split(",")
if not branch:
branch = "master"
else:
url = repo.strip()
branch = "master" branch = "master"
else:
url = repo.strip() # url must not be empty otherwise it's considered
branch = "master" # as an unrecoverable, invalid configuration
_repos.append(Repository(url.strip(), branch.strip())) if not url:
raise InvalidValueError(section, "repositories", repo)
_repos.append(Repository(url.strip(), branch.strip()))
except InvalidValueError as e:
Logger.print_error(f"Error parsing kiauh.cfg: {e}")
kill()
return _repos return _repos
def _set_config_options_state(self) -> None: def __write_internal_state_to_cfg(self) -> None:
"""Updates the config with current settings, preserving values that haven't been modified""" """Updates the config with current settings, preserving values that haven't been modified"""
if self.kiauh.backup_before_update is not None: if self.kiauh.backup_before_update is not None:
self.config.set_option( self.config.set_option(
@@ -288,6 +327,8 @@ class KiauhSettings:
"fluidd", "unstable_releases", str(self.fluidd.unstable_releases) "fluidd", "unstable_releases", str(self.fluidd.unstable_releases)
) )
self.config.write_file(CUSTOM_CFG)
def _check_deprecated_repo_config(self) -> bool: def _check_deprecated_repo_config(self) -> bool:
# repo_url and branch are deprecated - 2025.03.23 # repo_url and branch are deprecated - 2025.03.23
for section in ["klipper", "moonraker"]: for section in ["klipper", "moonraker"]:
@@ -299,22 +340,23 @@ class KiauhSettings:
def _prompt_migration_dialog(self) -> None: def _prompt_migration_dialog(self) -> None:
migration_1: List[str] = [ migration_1: List[str] = [
"The old 'repo_url' and 'branch' options are now combined under 'repositories'.", "Options 'repo_url' and 'branch' are now combined into a 'repositories' option.",
"\n\n", "\n\n",
"Example format:", "● Old format:",
"[klipper]", " [klipper]",
"repositories:", " repo_url: https://github.com/Klipper3d/klipper",
" https://github.com/Klipper3d/klipper, master", " branch: master",
"\n\n", "\n\n",
"[moonraker]", "● New format:",
"repositories:", " [klipper]",
" https://github.com/Arksine/moonraker, master", " repositories:",
" https://github.com/Klipper3d/klipper, master",
] ]
Logger.print_dialog( Logger.print_dialog(
DialogType.ATTENTION, DialogType.ATTENTION,
[ [
"Deprecated repository configuration found!", "Deprecated kiauh.cfg configuration found!",
"KAIUH can now attempt to automatically migrate your configuration.", "KAIUH can now attempt to automatically migrate the configuration.",
"\n\n", "\n\n",
*migration_1, *migration_1,
], ],
@@ -325,7 +367,7 @@ class KiauhSettings:
Logger.print_dialog( Logger.print_dialog(
DialogType.ERROR, DialogType.ERROR,
[ [
"Please update your configuration file manually.", "Please update the configuration file manually.",
], ],
center_content=True, center_content=True,
) )
@@ -366,23 +408,7 @@ class KiauhSettings:
self.config.write_file(CUSTOM_CFG) self.config.write_file(CUSTOM_CFG)
self.config.read_file(CUSTOM_CFG) # reload config self.config.read_file(CUSTOM_CFG) # reload config
# Validate the migrated config
self._validate_cfg()
self.__set_internal_state()
except Exception as e: except Exception as e:
Logger.print_error(f"Error migrating configuration: {e}") Logger.print_error(f"Error migrating configuration: {e}")
Logger.print_error("Please migrate manually.") Logger.print_error("Please migrate manually.")
kill() kill()
def __kill(self) -> None:
Logger.print_dialog(
DialogType.ERROR,
[
"No KIAUH configuration file found! Please make sure you have at least "
"one of the following configuration files in KIAUH's root directory:",
"● default.kiauh.cfg",
"● kiauh.cfg",
],
)
kill()

View File

@@ -314,9 +314,7 @@ class SimpleConfigParser:
elements.pop(i) elements.pop(i)
break break
def getval( def getval(self, section: str, option: str, fallback: str | _UNSET = _UNSET) -> str:
self, section: str, option: str, fallback: str | _UNSET = _UNSET
) -> str | List[str]:
""" """
Return the value of the given option in the given section Return the value of the given option in the given section
@@ -329,22 +327,34 @@ class SimpleConfigParser:
if option not in self.get_options(section): if option not in self.get_options(section):
raise NoOptionError(option, section) raise NoOptionError(option, section)
# Find the option in the elements list
for element in self.config[section]["elements"]: for element in self.config[section]["elements"]:
if element["type"] in [LineType.OPTION.value, LineType.OPTION_BLOCK.value] and element["name"] == option: if element["type"] is LineType.OPTION.value and element["name"] == option:
raw_value = element["value"] return str(element["value"].strip().replace("\n", ""))
if isinstance(raw_value, str) and raw_value.endswith("\n"): return ""
return raw_value[:-1].strip()
elif isinstance(raw_value, list): except (NoSectionError, NoOptionError):
values: List[str] = [] if fallback is _UNSET:
for i, val in enumerate(raw_value): raise
val = val.strip().strip("\n") return fallback
if len(val) < 1:
continue def getvals(self, section: str, option: str, fallback: List[str] | _UNSET = _UNSET) -> List[str]:
values.append(val.strip()) """
return values Return the values of the given multi-line option in the given section
return str(raw_value)
raise NoOptionError(option, section) If the key is not found and 'fallback' is provided, it is used as
a fallback value.
"""
try:
if section not in self.get_sections():
raise NoSectionError(section)
if option not in self.get_options(section):
raise NoOptionError(option, section)
for element in self.config[section]["elements"]:
if element["type"] is LineType.OPTION_BLOCK.value and element["name"] == option:
return [val.strip() for val in element["value"] if val.strip()]
return []
except (NoSectionError, NoOptionError): except (NoSectionError, NoOptionError):
if fallback is _UNSET: if fallback is _UNSET:
raise raise

View File

@@ -51,7 +51,7 @@ def test_getval(parser):
assert parser.getval("section_2", "option_2") == "value_2" assert parser.getval("section_2", "option_2") == "value_2"
# test multiline option values # test multiline option values
ml_val = parser.getval("section number 5", "multi_option") ml_val = parser.getvals("section number 5", "multi_option")
assert isinstance(ml_val, list) assert isinstance(ml_val, list)
assert len(ml_val) > 0 assert len(ml_val) > 0
@@ -164,7 +164,7 @@ def test_set_new_option(parser):
assert parser.getval("new_section", "very_new_option") == "very_new_value" assert parser.getval("new_section", "very_new_option") == "very_new_value"
parser.set_option("section_2", "array_option", ["value_1", "value_2", "value_3"]) parser.set_option("section_2", "array_option", ["value_1", "value_2", "value_3"])
assert parser.getval("section_2", "array_option") == [ assert parser.getvals("section_2", "array_option") == [
"value_1", "value_1",
"value_2", "value_2",
"value_3", "value_3",

View File

@@ -11,7 +11,7 @@ from __future__ import annotations
import shutil import shutil
import tempfile import tempfile
from pathlib import Path from pathlib import Path
from typing import List, Tuple from typing import List, Tuple, Union
from core.logger import Logger from core.logger import Logger
from core.submodules.simple_config_parser.src.simple_config_parser.simple_config_parser import ( from core.submodules.simple_config_parser.src.simple_config_parser.simple_config_parser import (
@@ -19,7 +19,7 @@ from core.submodules.simple_config_parser.src.simple_config_parser.simple_config
) )
from utils.instance_type import InstanceType from utils.instance_type import InstanceType
ConfigOption = Tuple[str, str] ConfigOption = Tuple[str, Union[str, List[str]]]
def add_config_section( def add_config_section(

View File

@@ -184,9 +184,6 @@ def install_python_requirements(target: Path, requirements: Path) -> None:
:return: None :return: None
""" """
try: try:
# always update pip before installing requirements
update_python_pip(target)
Logger.print_status("Installing Python requirements ...") Logger.print_status("Installing Python requirements ...")
command = [ command = [
target.joinpath("bin/pip").as_posix(), target.joinpath("bin/pip").as_posix(),
@@ -196,7 +193,7 @@ def install_python_requirements(target: Path, requirements: Path) -> None:
] ]
result = run(command, stderr=PIPE, text=True) result = run(command, stderr=PIPE, text=True)
if result.returncode != 0 or result.stderr: if result.returncode != 0:
Logger.print_error(f"{result.stderr}", False) Logger.print_error(f"{result.stderr}", False)
raise VenvCreationFailedException("Installing Python requirements failed!") raise VenvCreationFailedException("Installing Python requirements failed!")
@@ -216,9 +213,6 @@ def install_python_packages(target: Path, packages: List[str]) -> None:
:return: None :return: None
""" """
try: try:
# always update pip before installing requirements
update_python_pip(target)
Logger.print_status("Installing Python requirements ...") Logger.print_status("Installing Python requirements ...")
command = [ command = [
target.joinpath("bin/pip").as_posix(), target.joinpath("bin/pip").as_posix(),
@@ -228,7 +222,7 @@ def install_python_packages(target: Path, packages: List[str]) -> None:
command.append(pkg) command.append(pkg)
result = run(command, stderr=PIPE, text=True) result = run(command, stderr=PIPE, text=True)
if result.returncode != 0 or result.stderr: if result.returncode != 0:
Logger.print_error(f"{result.stderr}", False) Logger.print_error(f"{result.stderr}", False)
raise VenvCreationFailedException("Installing Python requirements failed!") raise VenvCreationFailedException("Installing Python requirements failed!")

View File

@@ -2,7 +2,7 @@
requires-python = ">=3.8" requires-python = ">=3.8"
[project.optional-dependencies] [project.optional-dependencies]
dev=["ruff", "mypy"] dev=["ruff", "pyright"]
[tool.ruff] [tool.ruff]
required-version = ">=0.9.10" required-version = ">=0.9.10"
@@ -20,14 +20,3 @@ quote-style = "double"
[tool.ruff.lint] [tool.ruff.lint]
extend-select = ["I"] extend-select = ["I"]
[tool.mypy]
python_version = "3.8"
platform = "linux"
# strict = true # TODO: enable this once everything is else is handled
check_untyped_defs = true
ignore_missing_imports = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_return_any = true
warn_unreachable = true

6
pyrightconfig.json Normal file
View File

@@ -0,0 +1,6 @@
{
"pythonVersion": "3.8",
"pythonPlatform": "Linux",
"typeCheckingMode": "standard",
"venvPath": "./.kiauh-env"
}

2
requirements-dev.txt Normal file
View File

@@ -0,0 +1,2 @@
ruff (>=0.9.10)
pyright

View File

@@ -280,7 +280,6 @@ function create_klipper_virtualenv() {
status_msg "Installing $("python${python_version}" -V) virtual environment..." status_msg "Installing $("python${python_version}" -V) virtual environment..."
if virtualenv -p "python${python_version}" "${KLIPPY_ENV}"; then if virtualenv -p "python${python_version}" "${KLIPPY_ENV}"; then
(( python_version == 3 )) && "${KLIPPY_ENV}"/bin/pip install -U pip
"${KLIPPY_ENV}"/bin/pip install -r "${KLIPPER_DIR}"/scripts/klippy-requirements.txt "${KLIPPY_ENV}"/bin/pip install -r "${KLIPPER_DIR}"/scripts/klippy-requirements.txt
else else
log_error "failure while creating python3 klippy-env" log_error "failure while creating python3 klippy-env"

View File

@@ -126,7 +126,7 @@ function update_klipperscreen() {
git checkout -f master && ok_msg "Checkout successfull" git checkout -f master && ok_msg "Checkout successfull"
if [[ $(md5sum "${KLIPPERSCREEN_DIR}/scripts/KlipperScreen-requirements.txt" | cut -d " " -f1) != "${old_md5}" ]]; then if [[ $(md5sum "${KLIPPERSCREEN_DIR}/scripts/KlipperScreen-requirements.txt" | cut -d " " -f1) != "${old_md5}" ]]; then
status_msg "New dependecies detected..." status_msg "New dependencies detected..."
"${KLIPPERSCREEN_ENV}"/bin/pip install -r "${KLIPPERSCREEN_DIR}/scripts/KlipperScreen-requirements.txt" "${KLIPPERSCREEN_ENV}"/bin/pip install -r "${KLIPPERSCREEN_DIR}/scripts/KlipperScreen-requirements.txt"
ok_msg "Dependencies have been installed!" ok_msg "Dependencies have been installed!"
fi fi

View File

@@ -133,7 +133,7 @@ function update_mobileraker() {
git checkout -f main && ok_msg "Checkout successfull" git checkout -f main && ok_msg "Checkout successfull"
if [[ $(md5sum "${MOBILERAKER_DIR}/scripts/mobileraker-requirements.txt" | cut -d " " -f1) != "${old_md5}" ]]; then if [[ $(md5sum "${MOBILERAKER_DIR}/scripts/mobileraker-requirements.txt" | cut -d " " -f1) != "${old_md5}" ]]; then
status_msg "New dependecies detected..." status_msg "New dependencies detected..."
"${MOBILERAKER_ENV}"/bin/pip install -r "${MOBILERAKER_DIR}/scripts/mobileraker-requirements.txt" "${MOBILERAKER_ENV}"/bin/pip install -r "${MOBILERAKER_DIR}/scripts/mobileraker-requirements.txt"
ok_msg "Dependencies have been installed!" ok_msg "Dependencies have been installed!"
fi fi

View File

@@ -336,7 +336,6 @@ function create_moonraker_virtualenv() {
[[ -d ${MOONRAKER_ENV} ]] && rm -rf "${MOONRAKER_ENV}" [[ -d ${MOONRAKER_ENV} ]] && rm -rf "${MOONRAKER_ENV}"
if virtualenv -p /usr/bin/python3 "${MOONRAKER_ENV}"; then if virtualenv -p /usr/bin/python3 "${MOONRAKER_ENV}"; then
"${MOONRAKER_ENV}"/bin/pip install -U pip
"${MOONRAKER_ENV}"/bin/pip install -r "${MOONRAKER_DIR}/scripts/moonraker-requirements.txt" "${MOONRAKER_ENV}"/bin/pip install -r "${MOONRAKER_DIR}/scripts/moonraker-requirements.txt"
else else
log_error "failure while creating python3 moonraker-env" log_error "failure while creating python3 moonraker-env"