From 7f6f5ac0d9363678a78d27d20772d170d59b767e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C3=85slund?= Date: Thu, 16 Jan 2025 07:41:52 +0100 Subject: [PATCH 01/17] Corrected printing of resulting json --- main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main.py b/main.py index ea7acc3..2f7ca88 100644 --- a/main.py +++ b/main.py @@ -4,10 +4,11 @@ import json from openhardwaremonitor import OpenHardwareMonitor + async def main(): ohm = OpenHardwareMonitor('192.168.1.114', 8085) data = await ohm.get_data() - json.dumps(data) + print(json.dumps(data)) await ohm._api.close() if __name__ == '__main__': From 002ad3703720e26ee20999cec3572e16666aa50d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C3=85slund?= Date: Fri, 17 Jan 2025 12:27:54 +0100 Subject: [PATCH 02/17] Able to close the session --- openhardwaremonitor/api.py | 8 ++++++-- openhardwaremonitor/openhardwaremonitor.py | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/openhardwaremonitor/api.py b/openhardwaremonitor/api.py index 451aef8..a76fae8 100644 --- a/openhardwaremonitor/api.py +++ b/openhardwaremonitor/api.py @@ -83,9 +83,13 @@ async def raw_request( # pylint: disable=too-many-arguments return await self.raw_request(uri, params, data, method, attempt=attempt + 1) raise OpenHardwareMonitorError("Request limit exceeded") + content = None if "Content-Type" in response.headers and "application/json" in response.headers["Content-Type"]: - return await response.json() - return await response.read() + content = await response.json() + content = await response.read() + _LOGGER.debug("Response %s, status: %s", response.url, response.status) + _LOGGER.debug("Response content: %s", content) + return content async def authenticate(self): """Perform authenticateion.""" diff --git a/openhardwaremonitor/openhardwaremonitor.py b/openhardwaremonitor/openhardwaremonitor.py index ecf6971..af7c48f 100644 --- a/openhardwaremonitor/openhardwaremonitor.py +++ b/openhardwaremonitor/openhardwaremonitor.py @@ -8,4 +8,7 @@ def __init__(self, *args, **kwargs): async def get_data(self): json = await self._api.request(f"data.json") return json + + async def close(self): + return await self._api.close() \ No newline at end of file From e2becd4166293d454fd42d3139fcdf535500b071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C3=85slund?= Date: Fri, 17 Jan 2025 12:28:05 +0100 Subject: [PATCH 03/17] Trigger on version-tags --- .github/workflows/python-publish.yml | 3 +++ openhardwaremonitor/const.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 6da9cc9..ba520d3 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -9,6 +9,9 @@ name: Upload Python Package on: + push: + tags: + - v** release: types: [created] diff --git a/openhardwaremonitor/const.py b/openhardwaremonitor/const.py index 82cda36..4949c00 100644 --- a/openhardwaremonitor/const.py +++ b/openhardwaremonitor/const.py @@ -1,3 +1,3 @@ """Constants used by pyOpenHardwareMonitor""" -__version__ = "0.1" +__version__ = "0.1.1" From 5efdb7f55b3308efb6f473c8a8275ecddfc981ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C3=85slund?= Date: Fri, 17 Jan 2025 12:53:29 +0100 Subject: [PATCH 04/17] Flake8 config and resolving issues --- .flake8 | 18 ++++++++++++++++++ main.py | 2 +- openhardwaremonitor/__init__.py | 2 -- openhardwaremonitor/api.py | 11 +++++------ openhardwaremonitor/exceptions.py | 2 +- openhardwaremonitor/openhardwaremonitor.py | 9 +++++---- setup.py | 4 +--- 7 files changed, 31 insertions(+), 17 deletions(-) create mode 100644 .flake8 diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..0d3de30 --- /dev/null +++ b/.flake8 @@ -0,0 +1,18 @@ +[flake8] +ignore = + # E501 = line too long + E501 + +exclude = + # No need to traverse our git directory + .git, + # There's no value in checking cache directories + __pycache__, + # The conf file is mostly autogenerated, ignore it + docs/source/conf.py, + # This contains our built documentation + build, + # This contains builds of flake8 that we don't want to check + dist, + # This folder is for local debugging + .venv diff --git a/main.py b/main.py index 2f7ca88..5224875 100644 --- a/main.py +++ b/main.py @@ -12,4 +12,4 @@ async def main(): await ohm._api.close() if __name__ == '__main__': - asyncio.run(main()) \ No newline at end of file + asyncio.run(main()) diff --git a/openhardwaremonitor/__init__.py b/openhardwaremonitor/__init__.py index bd7b3e3..8d25cf6 100644 --- a/openhardwaremonitor/__init__.py +++ b/openhardwaremonitor/__init__.py @@ -1,3 +1 @@ """Library to handle connection with a Open Hardware Monitor remote server""" - -from .openhardwaremonitor import OpenHardwareMonitor diff --git a/openhardwaremonitor/api.py b/openhardwaremonitor/api.py index a76fae8..8e38680 100644 --- a/openhardwaremonitor/api.py +++ b/openhardwaremonitor/api.py @@ -7,12 +7,11 @@ from .exceptions import NotFoundError, OpenHardwareMonitorError, UnauthorizedError - _LOGGER = logging.getLogger(__name__) class API: - + DEFAULT_TIMEOUT = 10 def __init__( @@ -32,7 +31,7 @@ def __init__( loop = loop or asyncio.get_event_loop() self.session = aiohttp.ClientSession(raise_for_status=True) self._close_session = True - + self._retry_count = retry_count #self._retry_delay = retry_delay @@ -43,12 +42,12 @@ def base_headers(self): "content-type": "application/json;charset=UTF-8", "accept": "application/json, text/plain, */*", } - + async def auth_headers(self): await self.authenticate() # return {**self.base_headers(), **self._auth_headers} return {**self.base_headers()} - + async def request(self, *args, **kwargs): """Perform request with error wrapping.""" try: @@ -61,7 +60,7 @@ async def request(self, *args, **kwargs): raise OpenHardwareMonitorError from error except Exception as error: raise OpenHardwareMonitorError from error - + async def raw_request( # pylint: disable=too-many-arguments self, uri, params=None, data=None, method="GET", attempt: int = 1 ): diff --git a/openhardwaremonitor/exceptions.py b/openhardwaremonitor/exceptions.py index 40d688d..728e52a 100644 --- a/openhardwaremonitor/exceptions.py +++ b/openhardwaremonitor/exceptions.py @@ -14,4 +14,4 @@ class NotFoundError(OpenHardwareMonitorError): class DisconnectedError(OpenHardwareMonitorError): - """Channel disconnected""" \ No newline at end of file + """Channel disconnected""" diff --git a/openhardwaremonitor/openhardwaremonitor.py b/openhardwaremonitor/openhardwaremonitor.py index af7c48f..213279a 100644 --- a/openhardwaremonitor/openhardwaremonitor.py +++ b/openhardwaremonitor/openhardwaremonitor.py @@ -1,14 +1,15 @@ from .api import API + class OpenHardwareMonitor: + def __init__(self, *args, **kwargs): """Initialize the client.""" self._api = API(*args, **kwargs) - + async def get_data(self): - json = await self._api.request(f"data.json") + json = await self._api.request("data.json") return json - + async def close(self): return await self._api.close() - \ No newline at end of file diff --git a/setup.py b/setup.py index c5a2665..b9be741 100644 --- a/setup.py +++ b/setup.py @@ -14,9 +14,7 @@ setup( name="pyOpenHardwareMonitor", packages=["openhardwaremonitor"], - #install_requires=["aiohttp>=3.0.6"], install_requires=install_requires, - #package_data={"openhardwaremonitor": ["py.typed"]}, version=consts["__version__"], description="A python3 library to communicate with an OpenHardwareMonitor remote server", python_requires=">=3.11.0", @@ -33,4 +31,4 @@ "Topic :: Software Development :: Libraries :: Python Modules", "License :: OSI Approved :: MIT License" ], -) \ No newline at end of file +) From 090bd7939d08ceab0b4112db693940e4d89470a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C3=85slund?= Date: Fri, 17 Jan 2025 12:53:39 +0100 Subject: [PATCH 05/17] Implementing retry_delay --- openhardwaremonitor/api.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openhardwaremonitor/api.py b/openhardwaremonitor/api.py index 8e38680..2d6bd29 100644 --- a/openhardwaremonitor/api.py +++ b/openhardwaremonitor/api.py @@ -1,5 +1,6 @@ import asyncio import logging +import random import aiohttp from aiohttp.client_exceptions import ClientResponseError @@ -21,7 +22,8 @@ def __init__( loop=None, session=None, timeout=DEFAULT_TIMEOUT, - retry_count=3 + retry_count=3, + retry_delay=lambda attempt: 3**attempt + random.uniform(0, 3) ): self._timeout = timeout self._close_session = False @@ -33,7 +35,7 @@ def __init__( self._close_session = True self._retry_count = retry_count - #self._retry_delay = retry_delay + self._retry_delay = retry_delay self.API_URL = URL(f"http://{host}:{port}/") From aedcab91662e219dccc2ec90423b2f0728576932 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C3=85slund?= Date: Fri, 17 Jan 2025 13:06:35 +0100 Subject: [PATCH 06/17] Improved retry_delay --- .github/workflows/code-checker.yml | 7 ++++--- openhardwaremonitor/api.py | 4 ++-- openhardwaremonitor/const.py | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/code-checker.yml b/.github/workflows/code-checker.yml index a15a0fc..ab9a4c3 100644 --- a/.github/workflows/code-checker.yml +++ b/.github/workflows/code-checker.yml @@ -10,9 +10,10 @@ jobs: strategy: matrix: python-version: - - "3.8" - - "3.9" - - "3.10" + - "3.11" + - "3.12" + - "3.13" + - "3.14" env: SRC_FOLDER: openhardwaremonitor steps: diff --git a/openhardwaremonitor/api.py b/openhardwaremonitor/api.py index 2d6bd29..b40ff61 100644 --- a/openhardwaremonitor/api.py +++ b/openhardwaremonitor/api.py @@ -23,7 +23,7 @@ def __init__( session=None, timeout=DEFAULT_TIMEOUT, retry_count=3, - retry_delay=lambda attempt: 3**attempt + random.uniform(0, 3) + retry_delay: callable[int] = None ): self._timeout = timeout self._close_session = False @@ -35,7 +35,7 @@ def __init__( self._close_session = True self._retry_count = retry_count - self._retry_delay = retry_delay + self._retry_delay = retry_delay or (lambda attempt: 3**attempt + random.SystemRandom.uniform(0, 3)) self.API_URL = URL(f"http://{host}:{port}/") diff --git a/openhardwaremonitor/const.py b/openhardwaremonitor/const.py index 4949c00..9a0c340 100644 --- a/openhardwaremonitor/const.py +++ b/openhardwaremonitor/const.py @@ -1,3 +1,3 @@ """Constants used by pyOpenHardwareMonitor""" -__version__ = "0.1.1" +__version__ = "0.1.2" From ddb71850ddf1759165d0bce5f01086c1bb800ef2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C3=85slund?= Date: Fri, 17 Jan 2025 13:22:33 +0100 Subject: [PATCH 07/17] Corrections --- main.py | 4 ++-- openhardwaremonitor/api.py | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/main.py b/main.py index 5224875..3e5366a 100644 --- a/main.py +++ b/main.py @@ -2,11 +2,11 @@ import asyncio import json -from openhardwaremonitor import OpenHardwareMonitor +from openhardwaremonitor import openhardwaremonitor async def main(): - ohm = OpenHardwareMonitor('192.168.1.114', 8085) + ohm = openhardwaremonitor.OpenHardwareMonitor('192.168.50.20', 8085) data = await ohm.get_data() print(json.dumps(data)) await ohm._api.close() diff --git a/openhardwaremonitor/api.py b/openhardwaremonitor/api.py index b40ff61..acc06d4 100644 --- a/openhardwaremonitor/api.py +++ b/openhardwaremonitor/api.py @@ -23,7 +23,7 @@ def __init__( session=None, timeout=DEFAULT_TIMEOUT, retry_count=3, - retry_delay: callable[int] = None + retry_delay=None ): self._timeout = timeout self._close_session = False @@ -87,7 +87,8 @@ async def raw_request( # pylint: disable=too-many-arguments content = None if "Content-Type" in response.headers and "application/json" in response.headers["Content-Type"]: content = await response.json() - content = await response.read() + else: + content = await response.read() _LOGGER.debug("Response %s, status: %s", response.url, response.status) _LOGGER.debug("Response content: %s", content) return content From 66d757afa27f7a6ba8ecdfa7dd3c489e49142911 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C3=85slund?= Date: Fri, 17 Jan 2025 13:22:59 +0100 Subject: [PATCH 08/17] Simplified library --- main.py | 6 +++--- openhardwaremonitor/api.py | 12 ++++++++---- openhardwaremonitor/openhardwaremonitor.py | 15 --------------- 3 files changed, 11 insertions(+), 22 deletions(-) delete mode 100644 openhardwaremonitor/openhardwaremonitor.py diff --git a/main.py b/main.py index 3e5366a..ed373a6 100644 --- a/main.py +++ b/main.py @@ -2,14 +2,14 @@ import asyncio import json -from openhardwaremonitor import openhardwaremonitor +from openhardwaremonitor.api import OpenHardwareMonitorAPI async def main(): - ohm = openhardwaremonitor.OpenHardwareMonitor('192.168.50.20', 8085) + ohm = OpenHardwareMonitorAPI('192.168.50.20', 8085) data = await ohm.get_data() print(json.dumps(data)) - await ohm._api.close() + await ohm.close() if __name__ == '__main__': asyncio.run(main()) diff --git a/openhardwaremonitor/api.py b/openhardwaremonitor/api.py index acc06d4..c5c54f3 100644 --- a/openhardwaremonitor/api.py +++ b/openhardwaremonitor/api.py @@ -11,7 +11,7 @@ _LOGGER = logging.getLogger(__name__) -class API: +class OpenHardwareMonitorAPI: DEFAULT_TIMEOUT = 10 @@ -39,6 +39,10 @@ def __init__( self.API_URL = URL(f"http://{host}:{port}/") + async def authenticate(self): + """Perform authenticateion.""" + # todo: + def base_headers(self): return { "content-type": "application/json;charset=UTF-8", @@ -93,9 +97,9 @@ async def raw_request( # pylint: disable=too-many-arguments _LOGGER.debug("Response content: %s", content) return content - async def authenticate(self): - """Perform authenticateion.""" - # todo: + async def get_data(self): + json = await self.request("data.json") + return json async def close(self): """Close the session.""" diff --git a/openhardwaremonitor/openhardwaremonitor.py b/openhardwaremonitor/openhardwaremonitor.py deleted file mode 100644 index 213279a..0000000 --- a/openhardwaremonitor/openhardwaremonitor.py +++ /dev/null @@ -1,15 +0,0 @@ -from .api import API - - -class OpenHardwareMonitor: - - def __init__(self, *args, **kwargs): - """Initialize the client.""" - self._api = API(*args, **kwargs) - - async def get_data(self): - json = await self._api.request("data.json") - return json - - async def close(self): - return await self._api.close() From 4582868b5ee9d41c3d1cb386ca634aecbc3d5dd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C3=85slund?= Date: Fri, 17 Jan 2025 15:23:51 +0100 Subject: [PATCH 09/17] Simplify some more --- .flake8 | 10 ++++++++-- openhardwaremonitor/api.py | 13 ++----------- openhardwaremonitor/const.py | 2 +- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/.flake8 b/.flake8 index 0d3de30..3aee66f 100644 --- a/.flake8 +++ b/.flake8 @@ -1,7 +1,13 @@ [flake8] ignore = - # E501 = line too long - E501 + # line too long + E501, + + # insecure use of "random" module, prefer "random.SystemRandom", + DUO102, + + # Standard pseudo-random generators are not suitable for security/cryptographic purposes + S311 exclude = # No need to traverse our git directory diff --git a/openhardwaremonitor/api.py b/openhardwaremonitor/api.py index c5c54f3..685fa56 100644 --- a/openhardwaremonitor/api.py +++ b/openhardwaremonitor/api.py @@ -35,25 +35,16 @@ def __init__( self._close_session = True self._retry_count = retry_count - self._retry_delay = retry_delay or (lambda attempt: 3**attempt + random.SystemRandom.uniform(0, 3)) + self._retry_delay = retry_delay or (lambda attempt: 3**attempt + random.uniform(0, 3)) self.API_URL = URL(f"http://{host}:{port}/") - async def authenticate(self): - """Perform authenticateion.""" - # todo: - def base_headers(self): return { "content-type": "application/json;charset=UTF-8", "accept": "application/json, text/plain, */*", } - async def auth_headers(self): - await self.authenticate() - # return {**self.base_headers(), **self._auth_headers} - return {**self.base_headers()} - async def request(self, *args, **kwargs): """Perform request with error wrapping.""" try: @@ -75,7 +66,7 @@ async def raw_request( # pylint: disable=too-many-arguments method, self.API_URL.join(URL(uri)).update_query(params), json=data, - headers=await self.auth_headers(), + headers=self.base_headers(), timeout=self._timeout, ) as response: _LOGGER.debug("Request %s, status: %s", response.url, response.status) diff --git a/openhardwaremonitor/const.py b/openhardwaremonitor/const.py index 9a0c340..925c894 100644 --- a/openhardwaremonitor/const.py +++ b/openhardwaremonitor/const.py @@ -1,3 +1,3 @@ """Constants used by pyOpenHardwareMonitor""" -__version__ = "0.1.2" +__version__ = "0.1.3" From b93c74f0a5eef5f0ad1354581dff4c343cefe3dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C3=85slund?= Date: Fri, 17 Jan 2025 17:24:39 +0100 Subject: [PATCH 10/17] Remove code-checker for Python v3.14 --- .github/workflows/code-checker.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/code-checker.yml b/.github/workflows/code-checker.yml index ab9a4c3..092c0d9 100644 --- a/.github/workflows/code-checker.yml +++ b/.github/workflows/code-checker.yml @@ -13,7 +13,6 @@ jobs: - "3.11" - "3.12" - "3.13" - - "3.14" env: SRC_FOLDER: openhardwaremonitor steps: From 63a3a3981e371555d09b8b43a354965e635fe975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C3=85slund?= Date: Fri, 17 Jan 2025 17:30:30 +0100 Subject: [PATCH 11/17] Renamed module to pyopenhardwaremonitor --- .github/workflows/code-checker.yml | 2 +- README.md | 11 ++++++----- main.py | 2 +- openhardwaremonitor/const.py | 3 --- .../__init__.py | 0 {openhardwaremonitor => pyopenhardwaremonitor}/api.py | 0 pyopenhardwaremonitor/const.py | 3 +++ .../exceptions.py | 2 +- setup.cfg | 2 +- setup.py | 8 ++++---- 10 files changed, 17 insertions(+), 16 deletions(-) delete mode 100644 openhardwaremonitor/const.py rename {openhardwaremonitor => pyopenhardwaremonitor}/__init__.py (100%) rename {openhardwaremonitor => pyopenhardwaremonitor}/api.py (100%) create mode 100644 pyopenhardwaremonitor/const.py rename {openhardwaremonitor => pyopenhardwaremonitor}/exceptions.py (87%) diff --git a/.github/workflows/code-checker.yml b/.github/workflows/code-checker.yml index 092c0d9..e8692ab 100644 --- a/.github/workflows/code-checker.yml +++ b/.github/workflows/code-checker.yml @@ -14,7 +14,7 @@ jobs: - "3.12" - "3.13" env: - SRC_FOLDER: openhardwaremonitor + SRC_FOLDER: pyopenhardwaremonitor steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} diff --git a/README.md b/README.md index 90b0540..873d7c9 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Python3 library for getting data from [Open Hardware Monitor](https://openhardwa ## Install ``` -pip3 install pyOpenHardwareMonitor +pip3 install pyopenhardwaremonitor ``` ## Example @@ -13,14 +13,15 @@ pip3 install pyOpenHardwareMonitor ``` import asyncio import json -from openhardwaremonitor import OpenHardwareMonitor +from pyopenhardwaremonitor.api import OpenHardwareMonitorAPI async def main(): - ohm = OpenHardwareMonitor('192.168.1.114', 8085) + ohm = OpenHardwareMonitorAPI('192.168.1.114', 8085) data = await ohm.get_data() - json.dumps(data) - await ohm._api.close() + print(json.dumps(data)) + await ohm.close() if __name__ == '__main__': asyncio.run(main()) + ``` diff --git a/main.py b/main.py index ed373a6..937543f 100644 --- a/main.py +++ b/main.py @@ -2,7 +2,7 @@ import asyncio import json -from openhardwaremonitor.api import OpenHardwareMonitorAPI +from pyopenhardwaremonitor.api import OpenHardwareMonitorAPI async def main(): diff --git a/openhardwaremonitor/const.py b/openhardwaremonitor/const.py deleted file mode 100644 index 925c894..0000000 --- a/openhardwaremonitor/const.py +++ /dev/null @@ -1,3 +0,0 @@ -"""Constants used by pyOpenHardwareMonitor""" - -__version__ = "0.1.3" diff --git a/openhardwaremonitor/__init__.py b/pyopenhardwaremonitor/__init__.py similarity index 100% rename from openhardwaremonitor/__init__.py rename to pyopenhardwaremonitor/__init__.py diff --git a/openhardwaremonitor/api.py b/pyopenhardwaremonitor/api.py similarity index 100% rename from openhardwaremonitor/api.py rename to pyopenhardwaremonitor/api.py diff --git a/pyopenhardwaremonitor/const.py b/pyopenhardwaremonitor/const.py new file mode 100644 index 0000000..c1dad80 --- /dev/null +++ b/pyopenhardwaremonitor/const.py @@ -0,0 +1,3 @@ +"""Constants used by Open Hardware Monitor""" + +__version__ = "0.1.3" diff --git a/openhardwaremonitor/exceptions.py b/pyopenhardwaremonitor/exceptions.py similarity index 87% rename from openhardwaremonitor/exceptions.py rename to pyopenhardwaremonitor/exceptions.py index 728e52a..145ed93 100644 --- a/openhardwaremonitor/exceptions.py +++ b/pyopenhardwaremonitor/exceptions.py @@ -1,4 +1,4 @@ -"""Exceptions for the OpenHardwareMonitor REST API.""" +"""Exceptions for the OpenHardwareMonitor API.""" class OpenHardwareMonitorError(Exception): diff --git a/setup.cfg b/setup.cfg index 96fa367..58cdf60 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,2 +1,2 @@ [metadata] -name = pyOpenHardwareMonitor +name = pyopenhardwaremonitor diff --git a/setup.py b/setup.py index b9be741..ab3a81c 100644 --- a/setup.py +++ b/setup.py @@ -9,14 +9,14 @@ ] consts = {} -exec((Path("openhardwaremonitor") / "const.py").read_text(encoding="utf-8"), consts) # noqa: S102 +exec((Path("pyopenhardwaremonitor") / "const.py").read_text(encoding="utf-8"), consts) # noqa: S102 setup( - name="pyOpenHardwareMonitor", - packages=["openhardwaremonitor"], + name="pyopenhardwaremonitor", + packages=["pyopenhardwaremonitor"], install_requires=install_requires, version=consts["__version__"], - description="A python3 library to communicate with an OpenHardwareMonitor remote server", + description="A python3 library to communicate with an Open Hardware Monitor remote server", python_requires=">=3.11.0", author="Peter Åslund", author_email="peter@peteraslund.me", From 6e5af9273cfb133814c1dbcaae6371cdb57d138d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C3=85slund?= Date: Fri, 17 Jan 2025 17:32:52 +0100 Subject: [PATCH 12/17] Set version to v0.1.5 --- pyopenhardwaremonitor/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyopenhardwaremonitor/const.py b/pyopenhardwaremonitor/const.py index c1dad80..792ea08 100644 --- a/pyopenhardwaremonitor/const.py +++ b/pyopenhardwaremonitor/const.py @@ -1,3 +1,3 @@ """Constants used by Open Hardware Monitor""" -__version__ = "0.1.3" +__version__ = "0.1.4" From 70349dcfdf87ce4167246a804bd580d95c8cfae5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C3=85slund?= Date: Fri, 17 Jan 2025 18:11:35 +0100 Subject: [PATCH 13/17] Set version to v0.1.6 --- pyopenhardwaremonitor/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyopenhardwaremonitor/const.py b/pyopenhardwaremonitor/const.py index 792ea08..aceb595 100644 --- a/pyopenhardwaremonitor/const.py +++ b/pyopenhardwaremonitor/const.py @@ -1,3 +1,3 @@ """Constants used by Open Hardware Monitor""" -__version__ = "0.1.4" +__version__ = "0.1.6" From fa2fc9664379d3641ab5ba7394bd1cfc71d8741e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C3=85slund?= Date: Mon, 27 Jan 2025 11:32:42 +0100 Subject: [PATCH 14/17] Implemented a simple Async Context Manager --- pyopenhardwaremonitor/api.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pyopenhardwaremonitor/api.py b/pyopenhardwaremonitor/api.py index 685fa56..58288be 100644 --- a/pyopenhardwaremonitor/api.py +++ b/pyopenhardwaremonitor/api.py @@ -96,3 +96,9 @@ async def close(self): """Close the session.""" if self.session and self._close_session: await self.session.close() + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + await self.close() From 65696eae47685555bafc3ac90d4f74f4fa067955 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C3=85slund?= Date: Mon, 27 Jan 2025 14:03:11 +0100 Subject: [PATCH 15/17] Updating example and README --- README.md | 2 ++ example.py | 41 +++++++++++++++++++++++++++++++++++++++++ main.py | 15 --------------- 3 files changed, 43 insertions(+), 15 deletions(-) create mode 100644 example.py delete mode 100644 main.py diff --git a/README.md b/README.md index 873d7c9..545ace0 100644 --- a/README.md +++ b/README.md @@ -25,3 +25,5 @@ if __name__ == '__main__': asyncio.run(main()) ``` + +For a more detailed example, see `example.py` diff --git a/example.py b/example.py new file mode 100644 index 0000000..1b24798 --- /dev/null +++ b/example.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +import asyncio +import json +from pyopenhardwaremonitor.api import OpenHardwareMonitorAPI + + +async def main(host=None, port=8085): + """Main example on using pyOpenHardwareMonitor""" + host = host or get_current_ip() + print("Running against: ", host, port) + + # Example when using `async with` syntax + async with OpenHardwareMonitorAPI(host, port) as api: + data = await api.get_data() + j = json.dumps(data) + print(j) + return j + + # Example with explicit method calls + # api = OpenHardwareMonitorAPI(host, port) + # data = await api.get_data() + # await api.close() + # j = json.dumps(data) + # print(j) + # return j + + +def get_current_ip() -> str: + """Gets the local IP-address of this machine""" + import socket + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.connect(("8.8.8.8", 80)) + return str(s.getsockname()[0]) + + +if __name__ == '__main__': + # if running on Windows + asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) + + # Run main with async + asyncio.run(main()) diff --git a/main.py b/main.py deleted file mode 100644 index 937543f..0000000 --- a/main.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python3 - -import asyncio -import json -from pyopenhardwaremonitor.api import OpenHardwareMonitorAPI - - -async def main(): - ohm = OpenHardwareMonitorAPI('192.168.50.20', 8085) - data = await ohm.get_data() - print(json.dumps(data)) - await ohm.close() - -if __name__ == '__main__': - asyncio.run(main()) From d89c90c8a4a5ccec3b083082f84d0e081f8ac4db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C3=85slund?= Date: Sat, 8 Mar 2025 07:04:22 +0100 Subject: [PATCH 16/17] Adding workflows and pre-commit --- .github/release-drafter.yml | 55 ++++++++++++++++++++ .github/workflows/lint.yaml | 34 ++++++++++++ .github/workflows/python-publish.yml | 2 +- .github/workflows/release-drafter.yaml | 35 +++++++++++++ .github/workflows/sourcery-for-codebase.yaml | 22 ++++++++ .github/workflows/sourcery-for-pr.yaml | 23 ++++++++ .pre-commit-config.yaml | 28 ++++++++++ 7 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 .github/release-drafter.yml create mode 100644 .github/workflows/lint.yaml create mode 100644 .github/workflows/release-drafter.yaml create mode 100644 .github/workflows/sourcery-for-codebase.yaml create mode 100644 .github/workflows/sourcery-for-pr.yaml create mode 100644 .pre-commit-config.yaml diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 0000000..bc678c1 --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,55 @@ +--- +name-template: 'v$RESOLVED_VERSION' +tag-template: 'v$RESOLVED_VERSION' +change-template: '- #$NUMBER $TITLE' +sort-direction: ascending +exclude-contributors: + - 'github-actions[bot]' + - 'github-actions' + - 'renovate[bot]' + - 'renovate' + - 'pre-commit-ci' + - 'pre-commit-ci[bot]' + - 'crowdin-bot' +exclude-labels: + - 'skip-changelog' + - 'dependencies' +version-resolver: + major: + labels: + - 'major' + minor: + labels: + - 'minor' + patch: + labels: + - 'patch' + default: patch +autolabeler: + - label: 'ci/cd' + files: + - '/.github/**/*' + - label: 'documentation' + files: + - '*.md' + - '/docs/*' + branch: + - '/docs{0,1}\/.+/' + - label: 'bug' + branch: + - '/fix\/.+/' + title: + - '/fix/i' + - label: 'enhancement' + branch: + - '/feature\/.+/' + body: + - '/JIRA-[0-9]{1,4}/' +commitish: refs/heads/master +template: | + ## 🚀 Changes + + $CHANGES + + ## ❤️ Contributors + $CONTRIBUTORS diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml new file mode 100644 index 0000000..54f2a6d --- /dev/null +++ b/.github/workflows/lint.yaml @@ -0,0 +1,34 @@ +--- +name: "Lint" + +on: + # push: + pull_request: + # schedule: + # - cron: "0 0 * * *" + +jobs: + lint: + name: Lint + runs-on: "ubuntu-latest" + steps: + - name: "Checkout the repository" + uses: actions/checkout@v4 + + - name: "Set up Python" + uses: actions/setup-python@v5 + with: + python-version: "3.11" + cache: "pip" + + - name: "Install requirements" + run: python3 -m pip install -r requirements.txt + + - name: "ruff check ." + run: python3 -m ruff check . + + - name: yaml-lint + uses: ibiqlik/action-yamllint@v3 + with: + # file_or_dir: myfolder/*values*.yaml + config_file: .yamllint.yaml diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index ba520d3..ac5500d 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -13,7 +13,7 @@ on: tags: - v** release: - types: [created] + types: [published] permissions: contents: read diff --git a/.github/workflows/release-drafter.yaml b/.github/workflows/release-drafter.yaml new file mode 100644 index 0000000..703b511 --- /dev/null +++ b/.github/workflows/release-drafter.yaml @@ -0,0 +1,35 @@ +--- +name: Release Drafter + +on: + push: + branches: [main, master] + pull_request: + types: [opened, reopened, synchronize] + workflow_dispatch: + +permissions: + contents: read + +jobs: + update_release_draft: + permissions: + # write permission is required to create a github release + contents: write + # write permission is required for autolabeler + # otherwise, read permission is required at least + pull-requests: write + name: Update release draft + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Create Release + uses: release-drafter/release-drafter@v6 + with: + disable-releaser: github.ref != 'refs/heads/main' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/sourcery-for-codebase.yaml b/.github/workflows/sourcery-for-codebase.yaml new file mode 100644 index 0000000..df65e3a --- /dev/null +++ b/.github/workflows/sourcery-for-codebase.yaml @@ -0,0 +1,22 @@ +--- +name: Sourcery (for Codebase) + +on: + push: + branches: [main, master] + workflow_dispatch: + +jobs: + review-codebase-with-sourcery: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + + # https://github.com/sourcery-ai/action + - uses: sourcery-ai/action@v1 + with: + token: ${{ secrets.SOURCERY_TOKEN }} diff --git a/.github/workflows/sourcery-for-pr.yaml b/.github/workflows/sourcery-for-pr.yaml new file mode 100644 index 0000000..3b2c69b --- /dev/null +++ b/.github/workflows/sourcery-for-pr.yaml @@ -0,0 +1,23 @@ +--- +name: Sourcery (for PR) + +on: + pull_request: + +jobs: + review-pr-with-sourcery: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + + # https://github.com/sourcery-ai/action + - uses: sourcery-ai/action@v1 + with: + token: ${{ secrets.SOURCERY_TOKEN }} + diff_ref: ${{ github.event.pull_request.base.sha }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..3797bfe --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,28 @@ +--- +repos: + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.9.7 + hooks: + - id: ruff + args: + - --fix + - id: ruff-format + files: ^((pyopenhardwaremonitor|tests)/.+)?[^/]+\.(py|pyi)$ + + - repo: https://github.com/adrienverge/yamllint.git + rev: v1.35.1 + hooks: + - id: yamllint + language: python + types: [file, yaml] + files: ^((pyopenhardwaremonitor|tests)/.+)?[^/]+\.(yaml|yml)$ + + - repo: https://github.com/sourcery-ai/sourcery + rev: v1.34.0 + hooks: + - id: sourcery + # The best way to use Sourcery in a pre-commit hook: + # * review only changed lines: + # * omit the summary + args: [--diff=git diff HEAD, --no-summary] + stages: [pre-push] From a91619fae8f92990fd72465a68955e28bcc26d52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C3=85slund?= Date: Sat, 8 Mar 2025 07:09:56 +0100 Subject: [PATCH 17/17] pre-commit run --all-files --- .github/release-drafter.yml | 2 +- FUNDING.yml | 4 ++-- example.py | 3 ++- pyopenhardwaremonitor/api.py | 16 +++++++++++----- setup.py | 2 +- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index bc678c1..bb272cb 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -45,7 +45,7 @@ autolabeler: - '/feature\/.+/' body: - '/JIRA-[0-9]{1,4}/' -commitish: refs/heads/master +commitish: refs/heads/main template: | ## 🚀 Changes diff --git a/FUNDING.yml b/FUNDING.yml index ebba2a5..05a574c 100644 --- a/FUNDING.yml +++ b/FUNDING.yml @@ -1,4 +1,4 @@ # These are supported funding model platforms - +--- github: lazytarget -custom: "https://paypal.me/peteraslund" \ No newline at end of file +custom: "https://paypal.me/peteraslund" diff --git a/example.py b/example.py index 1b24798..9d35629 100644 --- a/example.py +++ b/example.py @@ -28,12 +28,13 @@ async def main(host=None, port=8085): def get_current_ip() -> str: """Gets the local IP-address of this machine""" import socket + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(("8.8.8.8", 80)) return str(s.getsockname()[0]) -if __name__ == '__main__': +if __name__ == "__main__": # if running on Windows asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) diff --git a/pyopenhardwaremonitor/api.py b/pyopenhardwaremonitor/api.py index 58288be..2afbf2f 100644 --- a/pyopenhardwaremonitor/api.py +++ b/pyopenhardwaremonitor/api.py @@ -12,7 +12,6 @@ class OpenHardwareMonitorAPI: - DEFAULT_TIMEOUT = 10 def __init__( @@ -23,7 +22,7 @@ def __init__( session=None, timeout=DEFAULT_TIMEOUT, retry_count=3, - retry_delay=None + retry_delay=None, ): self._timeout = timeout self._close_session = False @@ -35,7 +34,9 @@ def __init__( self._close_session = True self._retry_count = retry_count - self._retry_delay = retry_delay or (lambda attempt: 3**attempt + random.uniform(0, 3)) + self._retry_delay = retry_delay or ( + lambda attempt: 3**attempt + random.uniform(0, 3) + ) self.API_URL = URL(f"http://{host}:{port}/") @@ -76,11 +77,16 @@ async def raw_request( # pylint: disable=too-many-arguments delay = self._retry_delay(attempt) _LOGGER.info("Request limit exceeded, retrying in %s second", delay) await asyncio.sleep(delay) - return await self.raw_request(uri, params, data, method, attempt=attempt + 1) + return await self.raw_request( + uri, params, data, method, attempt=attempt + 1 + ) raise OpenHardwareMonitorError("Request limit exceeded") content = None - if "Content-Type" in response.headers and "application/json" in response.headers["Content-Type"]: + if ( + "Content-Type" in response.headers + and "application/json" in response.headers["Content-Type"] + ): content = await response.json() else: content = await response.read() diff --git a/setup.py b/setup.py index ab3a81c..8f9817c 100644 --- a/setup.py +++ b/setup.py @@ -29,6 +29,6 @@ "Programming Language :: Python :: 3", "Topic :: Home Automation", "Topic :: Software Development :: Libraries :: Python Modules", - "License :: OSI Approved :: MIT License" + "License :: OSI Approved :: MIT License", ], )