From b7e2706b1242ae7673d622f06cc43a124da1cfd3 Mon Sep 17 00:00:00 2001 From: barry Date: Wed, 1 Oct 2025 19:11:46 +0200 Subject: [PATCH] linting --- poetry.lock | 106 +++++++++++++++++++++++++++++++++++- pyproject.toml | 1 + requirements.txt | 18 ++++++ spotiplayer_pi/api.py | 18 +++--- spotiplayer_pi/lcdconfig.py | 22 +++++--- spotiplayer_pi/main.py | 22 +++++--- 6 files changed, 163 insertions(+), 24 deletions(-) diff --git a/poetry.lock b/poetry.lock index d61a97f..29077ee 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,5 +1,25 @@ # This file is automatically @generated by Poetry 2.0.0 and should not be changed by hand. +[[package]] +name = "anyio" +version = "4.11.0" +description = "High-level concurrency and networking framework on top of asyncio or Trio" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc"}, + {file = "anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4"}, +] + +[package.dependencies] +idna = ">=2.8" +sniffio = ">=1.1" +typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} + +[package.extras] +trio = ["trio (>=0.31.0)"] + [[package]] name = "certifi" version = "2024.12.14" @@ -155,6 +175,65 @@ docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2. testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"] typing = ["typing-extensions (>=4.12.2)"] +[[package]] +name = "h11" +version = "0.16.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, + {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"}, + {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"}, +] + +[package.dependencies] +certifi = "*" +h11 = ">=0.16" + +[package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<1.0)"] + +[[package]] +name = "httpx" +version = "0.28.1" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"}, + {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"}, +] + +[package.dependencies] +anyio = "*" +certifi = "*" +httpcore = "==1.*" +idna = "*" + +[package.extras] +brotli = ["brotli", "brotlicffi"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +zstd = ["zstandard (>=0.18.0)"] + [[package]] name = "identify" version = "2.6.5" @@ -531,6 +610,18 @@ files = [ {file = "ruff-0.9.0.tar.gz", hash = "sha256:143f68fa5560ecf10fc49878b73cee3eab98b777fcf43b0e62d43d42f5ef9d8b"}, ] +[[package]] +name = "sniffio" +version = "1.3.1" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, + {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, +] + [[package]] name = "spidev" version = "3.6" @@ -543,6 +634,19 @@ files = [ {file = "spidev-3.6.tar.gz", hash = "sha256:14dbc37594a4aaef85403ab617985d3c3ef464d62bc9b769ef552db53701115b"}, ] +[[package]] +name = "typing-extensions" +version = "4.15.0" +description = "Backported and Experimental Type Hints for Python 3.9+" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version < \"3.13\"" +files = [ + {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, + {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, +] + [[package]] name = "urllib3" version = "2.3.0" @@ -585,4 +689,4 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [metadata] lock-version = "2.1" python-versions = "^3.11" -content-hash = "135cf9001d97689d659830abaa919636d20e76a494585757f9b59fbe9ca3adb5" +content-hash = "3e4bb3f59bdb90eac1180a026c9be37147b636f91f1f09cce2d7889b4c517f5e" diff --git a/pyproject.toml b/pyproject.toml index 29fc418..3adb918 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,6 +13,7 @@ numpy = "^2.2.1" pillow = "^11.1.0" pyyaml = "^6.0.2" psutil = "^6.1.1" +httpx = "^0.28.1" [tool.poetry.group.dev.dependencies] diff --git a/requirements.txt b/requirements.txt index 1952c91..33bf35a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,6 @@ +anyio==4.11.0 ; python_version >= "3.11" and python_version < "4.0" \ + --hash=sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc \ + --hash=sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4 certifi==2024.12.14 ; python_version >= "3.11" and python_version < "4.0" \ --hash=sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56 \ --hash=sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db @@ -94,6 +97,15 @@ charset-normalizer==3.4.1 ; python_version >= "3.11" and python_version < "4.0" --hash=sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e \ --hash=sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00 \ --hash=sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616 +h11==0.16.0 ; python_version >= "3.11" and python_version < "4.0" \ + --hash=sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1 \ + --hash=sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86 +httpcore==1.0.9 ; python_version >= "3.11" and python_version < "4.0" \ + --hash=sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55 \ + --hash=sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8 +httpx==0.28.1 ; python_version >= "3.11" and python_version < "4.0" \ + --hash=sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc \ + --hash=sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad idna==3.10 ; python_version >= "3.11" and python_version < "4.0" \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 @@ -300,9 +312,15 @@ pyyaml==6.0.2 ; python_version >= "3.11" and python_version < "4.0" \ requests==2.32.3 ; python_version >= "3.11" and python_version < "4.0" \ --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 +sniffio==1.3.1 ; python_version >= "3.11" and python_version < "4.0" \ + --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \ + --hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc spidev==3.6 ; python_version >= "3.11" and python_version < "4.0" \ --hash=sha256:14dbc37594a4aaef85403ab617985d3c3ef464d62bc9b769ef552db53701115b \ --hash=sha256:280abc00a1ef7780ef62c3f294f52a2527b6c47d8c269fea98664970bcaf6da5 +typing-extensions==4.15.0 ; python_version >= "3.11" and python_version < "3.13" \ + --hash=sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466 \ + --hash=sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548 urllib3==2.3.0 ; python_version >= "3.11" and python_version < "4.0" \ --hash=sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df \ --hash=sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d diff --git a/spotiplayer_pi/api.py b/spotiplayer_pi/api.py index c45b3eb..59b8e27 100644 --- a/spotiplayer_pi/api.py +++ b/spotiplayer_pi/api.py @@ -1,5 +1,5 @@ -import requests import warnings +import httpx class Api: @@ -8,23 +8,27 @@ class Api: self.base_64 = base_64 self.access_token = None self.header = None + self._client = httpx.AsyncClient(timeout=httpx.Timeout(5.0, connect=5.0)) - def refreshAuth(self) -> None: + async def refreshAuth(self) -> None: uri = "https://accounts.spotify.com/api/token" data = { "grant_type": "refresh_token", "refresh_token": self.refresh_token, } - req = requests.post( - uri, data=data, headers={"Authorization": "Basic " + self.base_64} - ).json() + res = await self._client.post( + uri, + data=data, + headers={"Authorization": "Basic " + self.base_64}, + ) + req = res.json() self.access_token = req["access_token"] self.header = {"Authorization": f"Bearer {self.access_token}"} return req["expires_in"] - def getPlaying(self): + async def getPlaying(self): url = "https://api.spotify.com/v1/me/player/currently-playing" - req = requests.get(url, headers=self.header) + req = await self._client.get(url, headers=self.header) if req.status_code == 204: return "not-playing" if req.status_code == 401: diff --git a/spotiplayer_pi/lcdconfig.py b/spotiplayer_pi/lcdconfig.py index b416042..f05af3b 100644 --- a/spotiplayer_pi/lcdconfig.py +++ b/spotiplayer_pi/lcdconfig.py @@ -56,10 +56,14 @@ class RaspberryPi: # self.GPIO.cleanup() self.GPIO.setmode(self.GPIO.BCM) self.GPIO.setwarnings(False) - self.GPIO.setup(self.RST_PIN, self.GPIO.OUT) - self.GPIO.setup(self.DC_PIN, self.GPIO.OUT) - self.GPIO.setup(self.BL_PIN, self.GPIO.OUT) - self.GPIO.output(self.BL_PIN, self.GPIO.HIGH) + # self.GPIO.setup(self.RST_PIN, self.GPIO.OUT) + # self.GPIO.setup(self.DC_PIN, self.GPIO.OUT) + # self.GPIO.setup(self.BL_PIN, self.GPIO.OUT) + # self.GPIO.output(self.BL_PIN, self.GPIO.HIGH) + self.GPIO.setup(self.RST_PIN, self.GPIO.OUT, initial=self.GPIO.HIGH) + self.GPIO.setup(self.DC_PIN, self.GPIO.OUT, initial=self.GPIO.LOW) + self.GPIO.setup(self.BL_PIN, self.GPIO.OUT, initial=self.GPIO.HIGH) + # Initialize SPI self.SPI = spidev.SpiDev() self.SPI.open(0, 0) @@ -86,9 +90,13 @@ class RaspberryPi: self._pwm.ChangeFrequency(freq) def module_init(self): - self.GPIO.setup(self.RST_PIN, self.GPIO.OUT) - self.GPIO.setup(self.DC_PIN, self.GPIO.OUT) - self.GPIO.setup(self.BL_PIN, self.GPIO.OUT) + # self.GPIO.setup(self.RST_PIN, self.GPIO.OUT) + # self.GPIO.setup(self.DC_PIN, self.GPIO.OUT) + # self.GPIO.setup(self.BL_PIN, self.GPIO.OUT) + self.GPIO.setup(self.RST_PIN, self.GPIO.OUT, initial=self.GPIO.HIGH) + self.GPIO.setup(self.DC_PIN, self.GPIO.OUT, initial=self.GPIO.LOW) + self.GPIO.setup(self.BL_PIN, self.GPIO.OUT, initial=self.GPIO.HIGH) + self._pwm = self.GPIO.PWM(self.BL_PIN, self.BL_freq) self._pwm.start(100) if self.SPI != None: diff --git a/spotiplayer_pi/main.py b/spotiplayer_pi/main.py index 8d9068a..a00e7e5 100644 --- a/spotiplayer_pi/main.py +++ b/spotiplayer_pi/main.py @@ -9,6 +9,7 @@ from datetime import datetime import yaml from typing import Dict import subprocess +import asyncio import numpy as np import psutil @@ -62,7 +63,7 @@ def parse_config(path="spotiplayer_pi/config.yaml"): return data -def display_loop(api: Api, cfg: Dict): +async def display_loop(api: Api, cfg: Dict): try: d = LCD_2inch() d.Init() @@ -98,12 +99,12 @@ def display_loop(api: Api, cfg: Dict): while True: if time.time() - last_auth_refresh >= auth_interval: - auth_interval = api.refreshAuth() - 120 + auth_interval = await api.refreshAuth() - 120 last_auth_refresh = time.time() print(f"Refreshed auth at {datetime.now().strftime('%d-%m %H:%M:%S')}") if time.time() - last_api_call >= cfg["api_interval"]: - data = api.getPlaying() + data = await api.getPlaying() last_api_call = time.time() if data == None: warnings.warn("No data found") @@ -129,7 +130,10 @@ def display_loop(api: Api, cfg: Dict): idx = cpu_values_idxs[i] val, prev_val = cpu_values[i], cpu_values[i - 1] draw.rectangle( - [(idx, 200 - val), (idx - 1, 200 - prev_val)], + [ + (min(idx - 1, idx), min(200 - prev_val, 200 - val)), + (max(idx - 1, idx), max(200 - prev_val, 200 - val)), + ], fill=(255, 253, 195), ) draw.text( @@ -185,8 +189,8 @@ def display_loop(api: Api, cfg: Dict): idx = len(binned_data) - idx_ - 1 draw.rectangle( [ - (321 - ((idx + 1) * 16), 240), - (319 - (idx * 16), 240 - bin_i // 65), + (321 - ((idx + 1) * 16), min(240, 240 - bin_i // 65)), + (319 - (idx * 16), max(240, 240 - bin_i // 65)), ], fill=tuple(cmap2[idx]), ) @@ -293,10 +297,10 @@ def display_loop(api: Api, cfg: Dict): fill=cfg["color_theme"]["text"], ) d.ShowImage(bg) - time.sleep(cfg["refresh_interval"]) + await asyncio.sleep(cfg["refresh_interval"]) except IOError as e: - raise e + print(f"IOError: {e}") except KeyboardInterrupt: d.module_exit() @@ -304,4 +308,4 @@ def display_loop(api: Api, cfg: Dict): if __name__ == "__main__": cfg = parse_config() api = Api(cfg["refresh_token"], cfg["base_64"]) - display_loop(api, cfg) + asyncio.run(display_loop(api, cfg))