From 31f309c942ebf76c4daf2a13d3e6f65100f52d3a Mon Sep 17 00:00:00 2001
From: Joel Heaps <joel@joelheaps.com>
Date: Thu, 28 Sep 2023 22:07:25 -0500
Subject: [PATCH] Switch to attridict, format with Black

---
 pdm.lock                         | 15 +++----
 pyproject.toml                   |  2 +-
 qbittorrent_exporter/exporter.py | 73 ++++++++++++++++++++------------
 3 files changed, 52 insertions(+), 38 deletions(-)

diff --git a/pdm.lock b/pdm.lock
index 77b8935..a2be35f 100644
--- a/pdm.lock
+++ b/pdm.lock
@@ -6,18 +6,15 @@ groups = ["default"]
 cross_platform = true
 static_urls = false
 lock_version = "4.3"
-content_hash = "sha256:619785556320f35b6aca0bf164725dc3afa5a1a978782d66a3add0b9e1ad8738"
+content_hash = "sha256:637d322b802d007082b71cf7d27382f3b6b5618434faf6b346358abe81fc2f7f"
 
 [[package]]
-name = "attrdict"
-version = "2.0.1"
-summary = "A dict with attribute-style access"
-dependencies = [
-    "six",
-]
+name = "attridict"
+version = "0.0.8"
+summary = "A dict implementation with support for easy and clean access of its values through attributes"
 files = [
-    {file = "attrdict-2.0.1-py2.py3-none-any.whl", hash = "sha256:9432e3498c74ff7e1b20b3d93b45d766b71cbffa90923496f82c4ae38b92be34"},
-    {file = "attrdict-2.0.1.tar.gz", hash = "sha256:35c90698b55c683946091177177a9e9c0713a0860f0e049febd72649ccd77b70"},
+    {file = "attridict-0.0.8-py3-none-any.whl", hash = "sha256:8ee65af81f7762354e4514c443bbc04786a924c8e3e610c7883d2efbf323df6d"},
+    {file = "attridict-0.0.8.tar.gz", hash = "sha256:23a17671b9439d36e2bdb0a69c09f033abab0900a9df178e0f89aa1b2c42c5cd"},
 ]
 
 [[package]]
diff --git a/pyproject.toml b/pyproject.toml
index 2278db1..0c3e925 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -6,10 +6,10 @@ authors = [
     {name = "Esteban Sanchez", email = "esteban.sanchez@gmail.com"},
 ]
 dependencies = [
-    "attrdict>=2.0.1",
     "prometheus-client>=0.17.1",
     "python-json-logger>=2.0.7",
     "qbittorrent-api>=2023.9.53",
+    "attridict>=0.0.8",
 ]
 requires-python = ">=3.11"
 readme = "README.md"
diff --git a/qbittorrent_exporter/exporter.py b/qbittorrent_exporter/exporter.py
index 5e69547..a9b6111 100644
--- a/qbittorrent_exporter/exporter.py
+++ b/qbittorrent_exporter/exporter.py
@@ -3,9 +3,8 @@ import os
 import sys
 import signal
 import faulthandler
-from attrdict import AttrDict
+import attridict
 from qbittorrentapi import Client, TorrentStates
-from qbittorrentapi.exceptions import APIConnectionError
 from prometheus_client import start_http_server
 from prometheus_client.core import GaugeMetricFamily, CounterMetricFamily, REGISTRY
 import logging
@@ -17,7 +16,7 @@ faulthandler.enable()
 logger = logging.getLogger()
 
 
-class QbittorrentMetricsCollector():
+class QbittorrentMetricsCollector:
     TORRENT_STATUSES = [
         "checking",
         "complete",
@@ -34,7 +33,7 @@ class QbittorrentMetricsCollector():
             port=config["port"],
             username=config["username"],
             password=config["password"],
-            VERIFY_WEBUI_CERTIFICATE=config["verify_webui_certificate"]
+            VERIFY_WEBUI_CERTIFICATE=config["verify_webui_certificate"],
         )
 
     def collect(self):
@@ -98,13 +97,13 @@ class QbittorrentMetricsCollector():
                 "name": f"{self.config['metrics_prefix']}_dl_info_data",
                 "value": response.get("dl_info_data", 0),
                 "help": "Data downloaded this session (bytes)",
-                "type": "counter"
+                "type": "counter",
             },
             {
                 "name": f"{self.config['metrics_prefix']}_up_info_data",
                 "value": response.get("up_info_data", 0),
                 "help": "Data uploaded this session (bytes)",
-                "type": "counter"
+                "type": "counter",
             },
         ]
 
