Compare commits

...

11 commits

Author SHA1 Message Date
3062378a7b Merge branch 'master' of https://github.com/Arksine/moonraker 2026-01-17 22:45:51 +01:00
Eric Callahan
bac55c65f8
workflows: delete stale github workflow
The "zip" style distribution of Moonraker was never deployed.

Signed-off-by: Eric Callahan <arksine.code@gmail.com>
2026-01-15 13:00:38 +00:00
Eric Callahan
63672ea38b
mqtt: update static types to support client version 2.0 or greater
Signed-off-by:  Eric Callahan <arksine.code@gmail.com>
2026-01-15 12:55:40 +00:00
Eric Callahan
4b751e79e1
build: update universal zeroconf wheels
Version 0.136.2 is the last release supporting Python 3.8,  0.148.0 is the latest release at the time of this commit.  These provide fallback options for
platforms for which wheels are not available.

Signed-off-by:  Eric Callahan <arksine.code@gmail.com>
2026-01-15 00:26:27 +00:00
Eric Callahan
3ea83163b0 build: update python dependencies to their latest versions
Signed-off-by:  Eric Callahan <arksine.code@gmail.com>
2026-01-14 16:21:49 +00:00
Eric Callahan
0e8dd923f8 install: add support for dev container installs
Add support for installing Moonraker inside a vscode "python"
dev container.

Signed-off-by:  Eric Callahan <arksine.code@gmail.com>
2026-01-14 12:49:16 +00:00
Eric Callahan
2b1c70a9e1 build: update python dev requirements
Signed-off-by:  Eric Callahan <arksine.code@gmail.com>
2026-01-14 12:49:16 +00:00
Eric Callahan
d7df2876dd sysdeps_parser: add support for env exclusions
A list of system package exclusions may be set via the
MOONRAKER_EXCLUDED_PKGS environment variable.
In addition, a MOONRAKER_VENDOR enviroment
variable has been added to allow for manually setting
the vendor name.

Signed-off-by:  Eric Callahan <arksine.code@gmail.com>
2026-01-14 12:49:16 +00:00
Eric Callahan
3e6378fbc6 repo: update gitignore file
Signed-off-by: Eric Callahan <arksine.code@gmail.com>
2026-01-14 12:49:16 +00:00
Eric Callahan
bdeddcabad system_deploy: check update severity bits in info_code
The update severity is stored in the upper 16 bits of the info code in
newer versions of package kit.  Some backends may omit the lower
16-bits and only store the severity, in those cases use the update
severity enum value in place of the info value.

Signed-off-by:  Eric Callahan <arksine.code@gmail.com>
2026-01-14 12:49:16 +00:00
82ce1ff26f feat: add spoolman auth support 2026-01-14 06:22:14 +01:00
12 changed files with 185 additions and 145 deletions

View file

@ -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 }}

6
.gitignore vendored
View file

@ -8,7 +8,13 @@ __pycache__/
venv
start_moonraker
*.env
*.egg-info
.pdm-python
build
dist
share
.vscode
.mypy_cache
.pdm-build
.pytest_cache

View file

@ -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,40 +270,43 @@ 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,
def _on_socket_open(
self,
client: paho_mqtt.Client,
userdata: Any,
sock: socket.socket
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,
def _on_socket_close(
self,
client: paho_mqtt.Client,
userdata: Any,
sock: socket.socket
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,
def _on_socket_register_write(
self,
client: paho_mqtt.Client,
userdata: Any,
sock: socket.socket
sock: socket.socket | paho_mqtt.SocketLike
) -> None:
self.loop.add_writer(sock, client.loop_write)
def _on_socket_unregister_write(self,
def _on_socket_unregister_write(
self,
client: paho_mqtt.Client,
userdata: Any,
sock: socket.socket
sock: socket.socket | paho_mqtt.SocketLike
) -> None:
self.loop.remove_writer(sock)
@ -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():

View file

@ -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()

View file

@ -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,

View file

@ -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

View file

@ -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"

View file

@ -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,6 +289,12 @@ install_packages()
# Step 4: Create python virtual environment
create_virtualenv()
{
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
@ -279,29 +304,37 @@ create_virtualenv()
fi
if [ ! -d ${PYTHONDIR} ]; then
virtualenv -p /usr/bin/python3 ${PYTHONDIR}
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
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

View file

@ -1 +1,5 @@
pre-commit
build
mypy
ruff
twine

View file

@ -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