pax_global_header00006660000000000000000000000064147222633760014526gustar00rootroot0000000000000052 comment=4d4cc97e2b88e20c494dfc4776c8ed0e36a5138e python-glances-api-0.9.0/000077500000000000000000000000001472226337600152365ustar00rootroot00000000000000python-glances-api-0.9.0/.github/000077500000000000000000000000001472226337600165765ustar00rootroot00000000000000python-glances-api-0.9.0/.github/workflows/000077500000000000000000000000001472226337600206335ustar00rootroot00000000000000python-glances-api-0.9.0/.github/workflows/testing.yml000066400000000000000000000022771472226337600230430ustar00rootroot00000000000000name: Testing on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build: runs-on: ubuntu-latest strategy: matrix: python-version: [ "3.11", "3.12", "3.13" ] steps: - name: Checkout uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install Poetry uses: snok/install-poetry@v1 with: virtualenvs-create: true virtualenvs-in-project: true installer-parallel: true - name: Load cached venv id: cached-poetry-dependencies uses: actions/cache@v4 with: path: .venv key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }} - name: Install dependencies if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' run: poetry install --no-interaction --no-root - name: Install library run: poetry install --no-interaction - name: Run tests run: | source .venv/bin/activate pytest tests/ - name: Black Code Formatter uses: jpetrucciani/black-check@22.12.0 python-glances-api-0.9.0/CHANGES.rst000066400000000000000000000046021472226337600170420ustar00rootroot00000000000000Changes ======= 0.9.0 - 2024-11-29 ------------------ - Add support for Glances containers (Thanks @pszypowicz) - Fix tests with pytest-httpx 0.32.0 (Thanks @mweinelt) 0.8.0 - 2024-06-09 ------------------ - Add/improve support for Glances v4 container & network format and improve v4 unit tests (Thanks @wittypluck) 0.7.0 - 2024-05-21 ------------------ - Add support for Glances v4 network sensors (Thanks @wittypluck) 0.6.0 - 2024-02-04 ------------------ - Fix network RX and TX for Home Assistant (bytes/s) (Thanks @wittypluck) - Reformat GPU data for Home Assistant and add unit test (Thanks @wittypluck) - Add diskio sensors for Home Assistant (in bytes/second) (Thanks @wittypluck) - Support for Python 3.12, pytest > 8 0.5.1 - 2024-01-11 ------------------ - Add guard for glances v2 (Thanks @engrbm87) - Add missing type hints (Thanks @engrbm87) 0.5.0 - 2023-11-17 ------------------ - Deprecate support for API v2 (Thanks @engrbm87) - Fix type hint for get_ha_sensor_data (Thanks @engrbm87) - Add percpu data (Thanks @engrbm87) - Update containers data key (Thanks @engrbm87) - Add GPU sensors (Thanks @neuralyze) - Update dependencies 0.4.3 - 2023-06-27 ------------------ - Add network information to Home Assistant data (Thanks @freeDom-) - Add uptime information to Home Assistant data (Thanks @freeDom-) - Update dependencies 0.4.2 - 2023-05-21 ------------------ - Safe access container dict when memory or cpu is not exposed (Thanks @freeDom-) 20220828 - 0.4.1 ---------------- - Raise error for any not OK response code (Thanks @engrbm87) - Update dependencies 20220819 - 0.4.0 ---------------- - Add pre-definied output for Home Assistant (Thanks @engrbm87) - Extend typing support 20220605 - 0.3.6 ---------------- - Use latest httpx release (CVE-2021-41945) 20220503 - 0.3.5 ---------------- - Handle TimeoutException (Thanks @b0z02003) 20220116 - 0.3.4 ---------------- - Allow using a custom external httpx client (Thanks @GuyKh) 20220104 - 0.3.3 ---------------- - Support later pytest-httpx releases 20211123 - 0.3.2 ---------------- - Remove version constraint of httpx 20211107 - 0.3.1 ---------------- - Add exception for invalid credentials (Thanks @engrbm87) 20211106 - 0.3.0 ---------------- - Migrate to pyproject style - Mgrate to httpx 20181121 - 0.2.0 ---------------- - Support for HTTP Basic authentication 20180814 - 0.1.0 ---------------- - Initial release python-glances-api-0.9.0/LICENSE000066400000000000000000000021261472226337600162440ustar00rootroot00000000000000MIT License Copyright (c) 2017-2024 Fabian Affolter Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. python-glances-api-0.9.0/README.rst000066400000000000000000000016741472226337600167350ustar00rootroot00000000000000python-glances-api ================== A Python client for interacting with `Glances `_. This module is not official, developed, supported or endorsed by Glances. Installation ------------ The module is available from the `Python Package Index `_. .. code:: bash $ pip3 install glances_api Or on a Fedora-based system or on a CentOS/RHEL machine with has EPEL enabled. .. code:: bash $ sudo dnf -y install python3-glances-api For Nix or NixOS is `pre-packed module `_ available. The lastest release is usually present in the ``unstable`` channel. .. code:: bash $ nix-env -iA nixos.python3Packages.glances-api Usage ----- The file ``example.py`` contains an example about how to use this module. License ------- ``python-glances-api`` is licensed under MIT, for more details check LICENSE. python-glances-api-0.9.0/example.py000066400000000000000000000012771472226337600172520ustar00rootroot00000000000000"""Sample script to use the Python API client for Glances.""" import asyncio from glances_api import Glances HOST = "127.0.0.1" VERSION = 3 async def main(): """The main part of the example script.""" data = Glances(version=VERSION) # Get the metrics for the memory await data.get_metrics("mem") # Print the values print("Memory values:", data.values) # Get the metrics about the disks await data.get_metrics("diskio") # Print the values print("Disk values:", data.values) # Get the data for Home Assistant print("Output to use with Home Assistant") print(await data.get_ha_sensor_data()) if __name__ == "__main__": asyncio.run(main()) python-glances-api-0.9.0/glances_api/000077500000000000000000000000001472226337600175035ustar00rootroot00000000000000python-glances-api-0.9.0/glances_api/__init__.py000066400000000000000000000223531472226337600216210ustar00rootroot00000000000000"""Client to interact with the Glances API.""" from __future__ import annotations import logging from typing import Any import httpx from . import exceptions _LOGGER = logging.getLogger(__name__) class Glances: """A class for handling the data retrieval.""" def __init__( self, host: str = "localhost", port: int = 61208, version: int = 3, ssl: bool = False, verify_ssl: bool = True, username: str | None = None, password: str | None = None, httpx_client: httpx.AsyncClient | None = None, ): """Initialize the connection.""" if version == 2: _LOGGER.warning( "Glances api older than v3 will not be supported in the next release." ) schema = "https" if ssl else "http" self.url = f"{schema}://{host}:{port}/api/{version}" self.data: dict[str, Any] = {} self.plugins: list[str] = [] self.values: dict[str, Any] | None = None self.username = username self.password = password self.verify_ssl = verify_ssl self.httpx_client = httpx_client self.version = version async def get_data(self, endpoint: str) -> None: """Retrieve the data.""" url = f"{self.url}/{endpoint}" httpx_client = ( self.httpx_client if self.httpx_client else httpx.AsyncClient(verify=self.verify_ssl) ) try: async with httpx_client as client: if self.password is None: response = await client.get(url) elif self.username is not None: response = await client.get( url, auth=(self.username, self.password) ) else: raise ValueError("username and password must be provided.") except (httpx.ConnectError, httpx.TimeoutException) as err: raise exceptions.GlancesApiConnectionError( f"Connection to {url} failed" ) from err if response.status_code == httpx.codes.UNAUTHORIZED: raise exceptions.GlancesApiAuthorizationError( "Please check your credentials" ) if response.status_code != httpx.codes.OK: raise exceptions.GlancesApiNoDataAvailable( f"endpoint: '{endpoint}' is not valid" ) try: _LOGGER.debug(response.json()) if endpoint == "all": self.data = response.json() elif endpoint == "pluginslist": self.plugins = response.json() except TypeError as err: _LOGGER.error("Can not load data from Glances") raise exceptions.GlancesApiConnectionError( "Unable to get the data from Glances" ) from err async def get_metrics(self, element: str) -> None: """Get all the metrics for a monitored element.""" await self.get_data("all") await self.get_data("pluginslist") if element in self.plugins: self.values = self.data[element] else: raise exceptions.GlancesApiError("Element data not available") async def get_ha_sensor_data(self) -> dict[str, Any]: """Create a dictionary with data for Home Assistant sensors.""" await self.get_data("all") sensor_data: dict[str, Any] = {} if disks := self.data.get("fs"): sensor_data["fs"] = {} for disk in disks: disk_free = disk.get("free") or (disk["size"] - disk["used"]) sensor_data["fs"][disk["mnt_point"]] = { "disk_use": round(disk["used"] / 1024**3, 1), "disk_use_percent": disk["percent"], "disk_free": round(disk_free / 1024**3, 1), } if data := self.data.get("sensors"): sensor_data["sensors"] = {} for sensor in data: sensor_data["sensors"][sensor["label"]] = { sensor["type"]: sensor["value"] } if data := self.data.get("mem"): sensor_data["mem"] = { "memory_use_percent": data["percent"], "memory_use": round(data["used"] / 1024**2, 1), "memory_free": round(data["free"] / 1024**2, 1), } if data := self.data.get("memswap"): sensor_data["memswap"] = { "swap_use_percent": data["percent"], "swap_use": round(data["used"] / 1024**3, 1), "swap_free": round(data["free"] / 1024**3, 1), } if data := self.data.get("load"): sensor_data["load"] = { "processor_load": data.get("min15"), "processor_load_1m": data.get("min1"), "processor_load_5m": data.get("min5"), } if data := self.data.get("processcount"): sensor_data["processcount"] = { "process_running": data["running"], "process_total": data["total"], "process_thread": data["thread"], "process_sleeping": data["sleeping"], } if data := self.data.get("quicklook"): sensor_data["cpu"] = {"cpu_use_percent": data["cpu"]} if data := self.data.get("percpu"): sensor_data["percpu"] = {} for cpu in data: sensor_data["percpu"][str(cpu["cpu_number"])] = { "cpu_use_percent": cpu["total"] } if networks := self.data.get("network"): sensor_data["network"] = {} for network in networks: rx = tx = None if self.version <= 3: time_since_update = network["time_since_update"] if (rx_bytes := network.get("rx")) is not None: rx = round(rx_bytes / time_since_update) if (tx_bytes := network.get("tx")) is not None: tx = round(tx_bytes / time_since_update) else: # New network sensors in Glances v4 rx = network.get("bytes_recv_rate_per_sec") tx = network.get("bytes_sent_rate_per_sec") sensor_data["network"][network["interface_name"]] = { "is_up": network.get("is_up"), "rx": rx, "tx": tx, "speed": round(network["speed"] / 1024**3, 1), } containers_data = None if self.version <= 3: # Glances v3 and earlier provide a dict, with containers inside a list in this dict # Key is "dockers" in 3.3 and before, and "containers" in 3.4 data = self.data.get("dockers") or self.data.get("containers") containers_data = data.get("containers") if data else None else: # Glances v4 provides a list of containers containers_data = self.data.get("containers") if containers_data: sensor_data["containers"] = {} active_containers = [ container for container in containers_data # "status" since Glance v4, "Status" in v3 and earlier if container.get("status") == "running" or container.get("Status") == "running" ] sensor_data["docker"] = {"docker_active": len(active_containers)} cpu_use = 0.0 for container in active_containers: cpu_use += container["cpu"].get("total", 0) sensor_data["docker"]["docker_cpu_use"] = round(cpu_use, 1) mem_use = 0.0 for container in active_containers: mem_use += container["memory"].get("usage", 0) sensor_data["docker"]["docker_memory_use"] = round(mem_use / 1024**2, 1) for container in active_containers: sensor_data["containers"][container["name"]] = { "container_cpu_use": round(container["cpu"].get("total", 0), 1), "container_memory_use": round( container["memory"].get("usage", 0) / 1024**2, 1 ), } if data := self.data.get("raid"): sensor_data["raid"] = data if data := self.data.get("uptime"): sensor_data["uptime"] = data if data := self.data.get("gpu"): sensor_data["gpu"] = {} for sensor in data: sensor_data["gpu"][f"{sensor['name']} (GPU {sensor['gpu_id']})"] = { "temperature": sensor.get("temperature", 0), "mem": sensor.get("mem", 0), "proc": sensor.get("proc", 0), "fan_speed": sensor.get("fan_speed", 0), } if data := self.data.get("diskio"): sensor_data["diskio"] = {} for disk in data: time_since_update = disk["time_since_update"] sensor_data["diskio"][disk["disk_name"]] = { "read": round(disk["read_bytes"] / time_since_update), "write": round(disk["write_bytes"] / time_since_update), } return sensor_data python-glances-api-0.9.0/glances_api/exceptions.py000066400000000000000000000006431472226337600222410ustar00rootroot00000000000000"""Exceptions for the client.""" class GlancesApiError(Exception): """General GlancesApiError exception occurred.""" class GlancesApiConnectionError(GlancesApiError): """When a connection error is encountered.""" class GlancesApiAuthorizationError(GlancesApiError): """When a connection error is encountered.""" class GlancesApiNoDataAvailable(GlancesApiError): """When no data is available.""" python-glances-api-0.9.0/poetry.lock000066400000000000000000000440601472226337600174360ustar00rootroot00000000000000# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. [[package]] name = "anyio" version = "4.6.2.post1" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.9" files = [ {file = "anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d"}, {file = "anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c"}, ] [package.dependencies] idna = ">=2.8" sniffio = ">=1.1" [package.extras] doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21.0b1)"] trio = ["trio (>=0.26.1)"] [[package]] name = "black" version = "24.10.0" description = "The uncompromising code formatter." optional = false python-versions = ">=3.9" files = [ {file = "black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812"}, {file = "black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea"}, {file = "black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f"}, {file = "black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e"}, {file = "black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad"}, {file = "black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50"}, {file = "black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392"}, {file = "black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175"}, {file = "black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3"}, {file = "black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65"}, {file = "black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f"}, {file = "black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8"}, {file = "black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981"}, {file = "black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b"}, {file = "black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2"}, {file = "black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b"}, {file = "black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd"}, {file = "black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f"}, {file = "black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800"}, {file = "black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7"}, {file = "black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d"}, {file = "black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875"}, ] [package.dependencies] click = ">=8.0.0" mypy-extensions = ">=0.4.3" packaging = ">=22.0" pathspec = ">=0.9.0" platformdirs = ">=2" [package.extras] colorama = ["colorama (>=0.4.3)"] d = ["aiohttp (>=3.10)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "certifi" version = "2024.8.30" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, ] [[package]] name = "click" version = "8.1.7" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" files = [ {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, ] [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} [[package]] name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] [[package]] name = "h11" version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false python-versions = ">=3.7" files = [ {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, ] [[package]] name = "httpcore" version = "1.0.6" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" files = [ {file = "httpcore-1.0.6-py3-none-any.whl", hash = "sha256:27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f"}, {file = "httpcore-1.0.6.tar.gz", hash = "sha256:73f6dbd6eb8c21bbf7ef8efad555481853f5f6acdeaff1edb0694289269ee17f"}, ] [package.dependencies] certifi = "*" h11 = ">=0.13,<0.15" [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.27.2" description = "The next generation HTTP client." optional = false python-versions = ">=3.8" files = [ {file = "httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0"}, {file = "httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2"}, ] [package.dependencies] anyio = "*" certifi = "*" httpcore = "==1.*" idna = "*" sniffio = "*" [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 = "idna" version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] [package.extras] all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] [[package]] name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.7" files = [ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] [[package]] name = "isort" version = "5.13.2" description = "A Python utility / library to sort Python imports." optional = false python-versions = ">=3.8.0" files = [ {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, ] [package.extras] colors = ["colorama (>=0.4.6)"] [[package]] name = "mypy" version = "0.971" description = "Optional static typing for Python" optional = false python-versions = ">=3.6" files = [ {file = "mypy-0.971-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f2899a3cbd394da157194f913a931edfd4be5f274a88041c9dc2d9cdcb1c315c"}, {file = "mypy-0.971-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:98e02d56ebe93981c41211c05adb630d1d26c14195d04d95e49cd97dbc046dc5"}, {file = "mypy-0.971-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:19830b7dba7d5356d3e26e2427a2ec91c994cd92d983142cbd025ebe81d69cf3"}, {file = "mypy-0.971-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:02ef476f6dcb86e6f502ae39a16b93285fef97e7f1ff22932b657d1ef1f28655"}, {file = "mypy-0.971-cp310-cp310-win_amd64.whl", hash = "sha256:25c5750ba5609a0c7550b73a33deb314ecfb559c350bb050b655505e8aed4103"}, {file = "mypy-0.971-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d3348e7eb2eea2472db611486846742d5d52d1290576de99d59edeb7cd4a42ca"}, {file = "mypy-0.971-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3fa7a477b9900be9b7dd4bab30a12759e5abe9586574ceb944bc29cddf8f0417"}, {file = "mypy-0.971-cp36-cp36m-win_amd64.whl", hash = "sha256:2ad53cf9c3adc43cf3bea0a7d01a2f2e86db9fe7596dfecb4496a5dda63cbb09"}, {file = "mypy-0.971-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:855048b6feb6dfe09d3353466004490b1872887150c5bb5caad7838b57328cc8"}, {file = "mypy-0.971-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:23488a14a83bca6e54402c2e6435467a4138785df93ec85aeff64c6170077fb0"}, {file = "mypy-0.971-cp37-cp37m-win_amd64.whl", hash = "sha256:4b21e5b1a70dfb972490035128f305c39bc4bc253f34e96a4adf9127cf943eb2"}, {file = "mypy-0.971-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:9796a2ba7b4b538649caa5cecd398d873f4022ed2333ffde58eaf604c4d2cb27"}, {file = "mypy-0.971-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5a361d92635ad4ada1b1b2d3630fc2f53f2127d51cf2def9db83cba32e47c856"}, {file = "mypy-0.971-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b793b899f7cf563b1e7044a5c97361196b938e92f0a4343a5d27966a53d2ec71"}, {file = "mypy-0.971-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d1ea5d12c8e2d266b5fb8c7a5d2e9c0219fedfeb493b7ed60cd350322384ac27"}, {file = "mypy-0.971-cp38-cp38-win_amd64.whl", hash = "sha256:23c7ff43fff4b0df93a186581885c8512bc50fc4d4910e0f838e35d6bb6b5e58"}, {file = "mypy-0.971-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1f7656b69974a6933e987ee8ffb951d836272d6c0f81d727f1d0e2696074d9e6"}, {file = "mypy-0.971-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d2022bfadb7a5c2ef410d6a7c9763188afdb7f3533f22a0a32be10d571ee4bbe"}, {file = "mypy-0.971-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef943c72a786b0f8d90fd76e9b39ce81fb7171172daf84bf43eaf937e9f220a9"}, {file = "mypy-0.971-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d744f72eb39f69312bc6c2abf8ff6656973120e2eb3f3ec4f758ed47e414a4bf"}, {file = "mypy-0.971-cp39-cp39-win_amd64.whl", hash = "sha256:77a514ea15d3007d33a9e2157b0ba9c267496acf12a7f2b9b9f8446337aac5b0"}, {file = "mypy-0.971-py3-none-any.whl", hash = "sha256:0d054ef16b071149917085f51f89555a576e2618d5d9dd70bd6eea6410af3ac9"}, {file = "mypy-0.971.tar.gz", hash = "sha256:40b0f21484238269ae6a57200c807d80debc6459d444c0489a102d7c6a75fa56"}, ] [package.dependencies] mypy-extensions = ">=0.4.3" typing-extensions = ">=3.10" [package.extras] dmypy = ["psutil (>=4.0)"] python2 = ["typed-ast (>=1.4.0,<2)"] reports = ["lxml"] [[package]] name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false python-versions = ">=3.5" files = [ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] [[package]] name = "packaging" version = "24.1" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" files = [ {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] [[package]] name = "pathspec" version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." optional = false python-versions = ">=3.8" files = [ {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, ] [[package]] name = "platformdirs" version = "4.3.6" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" files = [ {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, ] [package.extras] docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] type = ["mypy (>=1.11.2)"] [[package]] name = "pluggy" version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, ] [package.extras] dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] [[package]] name = "pytest" version = "8.3.3" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, ] [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} iniconfig = "*" packaging = "*" pluggy = ">=1.5,<2" [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-asyncio" version = "0.16.0" description = "Pytest support for asyncio." optional = false python-versions = ">= 3.6" files = [ {file = "pytest-asyncio-0.16.0.tar.gz", hash = "sha256:7496c5977ce88c34379df64a66459fe395cd05543f0a2f837016e7144391fcfb"}, {file = "pytest_asyncio-0.16.0-py3-none-any.whl", hash = "sha256:5f2a21273c47b331ae6aa5b36087047b4899e40f03f18397c0e65fa5cca54e9b"}, ] [package.dependencies] pytest = ">=5.4.0" [package.extras] testing = ["coverage", "hypothesis (>=5.7.1)"] [[package]] name = "pytest-httpx" version = "0.32.0" description = "Send responses to httpx." optional = false python-versions = ">=3.9" files = [ {file = "pytest_httpx-0.32.0-py3-none-any.whl", hash = "sha256:685d93ce5e5edb5e52310b72342cdc190bebf83aab058328943dd8bd8f6ac790"}, {file = "pytest_httpx-0.32.0.tar.gz", hash = "sha256:7807647e8254e5cff79bf2041ae272449ce915d3cf1bbecaa581c384163adb87"}, ] [package.dependencies] httpx = "==0.27.*" pytest = "==8.*" [package.extras] testing = ["pytest-asyncio (==0.24.*)", "pytest-cov (==5.*)"] [[package]] name = "sniffio" version = "1.3.1" description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" 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 = "typing-extensions" version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [metadata] lock-version = "2.0" python-versions = "^3.11" content-hash = "4a76e01c3273325242cf03d28ce74503f609aa0af5bbe31e77ce81ec75870cde" python-glances-api-0.9.0/py.typed000066400000000000000000000000001472226337600167230ustar00rootroot00000000000000python-glances-api-0.9.0/pyproject.toml000066400000000000000000000025511472226337600201550ustar00rootroot00000000000000[tool.poetry] name = "glances_api" version = "0.9.0" description = "Python API for interacting with Glances" authors = ["Fabian Affolter "] homepage = "https://github.com/home-assistant-ecosystem/python-glances-api" repository = "https://github.com/home-assistant-ecosystem/python-glances-api/releases" readme = "README.rst" license = "MIT" classifiers = [ "Development Status :: 3 - Alpha", "Environment :: Console", "Intended Audience :: Developers", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Topic :: Utilities", ] [tool.poetry.dependencies] python = "^3.11" httpx = ">=0.23,<1" [tool.poetry.dev-dependencies] black = "^24.3" pytest = "^8" pytest-httpx = ">0.15,<1" pytest-asyncio = "^0.16.0" isort = "^5.10.0" mypy = "^0.971" [tool.mypy] check_untyped_defs = true disallow_any_generics = true disallow_incomplete_defs = true disallow_untyped_defs = true mypy_path = "glances_api/" no_implicit_optional = true show_error_codes = true warn_unreachable = true warn_unused_ignores = true exclude = [ 'pyproject.toml', ] [[tool.mypy.overrides]] module = "tests.*" allow_untyped_defs = true [[tool.mypy.overrides]] module = "docs.*" ignore_errors = true [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" python-glances-api-0.9.0/tests/000077500000000000000000000000001472226337600164005ustar00rootroot00000000000000python-glances-api-0.9.0/tests/__init__.py000066400000000000000000000000471472226337600205120ustar00rootroot00000000000000"""Test for the Glances API client.""" python-glances-api-0.9.0/tests/test_responses.py000066400000000000000000000332101472226337600220310ustar00rootroot00000000000000"""Test the interaction with the Glances API.""" from typing import Any import pytest from pytest_httpx import HTTPXMock from glances_api import Glances from glances_api.exceptions import GlancesApiNoDataAvailable PLUGINS_LIST_RESPONSE = [ "alert", "amps", "cloud", "connections", "core", "cpu", "diskio", "docker", "folders", "fs", ] RESPONSE: dict[str, Any] = { "cpu": { "total": 10.6, "user": 7.6, "system": 2.1, "idle": 88.8, "nice": 0.0, "iowait": 0.6, }, "percpu": [ { "key": "cpu_number", "cpu_number": 0, "total": 22.1, "user": 7.6, "system": 12.4, "idle": 77.9, "nice": 0.0, "iowait": 0.2, "irq": 0.0, "softirq": 1.8, "steal": 0.0, "guest": 0.0, "guest_nice": 0.0, }, { "key": "cpu_number", "cpu_number": 1, "total": 17.2, "user": 8.7, "system": 7.8, "idle": 82.8, "nice": 0.0, "iowait": 0.4, "irq": 0.0, "softirq": 0.3, "steal": 0.0, "guest": 0.0, "guest_nice": 0.0, }, ], "diskio": [ { "time_since_update": 1, "disk_name": "nvme0n1", "read_count": 12, "write_count": 466, "read_bytes": 184320, "write_bytes": 23863296, "key": "disk_name", }, { "time_since_update": 142.23511338233948, "disk_name": "sda", "read_count": 34, "write_count": 254, "read_bytes": 548864, "write_bytes": 3691520, "key": "disk_name", }, ], "containers": { "version": {}, "version_podman": {}, "containers": [ { "key": "name", "name": "container1", "Status": "running", "cpu": {"total": 50.94973493230174}, "cpu_percent": 50.94973493230174, "memory": { "usage": 1120321536, "limit": 3976318976, "rss": 480641024, "cache": 580915200, "max_usage": 1309597696, }, "memory_usage": 539406336, }, { "key": "name", "name": "container2", "Status": "running", "cpu": {"total": 26.23567931034483}, "cpu_percent": 26.23567931034483, "memory": { "usage": 85139456, "limit": 3976318976, "rss": 33677312, "cache": 35012608, "max_usage": 87650304, }, "memory_usage": 50126848, }, ], }, "fs": [ { "device_name": "/dev/sda8", "fs_type": "ext4", "mnt_point": "/ssl", "size": 511320748032, "used": 32910458880, "free": 457917374464, "percent": 6.7, "key": "mnt_point", }, { "device_name": "/dev/sda8", "fs_type": "ext4", "mnt_point": "/media", "size": 511320748032, "used": 32910458880, "free": 457917374464, "percent": 6.7, "key": "mnt_point", }, ], "gpu": [ { "key": "gpu_id", "gpu_id": 0, "name": "NVIDIA GeForce RTX 4080", "mem": 13.333489176233513, "proc": 12, "temperature": 38, "fan_speed": 30, }, { "key": "gpu_id", "gpu_id": 1, "name": "NVIDIA GeForce RTX 3080", "mem": 8.41064453125, "proc": 26, "temperature": 51, "fan_speed": 0, }, ], "mem": { "total": 3976318976, "available": 2878337024, "percent": 27.6, "used": 1097981952, "free": 2878337024, "active": 567971840, "inactive": 1679704064, "buffers": 149807104, "cached": 1334816768, "shared": 1499136, }, "network": [ { "cumulative_cx": 19027046, "cumulative_rx": 9513523, "cumulative_tx": 9513523, "cx": 23770, "interface_name": "lo", "is_up": True, "key": "interface_name", "rx": 11885, "speed": 0, "time_since_update": 1.55433297157288, "tx": 11885, }, { "cumulative_cx": 0, "cumulative_rx": 0, "cumulative_tx": 0, "cx": 0, "interface_name": "bond0", "is_up": False, "key": "interface_name", "rx": 0, "speed": 68718428160, "time_since_update": 1.55433297157288, "tx": 0, }, { "cumulative_cx": 0, "cumulative_rx": 0, "cumulative_tx": 0, "cx": 0, "interface_name": "dummy0", "is_up": False, "key": "interface_name", "rx": 0, "speed": 0, "time_since_update": 1.55433297157288, "tx": 0, }, { "cumulative_cx": 704585, "cumulative_rx": 518329, "cumulative_tx": 186256, "cx": 15463, "interface_name": "eth0", "is_up": True, "key": "interface_name", "rx": 6144, "speed": 10485760000, "time_since_update": 1.55433297157288, "tx": 9319, }, { "cumulative_cx": 0, "cumulative_rx": 0, "cumulative_tx": 0, "cx": 0, "interface_name": "tunl0", "is_up": False, "key": "interface_name", "rx": 0, "speed": 0, "time_since_update": 1.55433297157288, "tx": 0, }, { "cumulative_cx": 0, "cumulative_rx": 0, "cumulative_tx": 0, "cx": 0, "interface_name": "sit0", "is_up": False, "key": "interface_name", "rx": 0, "speed": 0, "time_since_update": 1.55433297157288, "tx": 0, }, ], "sensors": [ { "label": "cpu_thermal 1", "value": 59, "warning": None, "critical": None, "unit": "C", "type": "temperature_core", "key": "label", } ], "system": { "os_name": "Linux", "hostname": "fedora-35", "platform": "64bit", "linux_distro": "Fedora Linux 35", "os_version": "5.15.6-200.fc35.x86_64", "hr_name": "Fedora Linux 35 64bit", }, "uptime": "3 days, 10:25:20", } HA_SENSOR_DATA: dict[str, Any] = { "fs": { "/ssl": {"disk_use": 30.7, "disk_use_percent": 6.7, "disk_free": 426.5}, "/media": {"disk_use": 30.7, "disk_use_percent": 6.7, "disk_free": 426.5}, }, "sensors": {"cpu_thermal 1": {"temperature_core": 59}}, "mem": { "memory_use_percent": 27.6, "memory_use": 1047.1, "memory_free": 2745.0, }, "network": { "lo": {"is_up": True, "rx": 7646, "tx": 7646, "speed": 0.0}, "bond0": {"is_up": False, "rx": 0.0, "tx": 0.0, "speed": 64.0}, "dummy0": {"is_up": False, "rx": 0.0, "tx": 0.0, "speed": 0.0}, "eth0": {"is_up": True, "rx": 3953, "tx": 5995, "speed": 9.8}, "tunl0": {"is_up": False, "rx": 0.0, "tx": 0.0, "speed": 0.0}, "sit0": {"is_up": False, "rx": 0.0, "tx": 0.0, "speed": 0.0}, }, "docker": {"docker_active": 2, "docker_cpu_use": 77.2, "docker_memory_use": 1149.6}, "uptime": "3 days, 10:25:20", "percpu": {"0": {"cpu_use_percent": 22.1}, "1": {"cpu_use_percent": 17.2}}, "diskio": { "nvme0n1": {"read": 184320, "write": 23863296}, "sda": {"read": 3859, "write": 25954}, }, "gpu": { "NVIDIA GeForce RTX 4080 (GPU 0)": { "mem": 13.333489176233513, "proc": 12, "temperature": 38, "fan_speed": 30, }, "NVIDIA GeForce RTX 3080 (GPU 1)": { "mem": 8.41064453125, "proc": 26, "temperature": 51, "fan_speed": 0, }, }, "containers": { "container1": { "container_cpu_use": 50.9, "container_memory_use": 1068.4, }, "container2": { "container_cpu_use": 26.2, "container_memory_use": 81.2, }, }, } RESPONSE_V4: dict[str, Any] = { "containers": [ { "key": "name", "name": "container1", "id": "1234", "status": "running", "created": "2024-06-07T09:21:57.688106748Z", "command": "./command", "image": ["image1/latest"], "io": {}, "memory": {}, "network": {}, "cpu": {"total": 0.37484029484029485}, "cpu_percent": 0.37484029484029485, "memory_usage": None, "uptime": "28 secs", "engine": "docker", }, { "key": "name", "name": "container2", "id": "5678", "status": "running", "created": "2023-08-23T21:54:50.745112185Z", "command": "./command", "image": ["image2:latest"], "io": {"cumulative_ior": 36413440, "cumulative_iow": 0}, "memory": {}, "network": {"cumulative_rx": 12012442, "cumulative_tx": 45791653}, "cpu": {"total": 0.0}, "cpu_percent": 0.0, "memory_usage": None, "uptime": "3 days", "engine": "docker", }, ], "network": [ { "bytes_sent": 1070106, "bytes_recv": 163781155, "speed": 1048576000, "key": "interface_name", "interface_name": "eth0", "bytes_all": 164851261, "time_since_update": 25.680001497268677, "bytes_recv_gauge": 5939087689, "bytes_recv_rate_per_sec": 6377770.0, "bytes_sent_gauge": 82538934, "bytes_sent_rate_per_sec": 41670.0, "bytes_all_gauge": 6021626623, "bytes_all_rate_per_sec": 6419441.0, }, ], } HA_SENSOR_DATA_V4: dict[str, Any] = { "docker": {"docker_active": 2, "docker_cpu_use": 0.4, "docker_memory_use": 0.0}, "network": { "eth0": {"is_up": None, "rx": 6377770.0, "speed": 1.0, "tx": 41670.0}, }, "containers": { "container1": { "container_cpu_use": 0.4, "container_memory_use": 0.0, }, "container2": { "container_cpu_use": 0.0, "container_memory_use": 0.0, }, }, } @pytest.mark.asyncio async def test_non_existing_endpoint(httpx_mock: HTTPXMock) -> None: """Test a non-exisiting endpoint.""" httpx_mock.add_response(status_code=400) client = Glances() with pytest.raises(GlancesApiNoDataAvailable): await client.get_data("some-data") assert not client.data @pytest.mark.asyncio async def test_plugins_list(httpx_mock: HTTPXMock) -> None: """Test the plugins list response.""" httpx_mock.add_response(json=PLUGINS_LIST_RESPONSE) client = Glances() await client.get_data("pluginslist") assert len(client.plugins) == 10 @pytest.mark.asyncio @pytest.mark.httpx_mock(can_send_already_matched_responses=True) async def test_exisiting_endpoint(httpx_mock: HTTPXMock) -> None: """Test the a valid endpoint.""" httpx_mock.add_response(json=RESPONSE) client = Glances() await client.get_metrics("cpu") assert client.values assert client.values["total"] == 10.6 assert client.values["system"] == 2.1 @pytest.mark.asyncio @pytest.mark.parametrize( ("version", "response", "expected"), [(3, RESPONSE, HA_SENSOR_DATA), (4, RESPONSE_V4, HA_SENSOR_DATA_V4)], ) async def test_ha_sensor_data( httpx_mock: HTTPXMock, version: int, response: dict, expected: dict ) -> None: """Test the return value for ha sensors.""" httpx_mock.add_response(json=response) client = Glances(version=version) result = await client.get_ha_sensor_data() assert result == expected @pytest.mark.asyncio async def test_ha_sensor_data_with_incomplete_container_information( httpx_mock: HTTPXMock, ) -> None: """Test the return value for ha sensors when some data is not exposed.""" response = RESPONSE.copy() del response["containers"]["containers"][0]["memory"]["usage"] del response["containers"]["containers"][0]["cpu"]["total"] del response["containers"]["containers"][1]["memory"]["usage"] del response["containers"]["containers"][1]["cpu"]["total"] ha_sensor_data = HA_SENSOR_DATA.copy() ha_sensor_data["docker"]["docker_memory_use"] = 0 ha_sensor_data["docker"]["docker_cpu_use"] = 0 ha_sensor_data["containers"]["container1"]["container_memory_use"] = 0 ha_sensor_data["containers"]["container1"]["container_cpu_use"] = 0 ha_sensor_data["containers"]["container2"]["container_memory_use"] = 0 ha_sensor_data["containers"]["container2"]["container_cpu_use"] = 0 httpx_mock.add_response(json=response) client = Glances() result = await client.get_ha_sensor_data() assert result == ha_sensor_data python-glances-api-0.9.0/tests/test_timeout.py000066400000000000000000000012511472226337600214760ustar00rootroot00000000000000"""Test the interaction with the currencylayer API.""" import httpx import pytest from pytest_httpx import HTTPXMock from glances_api import Glances, exceptions @pytest.mark.asyncio async def test_timeout(httpx_mock: HTTPXMock) -> None: """Test if the connection is hitting the timeout.""" def raise_timeout(request): """Set the timeout for the requests.""" raise httpx.ReadTimeout( f"Unable to read within {request.extensions['timeout']}", request=request ) httpx_mock.add_callback(raise_timeout) with pytest.raises(exceptions.GlancesApiConnectionError): client = Glances() await client.get_metrics("mem")