diff --git a/.github/workflows/publish_assets.yaml b/.github/workflows/publish_assets.yaml deleted file mode 100644 index 7510b37..0000000 --- a/.github/workflows/publish_assets.yaml +++ /dev/null @@ -1,51 +0,0 @@ -# CI Code for generating and publishing beta assets - -name: publish_assets -on: - release: - types: [published] -jobs: - generate_assets: - runs-on: ubuntu-latest - steps: - - name: Checkout Moonraker - uses: actions/checkout@v2 - with: - fetch-depth: 0 - ref: ${{ github.ref }} - path: moonraker - - - name: Checkout Klipper - uses: actions/checkout@v2 - with: - fetch-depth: 0 - repository: Klipper3d/klipper - path: klipper - - - name: Build Beta Assets - if: ${{ github.event.release.prerelease }} - run: > - ./moonraker/scripts/build-zip-release.sh -b - -o ${{ github.workspace }} - -k ${{ github.workspace }}/klipper - - - name: Build Stable Assets - if: ${{ !github.event.release.prerelease }} - run: > - ./moonraker/scripts/build-zip-release.sh - -o ${{ github.workspace }} - -k ${{ github.workspace }}/klipper - - - name: Upload assets - run: | - cd moonraker - gh release upload ${{ env.TAG }} ${{ env.FILES }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - FILES: > - ${{ github.workspace }}/moonraker.zip - ${{ github.workspace }}/klipper.zip - ${{ github.workspace }}/RELEASE_INFO - ${{ github.workspace }}/COMMIT_LOG - TAG: ${{ github.event.release.tag_name }} - diff --git a/.gitignore b/.gitignore index b394201..5302af4 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,13 @@ __pycache__/ venv start_moonraker *.env +*.egg-info .pdm-python build dist share + +.vscode +.mypy_cache +.pdm-build +.pytest_cache diff --git a/moonraker/components/mqtt.py b/moonraker/components/mqtt.py index 498769c..cbb6f30 100644 --- a/moonraker/components/mqtt.py +++ b/moonraker/components/mqtt.py @@ -21,6 +21,10 @@ from ..common import ( KlippyState ) from ..utils import json_wrapper as jsonw +try: + from paho.mqtt.reasoncodes import ReasonCode +except ImportError: + from paho.mqtt.reasoncodes import ReasonCodes as ReasonCode # Annotation imports from typing import ( @@ -41,6 +45,7 @@ if TYPE_CHECKING: from ..common import JsonRPC, APIDefinition from ..eventloop import FlexTimer from .klippy_apis import KlippyAPI + from paho.mqtt.properties import Properties FlexCallback = Callable[[bytes], Optional[Coroutine]] RPCCallback = Callable[..., Coroutine] @@ -73,7 +78,7 @@ class ExtPahoClient(paho_mqtt.Client): "remaining_count": [], "remaining_mult": 1, "remaining_length": 0, - "packet": b"", + "packet": b"", # type: ignore "to_process": 0, "pos": 0 } @@ -100,7 +105,7 @@ class ExtPahoClient(paho_mqtt.Client): self._last_msg_out = paho_mqtt.time_func() self._ping_t = 0 - self._state = paho_mqtt.mqtt_cs_new + self._state = paho_mqtt.mqtt_cs_new # type: ignore self._sock_close() @@ -149,16 +154,16 @@ class ExtPahoClient(paho_mqtt.Client): if self._transport == "websockets": sock.settimeout(self._keepalive) - sock = paho_mqtt.WebsocketWrapper( + sock = paho_mqtt.WebsocketWrapper( # type: ignore sock, self._host, self._port, self._ssl, self._websocket_path, self._websocket_extra_headers ) # type: ignore - self._sock = sock + self._sock = sock # type: ignore assert self._sock is not None self._sock.setblocking(False) self._registered_write = False - self._call_socket_open() + self._call_socket_open() # type: ignore return self._send_connect(self._keepalive) @@ -233,7 +238,7 @@ class BrokerAckLogger: def __call__(self, fut: asyncio.Future) -> None: if self.action == "subscribe": - res: Union[List[int], List[paho_mqtt.ReasonCodes]] + res: Union[List[int], List[ReasonCode]] res = fut.result() log_msg = "MQTT Subscriptions Acknowledged" if len(res) != len(self.topics): @@ -243,7 +248,7 @@ class BrokerAckLogger: else: for topic, qos in zip(self.topics, res): log_msg += f"\n Topic: {topic} | " - if isinstance(qos, paho_mqtt.ReasonCodes): + if isinstance(qos, ReasonCode): log_msg += qos.getName() else: log_msg += f"Granted QoS {qos}" @@ -265,41 +270,44 @@ class AIOHelper: self.client.on_socket_open = self._on_socket_open self.client.on_socket_close = self._on_socket_close self.client._on_socket_register_write = self._on_socket_register_write - self.client._on_socket_unregister_write = \ - self._on_socket_unregister_write + self.client._on_socket_unregister_write = self._on_socket_unregister_write self.misc_task: Optional[asyncio.Task] = None - def _on_socket_open(self, - client: paho_mqtt.Client, - userdata: Any, - sock: socket.socket - ) -> None: + def _on_socket_open( + self, + client: paho_mqtt.Client, + userdata: Any, + sock: socket.socket | paho_mqtt.SocketLike + ) -> None: logging.info("MQTT Socket Opened") self.loop.add_reader(sock, client.loop_read) self.misc_task = self.loop.create_task(self.misc_loop()) - def _on_socket_close(self, - client: paho_mqtt.Client, - userdata: Any, - sock: socket.socket - ) -> None: + def _on_socket_close( + self, + client: paho_mqtt.Client, + userdata: Any, + sock: socket.socket | paho_mqtt.SocketLike + ) -> None: logging.info("MQTT Socket Closed") self.loop.remove_reader(sock) if self.misc_task is not None: self.misc_task.cancel() - def _on_socket_register_write(self, - client: paho_mqtt.Client, - userdata: Any, - sock: socket.socket - ) -> None: + def _on_socket_register_write( + self, + client: paho_mqtt.Client, + userdata: Any, + sock: socket.socket | paho_mqtt.SocketLike + ) -> None: self.loop.add_writer(sock, client.loop_write) - def _on_socket_unregister_write(self, - client: paho_mqtt.Client, - userdata: Any, - sock: socket.socket - ) -> None: + def _on_socket_unregister_write( + self, + client: paho_mqtt.Client, + userdata: Any, + sock: socket.socket | paho_mqtt.SocketLike + ) -> None: self.loop.remove_writer(sock) async def misc_loop(self) -> None: @@ -354,7 +362,9 @@ class MQTTClient(APITransport): config.getboolean("publish_split_status", False) client_id: str = config.get("client_id", "") if PAHO_MQTT_VERSION < (2, 0): - self.client = ExtPahoClient(client_id, protocol=self.protocol) + self.client = ExtPahoClient( + client_id, protocol=self.protocol # type: ignore + ) else: self.client = ExtPahoClient( paho_mqtt.CallbackAPIVersion.VERSION1, client_id, # type: ignore @@ -472,7 +482,7 @@ class MQTTClient(APITransport): self._publish_status_update(payload, self.last_status_time) def _on_message(self, - client: str, + client: str | paho_mqtt.Client, user_data: Any, message: paho_mqtt.MQTTMessage ) -> None: @@ -491,8 +501,8 @@ class MQTTClient(APITransport): client: paho_mqtt.Client, user_data: Any, flags: Dict[str, Any], - reason_code: Union[int, paho_mqtt.ReasonCodes], - properties: Optional[paho_mqtt.Properties] = None + reason_code: Union[int, ReasonCode], + properties: Optional[Properties] = None ) -> None: logging.info("MQTT Client Connected") if reason_code == 0: @@ -521,7 +531,7 @@ class MQTTClient(APITransport): client: paho_mqtt.Client, user_data: Any, reason_code: int, - properties: Optional[paho_mqtt.Properties] = None + properties: Optional[Properties] = None ) -> None: if self.disconnect_evt is not None: self.disconnect_evt.set() @@ -547,8 +557,8 @@ class MQTTClient(APITransport): client: paho_mqtt.Client, user_data: Any, msg_id: int, - flex: Union[List[int], List[paho_mqtt.ReasonCodes]], - properties: Optional[paho_mqtt.Properties] = None + flex: Union[List[int], List[ReasonCode]], + properties: Optional[Properties] = None ) -> None: sub_fut = self.pending_acks.pop(msg_id, None) if sub_fut is not None and not sub_fut.done(): @@ -558,8 +568,8 @@ class MQTTClient(APITransport): client: paho_mqtt.Client, user_data: Any, msg_id: int, - properties: Optional[paho_mqtt.Properties] = None, - reasoncodes: Optional[paho_mqtt.ReasonCodes] = None + properties: Optional[Properties] = None, + reasoncodes: Optional[ReasonCode] = None ) -> None: unsub_fut = self.pending_acks.pop(msg_id, None) if unsub_fut is not None and not unsub_fut.done(): diff --git a/moonraker/components/spoolman.py b/moonraker/components/spoolman.py index d922bea..a1bbf25 100644 --- a/moonraker/components/spoolman.py +++ b/moonraker/components/spoolman.py @@ -9,7 +9,9 @@ import asyncio import logging import re import contextlib +import base64 import tornado.websocket as tornado_ws +from tornado.httpclient import HTTPRequest from tornado import version_info as tornado_version from ..common import RequestType, HistoryFieldData from ..utils import json_wrapper as jsonw @@ -86,6 +88,23 @@ class SpoolManager: self.spoolman_url = f"{scheme}://{host}/api" self.ws_url = f"{ws_scheme}://{host}/api/v1/spool" + headers_raw = config.get("headers", "") + self.http_headers = {} + for c in headers_raw.split(";"): + c = c.strip() + if not c: + continue + c_parts = c.split(":", 1) + if len(c_parts) != 2: + raise config.error(f"Section [spoolman], Option headers: {c}: Invalid header format") + self.http_headers[c_parts[0]] = c_parts[1] + + username = config.get("http_username", None) + password = config.get("http_password", None) + if username and password: + creds = base64.b64encode(f"{username}:{password}".encode()).decode() + self.http_headers["Authorization"] = "Basic " + creds + def _register_notifications(self): self.server.register_notification("spoolman:active_spool_set") self.server.register_notification("spoolman:spoolman_status_changed") @@ -130,10 +149,10 @@ class SpoolManager: if log_connect: logging.info(f"Connecting To Spoolman: {self.ws_url}") log_connect = False + request = HTTPRequest(url=self.ws_url, headers=self.http_headers, connect_timeout=5.) try: self.spoolman_ws = await tornado_ws.websocket_connect( - self.ws_url, - connect_timeout=5., + request, ping_interval=None if tornado_version < (6, 5) else 20. ) setattr(self.spoolman_ws, "on_ping", self._on_ws_ping) @@ -217,7 +236,7 @@ class SpoolManager: if self.spool_id is not None: response = await self.http_client.get( f"{self.spoolman_url}/v1/spool/{self.spool_id}", - connect_timeout=1., request_timeout=2. + connect_timeout=1., request_timeout=2., headers=self.http_headers ) if response.status_code == 404: logging.info(f"Spool ID {self.spool_id} not found, setting to None") @@ -308,7 +327,8 @@ class SpoolManager: response = await self.http_client.request( method="PUT", url=f"{self.spoolman_url}/v1/spool/{spool_id}/use", - body={"use_length": used_length} + body={"use_length": used_length}, + headers=self.http_headers ) if response.has_error(): if response.status_code == 404: @@ -370,6 +390,7 @@ class SpoolManager: method=method, url=full_url, body=body, + headers=self.http_headers ) if not use_v2_response: response.raise_for_status() diff --git a/moonraker/components/update_manager/system_deploy.py b/moonraker/components/update_manager/system_deploy.py index 86c8958..ec22b34 100644 --- a/moonraker/components/update_manager/system_deploy.py +++ b/moonraker/components/update_manager/system_deploy.py @@ -392,6 +392,9 @@ class PackageKitTransaction: summary: str ) -> None: info = PkEnum.Info.from_index(info_code & 0xFFFF) + severity = PkEnum.Info.from_index((info_code >> 16) & 0xFFFF) + if info == PkEnum.Info.UNKNOWN: + info = severity if self._role in self.GET_PKG_ROLES: pkg_data = { 'package_id': package_id, diff --git a/moonraker/utils/sysdeps_parser.py b/moonraker/utils/sysdeps_parser.py index b25f45d..fc372c7 100644 --- a/moonraker/utils/sysdeps_parser.py +++ b/moonraker/utils/sysdeps_parser.py @@ -4,6 +4,7 @@ # # This file may be distributed under the terms of the GNU GPLv3 license from __future__ import annotations +import os import shlex import re import pathlib @@ -61,15 +62,22 @@ class SysDepsParser: version = distro_info.get("distro_version") if version: self.distro_version = _convert_version(version) - self.vendor: str = "" - if pathlib.Path("/etc/rpi-issue").is_file(): + self.vendor: str = os.getenv("MOONRAKER_VENDOR", "") + if not self.vendor and pathlib.Path("/etc/rpi-issue").is_file(): self.vendor = "raspberry-pi" + exclusions = os.getenv("MOONRAKER_EXCLUDED_PKGS", "") + self.exclusions: List[str] = [ + excl.strip() for excl in exclusions.split() if excl.strip() + ] def _parse_spec(self, full_spec: str) -> str | None: parts = full_spec.split(";", maxsplit=1) - if len(parts) == 1: - return full_spec pkg_name = parts[0].strip() + if pkg_name in self.exclusions or not pkg_name: + logging.info(f"Package '{full_spec}' excluded by environment") + return None + if len(parts) == 1: + return pkg_name expressions = re.split(r"( and | or )", parts[1].strip()) if not len(expressions) & 1: # There should always be an odd number of expressions. Each diff --git a/pyproject.toml b/pyproject.toml index 6adf300..1705191 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,23 +6,22 @@ authors = [ {name = "Eric Callahan", email = "arksine.code@gmail.com"}, ] dependencies = [ - "tornado>=6.2.0, <=6.5.1", + "tornado>=6.2.0, <=6.5.4", "pyserial==3.4", - "pillow>=9.5.0, <=11.1.0", + "pillow>=9.5.0, <=12.1.0", "streaming-form-data>=1.11.0, <=1.19.1", "distro==1.9.0", - "inotify-simple==1.3.5", + "inotify-simple==2.0.1", "libnacl==2.1.0", - "paho-mqtt==1.6.1", - "zeroconf==0.131.0", + "paho-mqtt==2.1.0", + "zeroconf>=0.131.0, <=0.148.0", "preprocess-cancellation==0.2.1", - "jinja2==3.1.5", - "dbus-fast>=2.21.3, <=2.44.1", - "apprise==1.9.2", + "jinja2==3.1.6", + "dbus-fast>=2.21.3, <=3.1.2", + "apprise>=1.9.3, <=1.9.6", "ldap3==2.9.1", "python-periphery==2.4.1", - "importlib_metadata==6.7.0 ; python_version=='3.7'", - "importlib_metadata==8.2.0 ; python_version>='3.8'" + "importlib_metadata>=6.7.0, <=8.7.1" ] requires-python = ">=3.7" readme = "README.md" @@ -38,6 +37,8 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14" ] [project.urls] @@ -53,7 +54,7 @@ speedups = [ "msgspec>=0.18.4 ; python_version>='3.8'", "uvloop>=0.17.0" ] -dev = ["pre-commit"] +dev = ["pre-commit", "build", "mypy", "ruff", "twine"] [tool.pdm.version] source = "scm" diff --git a/scripts/install-moonraker.sh b/scripts/install-moonraker.sh index 6df1612..fa62b46 100755 --- a/scripts/install-moonraker.sh +++ b/scripts/install-moonraker.sh @@ -12,6 +12,8 @@ LOG_PATH="${MOONRAKER_LOG_PATH}" DATA_PATH="${MOONRAKER_DATA_PATH}" INSTANCE_ALIAS="${MOONRAKER_ALIAS:-moonraker}" SPEEDUPS="${MOONRAKER_SPEEDUPS:-n}" +DEV_INSTALL="${MOONRAKER_DEV_INSTALL:-n}" +PY_INST_TYPE="${MOONRAKER_PYTHON_INSTALL_TYPE:-venv}" SERVICE_VERSION="1" DISTRIBUTION="" DISTRO_VERSION="" @@ -25,6 +27,14 @@ if [ ! -z "${MOONRAKER_FORCE_DEFAULTS}" ]; then FORCE_SYSTEM_INSTALL=$MOONRAKER_FORCE_DEFAULTS fi +# Check if this is a dev container, apply dev defaults if not set by environment +if [ "${MOONRAKER_VENDOR}" = "vscode-dev" ]; then + echo "VSCode Dev Container detected..." + [ -z "${MOONRAKER_DEV_INSTALL}" ] && DEV_INSTALL="y" + [ -z "${MOONRAKER_PYTHON_INSTALL_TYPE}" ] && PY_INST_TYPE="user" + [ -z "${MOONRAKER_DISABLE_SYSTEMCTL}" ] && DISABLE_SYSTEMCTL="y" +fi + # Force script to exit if an error occurs set -e @@ -34,6 +44,7 @@ SRCDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/.. && pwd )" # Determine if Moonraker is to be installed from source if [ -f "${SRCDIR}/moonraker/__init__.py" ]; then echo "Installing from Moonraker source..." + cd $SRCDIR IS_SRC_DIST="y" fi @@ -48,6 +59,7 @@ detect_distribution() { # *** AUTO GENERATED OS PACKAGE SCRIPT START *** get_pkgs_script=$(cat << EOF from __future__ import annotations +import os import shlex import re import pathlib @@ -101,15 +113,22 @@ class SysDepsParser: version = distro_info.get("distro_version") if version: self.distro_version = _convert_version(version) - self.vendor: str = "" - if pathlib.Path("/etc/rpi-issue").is_file(): + self.vendor: str = os.getenv("MOONRAKER_VENDOR", "") + if not self.vendor and pathlib.Path("/etc/rpi-issue").is_file(): self.vendor = "raspberry-pi" + exclusions = os.getenv("MOONRAKER_EXCLUDED_PKGS", "") + self.exclusions: List[str] = [ + excl.strip() for excl in exclusions.split() if excl.strip() + ] def _parse_spec(self, full_spec: str) -> str | None: parts = full_spec.split(";", maxsplit=1) - if len(parts) == 1: - return full_spec pkg_name = parts[0].strip() + if pkg_name in self.exclusions or not pkg_name: + logging.info(f"Package '{full_spec}' excluded by environment") + return None + if len(parts) == 1: + return pkg_name expressions = re.split(r"( and | or )", parts[1].strip()) if not len(expressions) & 1: logging.info( @@ -137,7 +156,7 @@ class SysDepsParser: continue elif last_logical_op is None: logging.info( - f"Requirement specifier contains two seqential expressions " + f"Requirement specifier contains two sequential expressions " f"without a logical operator: {full_spec}") return None dep_parts = re.split(r"(==|!=|<=|>=|<|>)", exp.strip()) @@ -270,38 +289,52 @@ install_packages() # Step 4: Create python virtual environment create_virtualenv() { - report_status "Installing python virtual environment..." + if [ $PY_INST_TYPE = "system" ]; then + pip_inst="pip install" + elif [ $PY_INST_TYPE = "user" ]; then + pip_inst="pip install --user" + else + pip_inst="${PYTHONDIR}/bin/pip install" + report_status "Installing python virtual environment..." - # If venv exists and user prompts a rebuild, then do so - if [ -d ${PYTHONDIR} ] && [ $REBUILD_ENV = "y" ]; then - report_status "Removing old virtualenv" - rm -rf ${PYTHONDIR} + # If venv exists and user prompts a rebuild, then do so + if [ -d ${PYTHONDIR} ] && [ $REBUILD_ENV = "y" ]; then + report_status "Removing old virtualenv" + rm -rf ${PYTHONDIR} + fi + + if [ ! -d ${PYTHONDIR} ]; then + virtualenv -p python3 ${PYTHONDIR} + #GET_PIP="${HOME}/get-pip.py" + #curl https://bootstrap.pypa.io/pip/3.6/get-pip.py -o ${GET_PIP} + #${PYTHONDIR}/bin/python ${GET_PIP} + #rm ${GET_PIP} + fi fi - - if [ ! -d ${PYTHONDIR} ]; then - virtualenv -p /usr/bin/python3 ${PYTHONDIR} - #GET_PIP="${HOME}/get-pip.py" - #curl https://bootstrap.pypa.io/pip/3.6/get-pip.py -o ${GET_PIP} - #${PYTHONDIR}/bin/python ${GET_PIP} - #rm ${GET_PIP} - fi - + echo "Using pip install command '${pip_inst}'..." # Install/update dependencies export SKIP_CYTHON=1 if [ $IS_SRC_DIST = "y" ]; then report_status "Installing Moonraker python dependencies..." - ${PYTHONDIR}/bin/pip install -r ${SRCDIR}/scripts/moonraker-requirements.txt + $pip_inst -r ${SRCDIR}/scripts/moonraker-requirements.txt - if [ ${SPEEDUPS} = "y" ]; then + if [ $DEV_INSTALL = "y" ]; then + report_status "Installing dev requirements..." + $pip_inst -r ${SRCDIR}/scripts/moonraker-speedups.txt + $pip_inst -r ${SRCDIR}/scripts/moonraker-dev-reqs.txt + $pip_inst -r ${SRCDIR}/docs/doc-requirements.txt + elif [ $SPEEDUPS = "y" ]; then report_status "Installing Speedups..." - ${PYTHONDIR}/bin/pip install -r ${SRCDIR}/scripts/moonraker-speedups.txt + $pip_inst -r ${SRCDIR}/scripts/moonraker-speedups.txt fi else report_status "Installing Moonraker package via Pip..." - if [ ${SPEEDUPS} = "y" ]; then - ${PYTHONDIR}/bin/pip install -U moonraker[speedups] + if [ $DEV_INSTALL = "y" ]; then + $pip_inst -U moonraker[speedups,dev] + elif [ $SPEEDUPS = "y" ]; then + $pip_inst -U moonraker[speedups] else - ${PYTHONDIR}/bin/pip install -U moonraker + $pip_inst -U moonraker fi fi } @@ -349,9 +382,13 @@ EOF # Step 6: Install startup script install_script() { + if [ ! -d $SYSTEMDDIR ]; then + report_status "Systemd not detected, aborting service installation" + fi # Create systemd service file ENV_FILE="${DATA_PATH}/systemd/moonraker.env" if [ ! -f $ENV_FILE ] || [ $FORCE_SYSTEM_INSTALL = "y" ]; then + report_status "Creating systemd environment file ${ENV_FILE}..." rm -f $ENV_FILE env_vars="MOONRAKER_DATA_PATH=\"${DATA_PATH}\"" [ -n "${CONFIG_PATH}" ] && env_vars="${env_vars}\nMOONRAKER_CONFIG_PATH=\"${CONFIG_PATH}\"" @@ -361,7 +398,9 @@ install_script() echo -e $env_vars > $ENV_FILE fi [ -f $SERVICE_FILE ] && [ $FORCE_SYSTEM_INSTALL = "n" ] && return - report_status "Installing system start script..." + report_status "Installing systemd service unit..." + python_bin="${PYTHONDIR}/bin/python" + [ $PY_INST_TYPE != "venv" ] && python_bin="python3" sudo groupadd -f moonraker-admin sudo /bin/sh -c "cat > ${SERVICE_FILE}" << EOF # systemd service file for moonraker @@ -379,7 +418,7 @@ User=$USER SupplementaryGroups=moonraker-admin RemainAfterExit=yes EnvironmentFile=${ENV_FILE} -ExecStart=${PYTHONDIR}/bin/python \$MOONRAKER_ARGS +ExecStart=${python_bin} \$MOONRAKER_ARGS Restart=always RestartSec=10 EOF diff --git a/scripts/moonraker-dev-reqs.txt b/scripts/moonraker-dev-reqs.txt index 416634f..7682609 100644 --- a/scripts/moonraker-dev-reqs.txt +++ b/scripts/moonraker-dev-reqs.txt @@ -1 +1,5 @@ pre-commit +build +mypy +ruff +twine diff --git a/scripts/moonraker-requirements.txt b/scripts/moonraker-requirements.txt index 401c0fd..dbb3340 100644 --- a/scripts/moonraker-requirements.txt +++ b/scripts/moonraker-requirements.txt @@ -1,19 +1,18 @@ # Python dependencies for Moonraker --find-links=python_wheels -tornado>=6.2.0, <=6.5.1 +tornado>=6.2.0, <=6.5.4 pyserial==3.4 -pillow>=9.5.0, <=11.1.0 +pillow>=9.5.0, <=12.1.0 streaming-form-data>=1.11.0, <=1.19.1 distro==1.9.0 -inotify-simple==1.3.5 +inotify-simple==2.0.1 libnacl==2.1.0 -paho-mqtt==1.6.1 -zeroconf==0.131.0 +paho-mqtt==2.1.0 +zeroconf>=0.131.0, <=0.148.0 preprocess-cancellation==0.2.1 -jinja2==3.1.5 -dbus-fast>=2.21.3, <=2.44.1 -apprise==1.9.2 +jinja2==3.1.6 +dbus-fast>=2.21.3, <=3.1.2 +apprise>=1.9.3, <=1.9.6 ldap3==2.9.1 python-periphery==2.4.1 -importlib_metadata==6.7.0 ; python_version=='3.7' -importlib_metadata==8.2.0 ; python_version>='3.8' +importlib_metadata>=6.7.0, <=8.7.1 diff --git a/scripts/python_wheels/zeroconf-0.136.2-py3-none-any.whl b/scripts/python_wheels/zeroconf-0.136.2-py3-none-any.whl new file mode 100644 index 0000000..c29a5af Binary files /dev/null and b/scripts/python_wheels/zeroconf-0.136.2-py3-none-any.whl differ diff --git a/scripts/python_wheels/zeroconf-0.148.0-py3-none-any.whl b/scripts/python_wheels/zeroconf-0.148.0-py3-none-any.whl new file mode 100644 index 0000000..41ba72d Binary files /dev/null and b/scripts/python_wheels/zeroconf-0.148.0-py3-none-any.whl differ