pihole6api 0.1.2__py3-none-any.whl → 0.1.4__py3-none-any.whl
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.
- pihole6api/conn.py +36 -13
- pihole6api/ftl_info.py +25 -9
- pihole6api/list_management.py +14 -3
- pihole6api/network_info.py +35 -12
- {pihole6api-0.1.2.dist-info → pihole6api-0.1.4.dist-info}/METADATA +2 -3
- {pihole6api-0.1.2.dist-info → pihole6api-0.1.4.dist-info}/RECORD +9 -9
- {pihole6api-0.1.2.dist-info → pihole6api-0.1.4.dist-info}/LICENSE +0 -0
- {pihole6api-0.1.2.dist-info → pihole6api-0.1.4.dist-info}/WHEEL +0 -0
- {pihole6api-0.1.2.dist-info → pihole6api-0.1.4.dist-info}/top_level.txt +0 -0
pihole6api/conn.py
CHANGED
@@ -2,6 +2,8 @@ import requests
|
|
2
2
|
import urllib3
|
3
3
|
from urllib.parse import urljoin
|
4
4
|
import warnings
|
5
|
+
import time
|
6
|
+
import json
|
5
7
|
|
6
8
|
# Suppress InsecureRequestWarning
|
7
9
|
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
@@ -25,22 +27,43 @@ class PiHole6Connection:
|
|
25
27
|
self._authenticate()
|
26
28
|
|
27
29
|
def _authenticate(self):
|
28
|
-
"""Authenticate with the Pi-hole API and store session ID and CSRF token.
|
30
|
+
"""Authenticate with the Pi-hole API and store session ID and CSRF token.
|
31
|
+
|
32
|
+
Retries up to three times (with a one-second pause between attempts)
|
33
|
+
before raising an exception.
|
34
|
+
"""
|
29
35
|
auth_url = urljoin(self.base_url, "auth")
|
30
36
|
payload = {"password": self.password}
|
37
|
+
max_attempts = 3
|
38
|
+
last_exception = None
|
31
39
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
for attempt in range(1, max_attempts + 1):
|
41
|
+
response = requests.post(auth_url, json=payload, verify=False)
|
42
|
+
try:
|
43
|
+
if response.status_code == 200:
|
44
|
+
data = response.json()
|
45
|
+
if "session" in data and data["session"]["valid"]:
|
46
|
+
self.session_id = data["session"]["sid"]
|
47
|
+
self.csrf_token = data["session"]["csrf"]
|
48
|
+
self.validity = data["session"]["validity"]
|
49
|
+
return # Successful authentication
|
50
|
+
else:
|
51
|
+
last_exception = Exception("Authentication failed: Invalid session response")
|
52
|
+
else:
|
53
|
+
# Try to extract an error message from the response
|
54
|
+
try:
|
55
|
+
error_msg = response.json().get("error", {}).get("message", "Unknown error")
|
56
|
+
except (json.decoder.JSONDecodeError, ValueError):
|
57
|
+
error_msg = f"HTTP {response.status_code}: {response.reason}"
|
58
|
+
last_exception = Exception(f"Authentication failed: {error_msg}")
|
59
|
+
except Exception as e:
|
60
|
+
last_exception = e
|
61
|
+
|
62
|
+
if attempt < max_attempts:
|
63
|
+
time.sleep(1) # Pause before retrying
|
64
|
+
|
65
|
+
# All attempts failed; raise the last captured exception.
|
66
|
+
raise last_exception
|
44
67
|
|
45
68
|
def _get_headers(self):
|
46
69
|
"""Return headers including the authentication SID and CSRF token."""
|
pihole6api/ftl_info.py
CHANGED
@@ -62,14 +62,30 @@ class PiHole6FtlInfo:
|
|
62
62
|
"""Retrieve Pi-hole version details."""
|
63
63
|
return self.connection.get("info/version")
|
64
64
|
|
65
|
-
def get_dnsmasq_logs(self):
|
66
|
-
"""
|
67
|
-
|
65
|
+
def get_dnsmasq_logs(self, next_id=None):
|
66
|
+
"""
|
67
|
+
Retrieve DNS log content from the embedded DNS resolver (dnsmasq).
|
68
|
+
|
69
|
+
:param next_id: Optional ID to fetch only new log lines since the last request.
|
70
|
+
"""
|
71
|
+
params = {"nextID": next_id} if next_id is not None else {}
|
72
|
+
return self.connection.get("logs/dnsmasq", params=params)
|
73
|
+
|
68
74
|
|
69
|
-
def get_ftl_logs(self):
|
70
|
-
"""
|
71
|
-
|
75
|
+
def get_ftl_logs(self, next_id=None):
|
76
|
+
"""
|
77
|
+
Retrieve FTL log content.
|
78
|
+
|
79
|
+
:param next_id: Optional ID to fetch only new log lines since the last request.
|
80
|
+
"""
|
81
|
+
params = {"nextID": next_id} if next_id is not None else {}
|
82
|
+
return self.connection.get("logs/ftl", params=params)
|
72
83
|
|
73
|
-
def get_webserver_logs(self):
|
74
|
-
"""
|
75
|
-
|
84
|
+
def get_webserver_logs(self, next_id=None):
|
85
|
+
"""
|
86
|
+
Retrieve webserver log content.
|
87
|
+
|
88
|
+
:param next_id: Optional ID to fetch only new log lines since the last request.
|
89
|
+
"""
|
90
|
+
params = {"nextID": next_id} if next_id is not None else {}
|
91
|
+
return self.connection.get("logs/webserver", params=params)
|
pihole6api/list_management.py
CHANGED
@@ -52,7 +52,7 @@ class PiHole6ListManagement:
|
|
52
52
|
"""
|
53
53
|
encoded_address = urllib.parse.quote(address, safe="")
|
54
54
|
params = {"type": list_type}
|
55
|
-
return self.connection.get(f"lists/{encoded_address}")
|
55
|
+
return self.connection.get(f"lists/{encoded_address}", params=params)
|
56
56
|
|
57
57
|
def update_list(self, address, list_type=None, comment=None, groups=None, enabled=True):
|
58
58
|
"""
|
@@ -85,10 +85,21 @@ class PiHole6ListManagement:
|
|
85
85
|
params = {"type": list_type}
|
86
86
|
return self.connection.delete(f"lists/{encoded_address}", params=params)
|
87
87
|
|
88
|
-
def search_list(self, domain):
|
88
|
+
def search_list(self, domain, num=None, partial=False, debug=False):
|
89
89
|
"""
|
90
90
|
Search for a domain in Pi-hole's lists.
|
91
91
|
|
92
92
|
:param domain: Domain to search for.
|
93
|
+
:param num: Maximum number of results to be returned (optional).
|
94
|
+
:param partial: Boolean flag to enable partial matching (optional).
|
95
|
+
:param debug: Boolean flag to add debug information to the response (optional).
|
93
96
|
"""
|
94
|
-
|
97
|
+
params = {
|
98
|
+
"partial": str(partial).lower(),
|
99
|
+
"debug": str(debug).lower(),
|
100
|
+
}
|
101
|
+
if num is not None:
|
102
|
+
params["n"] = num
|
103
|
+
|
104
|
+
return self.connection.get(f"search/{domain}", params=params)
|
105
|
+
|
pihole6api/network_info.py
CHANGED
@@ -3,9 +3,20 @@ class PiHole6NetworkInfo:
|
|
3
3
|
"""Handles Pi-hole network information API endpoints."""
|
4
4
|
self.connection = connection
|
5
5
|
|
6
|
-
def get_devices(self):
|
7
|
-
"""
|
8
|
-
|
6
|
+
def get_devices(self, max_devices=None, max_addresses=None):
|
7
|
+
"""
|
8
|
+
Get information about devices on the local network.
|
9
|
+
|
10
|
+
:param max_devices: Optional maximum number of devices to show.
|
11
|
+
:param max_addresses: Optional maximum number of addresses to show.
|
12
|
+
"""
|
13
|
+
params = {}
|
14
|
+
if max_devices is not None:
|
15
|
+
params["max_devices"] = max_devices
|
16
|
+
if max_addresses is not None:
|
17
|
+
params["max_addresses"] = max_addresses
|
18
|
+
|
19
|
+
return self.connection.get("network/devices", params=params)
|
9
20
|
|
10
21
|
def delete_device(self, device_id):
|
11
22
|
"""
|
@@ -15,14 +26,26 @@ class PiHole6NetworkInfo:
|
|
15
26
|
"""
|
16
27
|
return self.connection.delete(f"network/devices/{device_id}")
|
17
28
|
|
18
|
-
def get_gateway(self):
|
19
|
-
"""
|
20
|
-
|
29
|
+
def get_gateway(self, detailed=False):
|
30
|
+
"""
|
31
|
+
Get information about the gateway of the Pi-hole.
|
21
32
|
|
22
|
-
|
23
|
-
"""
|
24
|
-
return self.connection.get("network/
|
33
|
+
:param detailed: Boolean flag to request detailed interface/routing information (default: False).
|
34
|
+
"""
|
35
|
+
return self.connection.get("network/gateway", params={"detailed": detailed})
|
25
36
|
|
26
|
-
def
|
27
|
-
"""
|
28
|
-
|
37
|
+
def get_interfaces(self, detailed=False):
|
38
|
+
"""
|
39
|
+
Get information about network interfaces of the Pi-hole.
|
40
|
+
|
41
|
+
:param detailed: Boolean flag to request detailed interface/routing information (default: False).
|
42
|
+
"""
|
43
|
+
return self.connection.get("network/interfaces", params={"detailed": detailed})
|
44
|
+
|
45
|
+
def get_routes(self, detailed=False):
|
46
|
+
"""
|
47
|
+
Get information about network routes of the Pi-hole.
|
48
|
+
|
49
|
+
:param detailed: Boolean flag to request detailed interface/routing information (default: False).
|
50
|
+
"""
|
51
|
+
return self.connection.get("network/routes", params={"detailed": detailed})
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: pihole6api
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.4
|
4
4
|
Summary: Python API Client for Pi-hole 6
|
5
5
|
Author-email: Shane Barbetta <shane@barbetta.me>
|
6
6
|
License: MIT
|
@@ -30,7 +30,7 @@ This package provides a simple, modular SDK for the PiHole 6 REST API.
|
|
30
30
|
## Features
|
31
31
|
|
32
32
|
* Automatically handles authentication and renewal
|
33
|
-
*
|
33
|
+
* Graceful error management
|
34
34
|
* Logically organized modules
|
35
35
|
* Easily maintained
|
36
36
|
|
@@ -130,7 +130,6 @@ client.actions.restart_dns()
|
|
130
130
|
| `dhcp` | Manage DHCP leases |
|
131
131
|
| `network_info` | View network devices, interfaces, routes |
|
132
132
|
| `actions` | Flush logs, restart services |
|
133
|
-
| `padd` | Fetch summarized data for PADD |
|
134
133
|
|
135
134
|
## License
|
136
135
|
|
@@ -3,17 +3,17 @@ pihole6api/actions.py,sha256=8CBkr8nYfT8yfdCO6F9M9nompaYcFdsaYGiEa1eVDCw,693
|
|
3
3
|
pihole6api/client.py,sha256=HYdRh3CSZJ0srbkpjIVnLo-iy1avqKDUne5ji2Aq394,2013
|
4
4
|
pihole6api/client_management.py,sha256=opPYGrjuW6SiwuxuvoOxnqjpmflU2znKHsqFbGSS3Gg,2439
|
5
5
|
pihole6api/config.py,sha256=NdBHOudz147oIs5YVR3U4WLvqk3hU3HlZHnshy1NK4g,4680
|
6
|
-
pihole6api/conn.py,sha256=
|
6
|
+
pihole6api/conn.py,sha256=60Q9paDCD6Bwmdg_G9mOUr86Hzj9G-dhMwL7F3NvLB8,5837
|
7
7
|
pihole6api/dhcp.py,sha256=1A3z-3q9x51-6MOC3JMl7yR_5pHmRxZtMWtPqzWxYm0,629
|
8
8
|
pihole6api/dns_control.py,sha256=mxV3AIuGCsx0-1ibpMXor9QUGd_fDFfeaUENPhIK_TY,853
|
9
9
|
pihole6api/domain_management.py,sha256=vxhQSG5F8EFDGqtiNkF0H_KOWFMerXaAuJZT0nMa8ec,3492
|
10
|
-
pihole6api/ftl_info.py,sha256=
|
10
|
+
pihole6api/ftl_info.py,sha256=FINHFotI1sQgkL0OPaNqW-rk4h1ua6QHnRh5gFXXRIE,3210
|
11
11
|
pihole6api/group_management.py,sha256=MGHwegw-b9U9PIA-IBzqT-a1kYkpXyjfSXJJJjkyTxc,2225
|
12
|
-
pihole6api/list_management.py,sha256=
|
12
|
+
pihole6api/list_management.py,sha256=52cCe3lEAvHYkyBOYdxkOn7C2I39fBUNsMpNC_rGiCI,3876
|
13
13
|
pihole6api/metrics.py,sha256=czNyx9tUf2yZi_HnUpqykrtW51c042Rxq3zFl2_GjLY,7379
|
14
|
-
pihole6api/network_info.py,sha256=
|
15
|
-
pihole6api-0.1.
|
16
|
-
pihole6api-0.1.
|
17
|
-
pihole6api-0.1.
|
18
|
-
pihole6api-0.1.
|
19
|
-
pihole6api-0.1.
|
14
|
+
pihole6api/network_info.py,sha256=E1qQ7DsCb7qplt0oQIyKhUY12ExNF6bv6thm9rbNqwY,1953
|
15
|
+
pihole6api-0.1.4.dist-info/LICENSE,sha256=hpO6J6J9O1VZxZeHQTxKMTmuobaHbApiZxp279I4xNU,1062
|
16
|
+
pihole6api-0.1.4.dist-info/METADATA,sha256=F7_jh48dzzmrzazbdrvsBhh4_zdN6BhDhJasq7KH1lM,3778
|
17
|
+
pihole6api-0.1.4.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
18
|
+
pihole6api-0.1.4.dist-info/top_level.txt,sha256=Qrh46lxEC54rBR8T53em-tuZLWbmi1SDwL1rOhsgrME,11
|
19
|
+
pihole6api-0.1.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|