@@ -117,29 +116,43 @@ class QbittorrentMetricsCollector():
             return []
 
         metrics = []
-        categories.Uncategorized = AttrDict({'name': 'Uncategorized', 'savePath': ''})
+        categories.Uncategorized = attridict({"name": "Uncategorized", "savePath": ""})
         for category in categories:
-            category_torrents = [t for t in torrents if t['category'] == category or (category == "Uncategorized" and t['category'] == "")]
+            category_torrents = [
+                t
+                for t in torrents
+                if t["category"] == category
+                or (category == "Uncategorized" and t["category"] == "")
+            ]
 
             for status in self.TORRENT_STATUSES:
                 status_prop = f"is_{status}"
                 status_torrents = [
-                    t for t in category_torrents if getattr(TorrentStates, status_prop).fget(TorrentStates(t['state']))
+                    t
+                    for t in category_torrents
+                    if getattr(TorrentStates, status_prop).fget(
+                        TorrentStates(t["state"])
+                    )
                 ]
-                metrics.append({
-                    "name": f"{self.config['metrics_prefix']}_torrents_count",
-                    "value": len(status_torrents),
-                    "labels": {
-                        "status": status,
-                        "category": category,
-                    },
-                    "help": f"Number of torrents in status {status} under category {category}"
-                })
+                metrics.append(
+                    {
+                        "name": f"{self.config['metrics_prefix']}_torrents_count",
+                        "value": len(status_torrents),
+                        "labels": {
+                            "status": status,
+                            "category": category,
+                        },
+                        "help": (
+                            f"Number of torrents in status {status} under category"
+                            f" {category}"
+                        ),
+                    }
+                )
 
         return metrics
 
 
-class SignalHandler():
+class SignalHandler:
     def __init__(self):
         self.shutdownCount = 0
 
@@ -157,6 +170,7 @@ class SignalHandler():
         logger.info("Exporter is shutting down")
         self.shutdownCount += 1
 
+
 def get_config_value(key, default=""):
     input_path = os.environ.get("FILE__" + key, None)
     if input_path is not None:
@@ -173,12 +187,11 @@ def main():
     # Init logger so it can be used
     logHandler = logging.StreamHandler()
     formatter = jsonlogger.JsonFormatter(
-        "%(asctime) %(levelname) %(message)",
-        datefmt="%Y-%m-%d %H:%M:%S"
+        "%(asctime) %(levelname) %(message)", datefmt="%Y-%m-%d %H:%M:%S"
     )
     logHandler.setFormatter(formatter)
     logger.addHandler(logHandler)
-    logger.setLevel("INFO") # default until config is loaded
+    logger.setLevel("INFO")  # default until config is loaded
 
     config = {
         "host": get_config_value("QBITTORRENT_HOST", ""),
@@ -188,7 +201,9 @@ def main():
         "exporter_port": int(get_config_value("EXPORTER_PORT", "8000")),
         "log_level": get_config_value("EXPORTER_LOG_LEVEL", "INFO"),
         "metrics_prefix": get_config_value("METRICS_PREFIX", "qbittorrent"),
-        "verify_webui_certificate": get_config_value("VERIFY_WEBUI_CERTIFICATE", "True") == "True",
+        "verify_webui_certificate": (
+            get_config_value("VERIFY_WEBUI_CERTIFICATE", "True") == "True"
+        ),
     }
     # set level once config has been loaded
     logger.setLevel(config["log_level"])
@@ -197,10 +212,14 @@ def main():
     signal_handler = SignalHandler()
 
     if not config["host"]:
-        logger.error("No host specified, please set QBITTORRENT_HOST environment variable")
+        logger.error(
+            "No host specified, please set QBITTORRENT_HOST environment variable"
+        )
         sys.exit(1)
     if not config["port"]:
-        logger.error("No port specified, please set QBITTORRENT_PORT environment variable")
+        logger.error(
+            "No port specified, please set QBITTORRENT_PORT environment variable"
+        )
         sys.exit(1)
 
     # Register our custom collector
@@ -209,9 +228,7 @@ def main():
 
     # Start server
     start_http_server(config["exporter_port"])
-    logger.info(
-        f"Exporter listening on port {config['exporter_port']}"
-    )
+    logger.info(f"Exporter listening on port {config['exporter_port']}")
 
     while not signal_handler.is_shutting_down():
         time.sleep(1)