pythonkuma 0.0.0rc0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,131 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ pip-wheel-metadata/
24
+ share/python-wheels/
25
+ *.egg-info/
26
+ .installed.cfg
27
+ *.egg
28
+ MANIFEST
29
+
30
+ # PyInstaller
31
+ # Usually these files are written by a python script from a template
32
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
33
+ *.manifest
34
+ *.spec
35
+
36
+ # Installer logs
37
+ pip-log.txt
38
+ pip-delete-this-directory.txt
39
+
40
+ # Unit test / coverage reports
41
+ htmlcov/
42
+ .tox/
43
+ .nox/
44
+ .coverage
45
+ .coverage.*
46
+ .cache
47
+ nosetests.xml
48
+ coverage.xml
49
+ *.cover
50
+ *.py,cover
51
+ .hypothesis/
52
+ .pytest_cache/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ target/
76
+
77
+ # Jupyter Notebook
78
+ .ipynb_checkpoints
79
+
80
+ # IPython
81
+ profile_default/
82
+ ipython_config.py
83
+
84
+ # pyenv
85
+ .python-version
86
+
87
+ # pipenv
88
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
90
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
91
+ # install all needed dependencies.
92
+ #Pipfile.lock
93
+
94
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95
+ __pypackages__/
96
+
97
+ # Celery stuff
98
+ celerybeat-schedule
99
+ celerybeat.pid
100
+
101
+ # SageMath parsed files
102
+ *.sage.py
103
+
104
+ # Environments
105
+ .env
106
+ .venv
107
+ env/
108
+ venv/
109
+ ENV/
110
+ env.bak/
111
+ venv.bak/
112
+
113
+ # Spyder project settings
114
+ .spyderproject
115
+ .spyproject
116
+
117
+ # Rope project settings
118
+ .ropeproject
119
+
120
+ # mkdocs documentation
121
+ /site
122
+
123
+ # mypy
124
+ .mypy_cache/
125
+ .dmypy.json
126
+ dmypy.json
127
+
128
+ # Pyre type checker
129
+ .pyre/
130
+
131
+ test.py
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Bacon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,55 @@
1
+ Metadata-Version: 2.4
2
+ Name: pythonkuma
3
+ Version: 0.0.0rc0
4
+ Summary: Simple Python wrapper for Uptime Kuma
5
+ Project-URL: Source, https://github.com/tr4nt0r/pythonkuma
6
+ Author-email: Manfred Dennerlein Rodelo <manfred@dennerlein.name>, Jayakorn Karikan <jayakornk@gmail.com>
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Programming Language :: Python :: 3
11
+ Requires-Python: >=3.12
12
+ Requires-Dist: aiohttp>=3.12.9
13
+ Requires-Dist: prometheus-client>=0.21.0
14
+ Provides-Extra: dev
15
+ Requires-Dist: ruff==0.11.13; extra == 'dev'
16
+ Description-Content-Type: text/markdown
17
+
18
+ # pythonkuma
19
+ Simple Python wrapper for Uptime Kuma
20
+
21
+ ## Installation
22
+
23
+ ```shell
24
+ pip install pythonkuma
25
+ ```
26
+
27
+ ## Example
28
+
29
+ ```python
30
+ import asyncio
31
+
32
+ import aiohttp
33
+
34
+ from pythonkuma import UptimeKuma
35
+
36
+ URL = ""
37
+ USERNAME = ""
38
+ PASSWORD = ""
39
+
40
+
41
+ async def main():
42
+
43
+ async with aiohttp.ClientSession() as session:
44
+ uptime_kuma = UptimeKuma(session, URL, USERNAME, PASSWORD)
45
+ response = await uptime_kuma.async_get_monitors()
46
+ print(response.data)
47
+
48
+
49
+ asyncio.run(main())
50
+
51
+ ```
52
+
53
+ ## Credit
54
+
55
+ This library is a fork of **pyuptimekuma** by [@jayakornk](https://github.com/jayakornk)
@@ -0,0 +1,38 @@
1
+ # pythonkuma
2
+ Simple Python wrapper for Uptime Kuma
3
+
4
+ ## Installation
5
+
6
+ ```shell
7
+ pip install pythonkuma
8
+ ```
9
+
10
+ ## Example
11
+
12
+ ```python
13
+ import asyncio
14
+
15
+ import aiohttp
16
+
17
+ from pythonkuma import UptimeKuma
18
+
19
+ URL = ""
20
+ USERNAME = ""
21
+ PASSWORD = ""
22
+
23
+
24
+ async def main():
25
+
26
+ async with aiohttp.ClientSession() as session:
27
+ uptime_kuma = UptimeKuma(session, URL, USERNAME, PASSWORD)
28
+ response = await uptime_kuma.async_get_monitors()
29
+ print(response.data)
30
+
31
+
32
+ asyncio.run(main())
33
+
34
+ ```
35
+
36
+ ## Credit
37
+
38
+ This library is a fork of **pyuptimekuma** by [@jayakornk](https://github.com/jayakornk)
@@ -0,0 +1,57 @@
1
+ [build-system]
2
+ requires = ["hatchling", "hatch-regex-commit"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "pythonkuma"
7
+ dynamic = ["version"]
8
+ description = "Simple Python wrapper for Uptime Kuma"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.12"
12
+ authors = [
13
+ { name = "Manfred Dennerlein Rodelo", email = "manfred@dennerlein.name" },
14
+ { name = "Jayakorn Karikan", email = "jayakornk@gmail.com" },
15
+ ]
16
+ classifiers = [
17
+ "Operating System :: OS Independent",
18
+ "Programming Language :: Python :: 3",
19
+ ]
20
+ dependencies = [
21
+ "aiohttp>=3.12.9",
22
+ "prometheus-client>=0.21.0",
23
+ ]
24
+
25
+ [project.optional-dependencies]
26
+ dev = [
27
+ "ruff==0.11.13",
28
+ ]
29
+
30
+ [project.urls]
31
+ Source = "https://github.com/tr4nt0r/pythonkuma"
32
+
33
+ [tool.hatch.version]
34
+ source = "regex_commit"
35
+ commit_extra_args = ["-e"]
36
+ path = "pythonkuma/__init__.py"
37
+
38
+ [tool.hatch.build.targets.sdist]
39
+ include = [
40
+ "/pythonkuma",
41
+ ]
42
+
43
+ [tool.hatch.envs.hatch-static-analysis]
44
+ dependencies = ["ruff==0.11.13"]
45
+ config-path = "ruff.toml"
46
+
47
+ [tool.pytest.ini_options]
48
+ addopts = "--cov=pythonkuma/ --cov-report=term-missing"
49
+ asyncio_mode = "auto"
50
+ asyncio_default_fixture_loop_scope="module"
51
+ testpaths = ["tests"]
52
+ pythonpath = ["pythonkuma"]
53
+
54
+ [tool.hatch.envs.hatch-test]
55
+ extra-dependencies = [
56
+ "pytest-cov"
57
+ ]
@@ -0,0 +1,21 @@
1
+ """Python API wrapper for Uptime Kuma."""
2
+
3
+ from .exceptions import (
4
+ UptimeKumaAuthenticationException,
5
+ UptimeKumaConnectionException,
6
+ UptimeKumaException,
7
+ )
8
+ from .models import MonitorType, UptimeKumaApiResponse, UptimeKumaMonitor
9
+ from .uptimekuma import UptimeKuma
10
+
11
+ __version__ = "0.0.0rc0"
12
+
13
+ __all__ = [
14
+ "MonitorType",
15
+ "UptimeKuma",
16
+ "UptimeKumaApiResponse",
17
+ "UptimeKumaAuthenticationException",
18
+ "UptimeKumaConnectionException",
19
+ "UptimeKumaException",
20
+ "UptimeKumaMonitor",
21
+ ]
@@ -0,0 +1,5 @@
1
+ """Uptime Kuma constants."""
2
+
3
+ from logging import Logger, getLogger
4
+
5
+ LOGGER: Logger = getLogger(__package__)
@@ -0,0 +1,71 @@
1
+ """Decorator for Uptime Kuma"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ import aiohttp
8
+
9
+ from . import exceptions
10
+ from .const import LOGGER
11
+ from .models import UptimeKumaApiResponse
12
+
13
+ if TYPE_CHECKING:
14
+ from .uptimekuma import UptimeKuma
15
+
16
+
17
+ def api_request(api_path: str, method: str = "GET"):
18
+ """Decorator for Uptime Kuma API request"""
19
+
20
+ def decorator(func):
21
+ """Decorator"""
22
+
23
+ async def wrapper(*args, **kwargs):
24
+ """Wrapper"""
25
+ client: UptimeKuma = args[0]
26
+ url = f"{client._base_url}{api_path}"
27
+ LOGGER.debug("Requesting %s", url)
28
+ try:
29
+ request = await client._session.request(
30
+ method=method,
31
+ url=url,
32
+ timeout=aiohttp.ClientTimeout(total=10),
33
+ auth=aiohttp.BasicAuth(client._username, client._password),
34
+ )
35
+
36
+ if request.status != 200:
37
+ raise exceptions.UptimeKumaConnectionException(
38
+ f"Request for '{url}' failed with status code '{request.status}'"
39
+ )
40
+
41
+ result = await request.text()
42
+ except aiohttp.ClientError as exception:
43
+ raise exceptions.UptimeKumaConnectionException(
44
+ f"Request exception for '{url}' with - {exception}"
45
+ ) from exception
46
+
47
+ except TimeoutError:
48
+ raise exceptions.UptimeKumaConnectionException(f"Request timeout for '{url}'") from None
49
+
50
+ except exceptions.UptimeKumaConnectionException as exception:
51
+ raise exceptions.UptimeKumaConnectionException(exception) from exception
52
+
53
+ except exceptions.UptimeKumaException as exception:
54
+ raise exceptions.UptimeKumaException(exception) from exception
55
+
56
+ except (Exception, BaseException) as exception:
57
+ raise exceptions.UptimeKumaException(
58
+ f"Unexpected exception for '{url}' with - {exception}"
59
+ ) from exception
60
+
61
+ LOGGER.debug("Requesting %s returned %s", url, result)
62
+
63
+ response = UptimeKumaApiResponse.from_prometheus(
64
+ {"monitors": result, "_api_path": api_path, "_method": method}
65
+ )
66
+
67
+ return response
68
+
69
+ return wrapper
70
+
71
+ return decorator
@@ -0,0 +1,13 @@
1
+ """Uptime Kuma exceptions."""
2
+
3
+
4
+ class UptimeKumaException(Exception):
5
+ """Base Uptime Kuma exception."""
6
+
7
+
8
+ class UptimeKumaConnectionException(UptimeKumaException):
9
+ """Uptime Kuma connection exception."""
10
+
11
+
12
+ class UptimeKumaAuthenticationException(UptimeKumaException):
13
+ """Uptime Kuma authentication exception."""
@@ -0,0 +1,101 @@
1
+ """Uptime Kuma models"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from enum import StrEnum
7
+ from typing import Any
8
+
9
+ from prometheus_client.parser import text_string_to_metric_families as parser
10
+
11
+
12
+ class MonitorType(StrEnum):
13
+ """Monitors type."""
14
+
15
+ HTTP = "http"
16
+ PORT = "port"
17
+ PING = "ping"
18
+ KEYWORD = "keyword"
19
+ DNS = "dns"
20
+ PUSH = "push"
21
+ STEAM = "steam"
22
+ MQTT = "mqtt"
23
+ SQL = "sqlserver"
24
+ JSON_QUERY = "json-query"
25
+ GROUP = "group"
26
+ DOCKER = "docker"
27
+ GRPC_KEYWORD = "grpc-keyword"
28
+ REAL_BROWSER = "real-browser"
29
+ GAMEDIG = "gamedig"
30
+ KAFKA_PRODUCER = "kafka-producer"
31
+ POSTGRES = "postgres"
32
+ MYSQL = "mysql"
33
+ MONGODB = "mongodb"
34
+ RADIUS = "radius"
35
+ REDIS = "redis"
36
+ TAILSCALE_PING = "tailscale-ping"
37
+
38
+
39
+ class UptimeKumaBaseModel:
40
+ """UptimeKumaBaseModel."""
41
+
42
+
43
+ @dataclass
44
+ class UptimeKumaMonitor(UptimeKumaBaseModel):
45
+ """Monitor model for Uptime Kuma."""
46
+
47
+ monitor_cert_days_remaining: float = 0
48
+ monitor_cert_is_valid: float = 0
49
+ monitor_hostname: str = ""
50
+ monitor_name: str = ""
51
+ monitor_port: str = ""
52
+ monitor_response_time: float = 0
53
+ monitor_status: float = 0
54
+ monitor_type: MonitorType = MonitorType.HTTP
55
+ monitor_url: str = ""
56
+
57
+ @staticmethod
58
+ def from_dict(data: dict[str, Any]) -> UptimeKumaMonitor:
59
+ """Generate object from json."""
60
+ obj: dict[str, Any] = {}
61
+ for key, value in data.items():
62
+ if hasattr(UptimeKumaMonitor, key):
63
+ obj[key] = MonitorType(value) if key == "monitor_type" else value
64
+
65
+ return UptimeKumaMonitor(**obj)
66
+
67
+
68
+ @dataclass
69
+ class UptimeKumaApiResponse(UptimeKumaBaseModel):
70
+ """API response model for Uptime Kuma."""
71
+
72
+ _method: str | None = None
73
+ _api_path: str | None = None
74
+ data: list[UptimeKumaMonitor] | None = None
75
+
76
+ @staticmethod
77
+ def from_prometheus(data: dict[str, Any]) -> UptimeKumaApiResponse:
78
+ """Generate object from json."""
79
+ obj: dict[str, Any] = {}
80
+ monitors = []
81
+
82
+ for key, value in data.items():
83
+ if hasattr(UptimeKumaApiResponse, key):
84
+ obj[key] = value
85
+
86
+ parsed = parser(data["monitors"])
87
+ for family in parsed:
88
+ for sample in family.samples:
89
+ if sample.name.startswith("monitor"):
90
+ existed = next(
91
+ (i for i, x in enumerate(monitors) if x["monitor_name"] == sample.labels["monitor_name"]),
92
+ None,
93
+ )
94
+ if existed is None:
95
+ temp = {**sample.labels, sample.name: sample.value}
96
+ monitors.append(temp)
97
+ else:
98
+ monitors[existed][sample.name] = sample.value
99
+ obj["data"] = [UptimeKumaMonitor.from_dict(monitor) for monitor in monitors]
100
+
101
+ return UptimeKumaApiResponse(**obj)
File without changes
@@ -0,0 +1,22 @@
1
+ """Uptime Kuma client."""
2
+
3
+ from aiohttp import ClientSession
4
+
5
+ from .decorator import api_request
6
+ from .models import UptimeKumaApiResponse
7
+
8
+
9
+ class UptimeKuma:
10
+ """This class is used to get information from Uptime Kuma."""
11
+
12
+ def __init__(self, session: ClientSession, base_url: str, username: str, password: str) -> None:
13
+ """Initialize"""
14
+ self.monitors = []
15
+ self._base_url = base_url
16
+ self._username = username
17
+ self._password = password
18
+ self._session: ClientSession = session
19
+
20
+ @api_request("/metrics")
21
+ async def async_get_monitors(self, **kwargs) -> UptimeKumaApiResponse:
22
+ """Get monitors from API."""