Skip to content

Commit

Permalink
merge config files and apply current rules
Browse files Browse the repository at this point in the history
  • Loading branch information
miaucl committed Sep 20, 2024
1 parent 63ddbc6 commit 010c55f
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 135 deletions.
2 changes: 1 addition & 1 deletion .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
{
"label": "Python: Build docker2mqtt package",
"type": "shell",
"command": "pip install -e .",
"command": "scripts/run-in-env.sh pip install -e .",
"problemMatcher": [],
"group": {
"kind": "build"
Expand Down
5 changes: 3 additions & 2 deletions docker2mqtt/__docker__.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
docker2mqtt.loop_busy()

except Exception as ex:
main_logger.info("Error occurred, printing relevant information and exiting...")
main_logger.error("Error processing: %s", str(ex))
main_logger.exception(
"Error occurred, printing relevant information and exiting..."
)
print(ex)
120 changes: 63 additions & 57 deletions docker2mqtt/docker2mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
Docker2MqttConfigException,
Docker2MqttConnectionException,
Docker2MqttEventsException,
Docker2MqttException,
Docker2MqttStatsException,
)
from .type_definitions import (
Expand Down Expand Up @@ -222,10 +223,10 @@ def __init__(self, cfg: Docker2MqttConfig, do_not_exit: bool = False):
self._mqtt_send(self.status_topic, "online", retain=True)
self._mqtt_send(self.version_topic, self.version, retain=True)

except paho.mqtt.client.WebsocketConnectionError as e:
main_logger.error("Error while trying to connect to MQTT broker.")
main_logger.error(str(e))
raise Docker2MqttConnectionException from e
except paho.mqtt.client.WebsocketConnectionError as ex:
main_logger.exception("Error while trying to connect to MQTT broker.")
main_logger.debug(ex)
raise Docker2MqttConnectionException from ex

# Register containers with HA
docker_ps = subprocess.run(
Expand Down Expand Up @@ -264,20 +265,20 @@ def __init__(self, cfg: Docker2MqttConfig, do_not_exit: bool = False):
logging.info("Starting Events thread")
self._start_readline_events_thread()
started = True
except Exception as e:
main_logger.error("Error while trying to start events thread.")
main_logger.error(str(e))
raise Docker2MqttConfigException from e
except Exception as ex:
main_logger.exception("Error while trying to start events thread.")
main_logger.debug(ex)
raise Docker2MqttConfigException from ex

try:
if self.b_stats:
started = True
logging.info("Starting Stats thread")
self._start_readline_stats_thread()
except Exception as e:
main_logger.error("Error while trying to start stats thread.")
main_logger.error(str(e))
raise Docker2MqttConfigException from e
except Exception as ex:
main_logger.exception("Error while trying to start stats thread.")
main_logger.debug(ex)
raise Docker2MqttConfigException from ex

if started is False:
logging.critical("Nothing started, check your config!")
Expand Down Expand Up @@ -307,8 +308,9 @@ def _cleanup(self) -> None:
main_logger.warning("Shutting down gracefully.")
try:
self._mqtt_disconnect()
except Docker2MqttConnectionException as e:
main_logger.error("MQTT Cleanup Failed: %s", str(e))
except Docker2MqttConnectionException as ex:
main_logger.exception("MQTT Cleanup Failed")
main_logger.debug(ex)
main_logger.info("Ignoring cleanup error and exiting...")

def loop(self) -> None:
Expand All @@ -335,19 +337,19 @@ def loop(self) -> None:
if self.b_events and not self.docker_events_t.is_alive():
main_logger.warning("Restarting events thread")
self._start_readline_events_thread()
except Exception as e:
main_logger.error("Error while trying to restart events thread.")
main_logger.error(str(e))
raise Docker2MqttConfigException from e
except Exception as ex:
main_logger.exception("Error while trying to restart events thread.")
main_logger.debug(ex)
raise Docker2MqttConfigException from ex

try:
if self.b_stats and not self.docker_stats_t.is_alive():
main_logger.warning("Restarting stats thread")
self._start_readline_stats_thread()
except Exception as e:
main_logger.error("Error while trying to restart stats thread.")
main_logger.error(str(e))
raise Docker2MqttConfigException from e
except Exception as ex:
main_logger.exception("Error while trying to restart stats thread.")
main_logger.debug(ex)
raise Docker2MqttConfigException from ex

def loop_busy(self, raise_known_exceptions: bool = False) -> None:
"""Start the loop (blocking).
Expand All @@ -373,14 +375,14 @@ def loop_busy(self, raise_known_exceptions: bool = False) -> None:
self.loop()
except Docker2MqttEventsException as ex:
if raise_known_exceptions:
raise ex
raise ex # noqa: TRY201
else:
main_logger.warning(
"Do not raise due to raise_known_exceptions=False: %s", str(ex)
)
except Docker2MqttStatsException as ex:
if raise_known_exceptions:
raise ex
raise ex # noqa: TRY201
else:
main_logger.warning(
"Do not raise due to raise_known_exceptions=False: %s", str(ex)
Expand Down Expand Up @@ -422,7 +424,7 @@ def _get_docker_version(self) -> str:
# Extract the version information from the output
return result.stdout.strip()
else:
raise Exception(f"Error: {result.stderr.strip()}")
raise Docker2MqttException(f"Error: {result.stderr.strip()}")
except FileNotFoundError:
return "Docker is not installed or not found in PATH."

Expand Down Expand Up @@ -450,9 +452,10 @@ def _mqtt_send(self, topic: str, payload: str, retain: bool = False) -> None:
topic, payload=payload, qos=self.cfg["mqtt_qos"], retain=retain
)

except paho.mqtt.client.WebsocketConnectionError as e:
main_logger.error("MQTT Publish Failed: %s", str(e))
raise Docker2MqttConnectionException() from e
except paho.mqtt.client.WebsocketConnectionError as ex:
main_logger.exception("MQTT Publish Failed")
main_logger.debug(ex)
raise Docker2MqttConnectionException() from ex

def _mqtt_disconnect(self) -> None:
"""Make sure we send our last_will message.
Expand All @@ -479,9 +482,12 @@ def _mqtt_disconnect(self) -> None:
self.mqtt.disconnect()
sleep(1)
self.mqtt.loop_stop()
except paho.mqtt.client.WebsocketConnectionError as e:
main_logger.error("MQTT Disconnect: %s", str(e))
raise Docker2MqttConnectionException() from e
except paho.mqtt.client.WebsocketConnectionError as ex:
main_logger.exception(
"MQTT Disconnect",
)
main_logger.debug(ex)
raise Docker2MqttConnectionException() from ex

def _start_readline_events_thread(self) -> None:
"""Start the events thread."""
Expand All @@ -499,18 +505,17 @@ def _run_readline_events_thread(self) -> None:
thread_logger.debug("Command: %s", DOCKER_EVENTS_CMD)
with Popen(DOCKER_EVENTS_CMD, stdout=PIPE, text=True) as process:
while True:
if process.stdout:
line = ANSI_ESCAPE.sub("", process.stdout.readline())
if line == "" and process.poll() is not None:
break
if line:
thread_logger.debug("Read docker event line: %s", line)
self.docker_events.put(line.strip())
_rc = process.poll()
else:
raise ReferenceError("process stdout is undefined")
assert process.stdout
line = ANSI_ESCAPE.sub("", process.stdout.readline())
if line == "" and process.poll() is not None:
break
if line:
thread_logger.debug("Read docker event line: %s", line)
self.docker_events.put(line.strip())
_rc = process.poll()
except Exception as ex:
thread_logger.error("Error Running Events thread: %s", str(ex))
thread_logger.exception("Error Running Events thread")
thread_logger.debug(ex)
thread_logger.debug("Waiting for main thread to restart this thread")

def _start_readline_stats_thread(self) -> None:
Expand All @@ -529,18 +534,17 @@ def _run_readline_stats_thread(self) -> None:
thread_logger.debug("Command: %s", DOCKER_STATS_CMD)
with Popen(DOCKER_STATS_CMD, stdout=PIPE, text=True) as process:
while True:
if process.stdout:
line = ANSI_ESCAPE.sub("", process.stdout.readline())
if line == "" and process.poll() is not None:
break
if line:
thread_logger.debug("Read docker stat line: %s", line)
self.docker_stats.put(line.strip())
_rc = process.poll()
else:
raise ReferenceError("process stdout is undefined")
assert process.stdout
line = ANSI_ESCAPE.sub("", process.stdout.readline())
if line == "" and process.poll() is not None:
break
if line:
thread_logger.debug("Read docker stat line: %s", line)
self.docker_stats.put(line.strip())
_rc = process.poll()
except Exception as ex:
thread_logger.error("Error Running Stats thread: %s", str(ex))
thread_logger.exception("Error Running Stats thread")
thread_logger.debug(ex)
thread_logger.debug("Waiting for main thread to restart this thread")

def _device_definition(
Expand Down Expand Up @@ -961,8 +965,9 @@ def _handle_events_queue(self) -> None:
events_logger.debug("Unknown event: %s", event["status"])

except Exception as ex:
events_logger.error("Error parsing line: %s", event_line)
events_logger.error("Error of parsed line: %s", str(ex))
events_logger.exception("Error parsing line: %s", event_line)
events_logger.exception("Error of parsed line")
events_logger.debug(ex)
raise Docker2MqttEventsException(
f"Error parsing line: {event_line}"
) from ex
Expand Down Expand Up @@ -1164,8 +1169,9 @@ def _handle_stats_queue(self) -> None:
)

except Exception as ex:
stats_logger.error("Error parsing line: %s", stat_line)
stats_logger.error("Error of parsed line: %s", str(ex))
stats_logger.exception("Error parsing line: %s", stat_line)
stats_logger.exception("Error of parsed line")
stats_logger.debug(ex)
stats_logger.info(":".join(hex(ord(x))[2:] for x in stat_line))
raise Docker2MqttStatsException(
f"Error parsing line: {stat_line}"
Expand Down
6 changes: 2 additions & 4 deletions docker2mqtt/helpers.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
"""docker2mqtt helpers."""

from typing import Union

from .type_definitions import ContainerEntry


def clean_for_discovery(
val: ContainerEntry,
) -> dict[str, Union[str, int, float, object]]:
) -> dict[str, str | int | float | object]:
"""Cleanup a typed dict for home assistant discovery, which is quite picky and does not like empty of None values.
Parameters
Expand All @@ -25,5 +23,5 @@ def clean_for_discovery(
return {
k: v
for k, v in dict(val).items()
if isinstance(v, (str, int, float, object)) and v not in (None, "")
if isinstance(v, str | int | float | object) and v not in (None, "")
}
22 changes: 0 additions & 22 deletions mypy.ini

This file was deleted.

76 changes: 71 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,52 @@ requires = [
]
build-backend = "setuptools.build_meta"

[project]
name = "docker2mqtt"
dynamic = ["version", "readme"]
description = "Send your docker stats and and events to mqtt and discovery them in home assistant."
authors = [
{ name = "Cyrill Raccaud", email = "[email protected]" },
]
dependencies = [
"jsons",
"psutil",
"paho-mqtt",
"numpy",
"typing-extensions"
]
requires-python = ">=3.11"

classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Intended Audience :: Information Technology",
"Topic :: System :: Monitoring",
"Topic :: System :: Logging",
"Topic :: System :: Systems Administration",
]
license = {text = "MIT License"}
keywords = ["docker", "mqtt", "paho", "home-assistant", "system-monitoring", "discovery", "iot"]

[tool.setuptools]
packages = ["docker2mqtt"]

[tool.setuptools.package-data]
docker2mtt = ["py.typed"]

[tool.setuptools.dynamic]
version = {attr = "docker2mqtt.__version__"}
readme = {file = ["README.md", "CHANGELOG.md"], content-type = "text/markdown"}

[project.urls]
Documentation = "https://miaucl.github.io/docker2mqtt/"
Source = "https://github.com/miaucl/docker2mqtt"
Issues = "https://github.com/miaucl/docker2mqtt/issues"

[project.scripts]
docker2mqtt = "docker2mqtt.docker2mqtt:main"

[tool.ruff]

target-version = "py312"
Expand Down Expand Up @@ -69,7 +115,7 @@ select = [
"TID251", # Banned imports
"TRY004", # Prefer TypeError exception for invalid type
"B904", # Use raise from to specify exception cause
"TRY302", # Remove exception handler; error is immediately re-raised
"TRY", # tryceratops
"UP", # pyupgrade
"W", # pycodestyle
]
Expand All @@ -96,10 +142,7 @@ ignore = [
"PLR0915", # Too many statements ({statements} > {max_statements})
"PLR2004", # Magic value used in comparison, consider replacing {value} with a constant variable
"PLW2901", # Outer {outer_kind} variable {name} overwritten by inner {inner_kind} target
"UP006", # keep type annotation style as is
"UP007", # keep type annotation style as is
# Ignored due to performance: https://github.com/charliermarsh/ruff/issues/2923
"UP038", # Use `X | Y` in `isinstance` call instead of `(X, Y)`
"TRY003", # Avoid specifying long messages outside the exception class

# May conflict with the formatter, https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules
"W191",
Expand Down Expand Up @@ -145,3 +188,26 @@ split-on-trailing-comma = false

[tool.ruff.lint.mccabe]
max-complexity = 25

[tool.mypy]
python_version = "3.12"
plugins = "pydantic.mypy"
show_error_codes = true
local_partial_types = true
strict_equality = true
no_implicit_optional = true
warn_incomplete_stub = true
warn_redundant_casts = true
warn_unused_configs = true
warn_unused_ignores = false
enable_error_code = ["ignore-without-code", "redundant-self", "truthy-iterable"]
disable_error_code = ["annotation-unchecked", "import-not-found", "import-untyped"]
extra_checks = false
check_untyped_defs = true
disallow_incomplete_defs = true
disallow_subclassing_any = true
disallow_untyped_calls = true
disallow_untyped_decorators = true
disallow_untyped_defs = true
warn_return_any = true
warn_unreachable = true
Loading

0 comments on commit 010c55f

Please sign in to comment.