ipspot 0.6__py3-none-any.whl → 0.7__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.
- ipspot/cli.py +24 -15
- ipspot/ipv4.py +31 -26
- ipspot/ipv6.py +24 -19
- ipspot/params.py +6 -1
- ipspot/utils.py +7 -2
- {ipspot-0.6.dist-info → ipspot-0.7.dist-info}/METADATA +30 -17
- ipspot-0.7.dist-info/RECORD +14 -0
- ipspot-0.6.dist-info/RECORD +0 -14
- {ipspot-0.6.dist-info → ipspot-0.7.dist-info}/WHEEL +0 -0
- {ipspot-0.6.dist-info → ipspot-0.7.dist-info}/entry_points.txt +0 -0
- {ipspot-0.6.dist-info → ipspot-0.7.dist-info}/licenses/AUTHORS.md +0 -0
- {ipspot-0.6.dist-info → ipspot-0.7.dist-info}/licenses/LICENSE +0 -0
- {ipspot-0.6.dist-info → ipspot-0.7.dist-info}/top_level.txt +0 -0
ipspot/cli.py
CHANGED
|
@@ -8,9 +8,11 @@ from .ipv6 import get_public_ipv6, get_private_ipv6
|
|
|
8
8
|
from .utils import _filter_parameter
|
|
9
9
|
from .params import IPv4API, IPv6API, PARAMETERS_NAME_MAP
|
|
10
10
|
from .params import IPSPOT_OVERVIEW, IPSPOT_REPO, IPSPOT_VERSION
|
|
11
|
+
from .params import PUBLIC_IPV4_ERROR, PRIVATE_IPV4_ERROR
|
|
12
|
+
from .params import PUBLIC_IPV6_ERROR, PRIVATE_IPV6_ERROR
|
|
11
13
|
|
|
12
14
|
|
|
13
|
-
def
|
|
15
|
+
def _print_ipspot_info() -> None: # pragma: no cover
|
|
14
16
|
"""Print ipspot details."""
|
|
15
17
|
tprint("IPSpot")
|
|
16
18
|
tprint("V:" + IPSPOT_VERSION)
|
|
@@ -18,11 +20,13 @@ def ipspot_info() -> None: # pragma: no cover
|
|
|
18
20
|
print("Repo : " + IPSPOT_REPO)
|
|
19
21
|
|
|
20
22
|
|
|
21
|
-
def
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
def _print_report(ipv4_api: IPv4API,
|
|
24
|
+
ipv6_api: IPv6API,
|
|
25
|
+
geo: bool,
|
|
26
|
+
timeout: Union[float, Tuple[float, float]],
|
|
27
|
+
max_retries: int,
|
|
28
|
+
retry_delay: float,
|
|
29
|
+
backoff_factor: float) -> None: # pragma: no cover
|
|
26
30
|
"""
|
|
27
31
|
Print collected IP and location data.
|
|
28
32
|
|
|
@@ -32,20 +36,21 @@ def display_ip_info(ipv4_api: IPv4API = IPv4API.AUTO_SAFE,
|
|
|
32
36
|
:param timeout: timeout value for API
|
|
33
37
|
:param max_retries: number of retries
|
|
34
38
|
:param retry_delay: delay between retries (in seconds)
|
|
39
|
+
:param backoff_factor: backoff factor
|
|
35
40
|
"""
|
|
36
41
|
print("Private IP:\n")
|
|
37
42
|
private_ipv4_result = get_private_ipv4()
|
|
38
43
|
if private_ipv4_result["status"]:
|
|
39
44
|
private_ipv4 = private_ipv4_result["data"]["ip"]
|
|
40
45
|
else:
|
|
41
|
-
private_ipv4 =
|
|
46
|
+
private_ipv4 = PRIVATE_IPV4_ERROR
|
|
42
47
|
print(" IPv4: {private_ipv4}\n".format(private_ipv4=private_ipv4))
|
|
43
48
|
|
|
44
49
|
private_ipv6_result = get_private_ipv6()
|
|
45
50
|
if private_ipv6_result["status"]:
|
|
46
51
|
private_ipv6 = private_ipv6_result["data"]["ip"]
|
|
47
52
|
else:
|
|
48
|
-
private_ipv6 =
|
|
53
|
+
private_ipv6 = PRIVATE_IPV6_ERROR
|
|
49
54
|
print(" IPv6: {private_ipv6}".format(private_ipv6=private_ipv6))
|
|
50
55
|
|
|
51
56
|
public_title = "\nPublic IP"
|
|
@@ -59,7 +64,8 @@ def display_ip_info(ipv4_api: IPv4API = IPv4API.AUTO_SAFE,
|
|
|
59
64
|
geo=geo,
|
|
60
65
|
timeout=timeout,
|
|
61
66
|
max_retries=max_retries,
|
|
62
|
-
retry_delay=retry_delay
|
|
67
|
+
retry_delay=retry_delay,
|
|
68
|
+
backoff_factor=backoff_factor)
|
|
63
69
|
if public_ipv4_result["status"]:
|
|
64
70
|
for name, parameter in sorted(public_ipv4_result["data"].items()):
|
|
65
71
|
print(
|
|
@@ -67,7 +73,7 @@ def display_ip_info(ipv4_api: IPv4API = IPv4API.AUTO_SAFE,
|
|
|
67
73
|
name=PARAMETERS_NAME_MAP[name],
|
|
68
74
|
parameter=_filter_parameter(parameter)))
|
|
69
75
|
else:
|
|
70
|
-
print(" Error: {public_ipv4_result
|
|
76
|
+
print(" Error: {public_ipv4_result}".format(public_ipv4_result=PUBLIC_IPV4_ERROR))
|
|
71
77
|
|
|
72
78
|
print("\n IPv6:\n")
|
|
73
79
|
public_ipv6_result = get_public_ipv6(
|
|
@@ -75,7 +81,8 @@ def display_ip_info(ipv4_api: IPv4API = IPv4API.AUTO_SAFE,
|
|
|
75
81
|
geo=geo,
|
|
76
82
|
timeout=timeout,
|
|
77
83
|
max_retries=max_retries,
|
|
78
|
-
retry_delay=retry_delay
|
|
84
|
+
retry_delay=retry_delay,
|
|
85
|
+
backoff_factor=backoff_factor)
|
|
79
86
|
if public_ipv6_result["status"]:
|
|
80
87
|
for name, parameter in sorted(public_ipv6_result["data"].items()):
|
|
81
88
|
print(
|
|
@@ -83,7 +90,7 @@ def display_ip_info(ipv4_api: IPv4API = IPv4API.AUTO_SAFE,
|
|
|
83
90
|
name=PARAMETERS_NAME_MAP[name],
|
|
84
91
|
parameter=_filter_parameter(parameter)))
|
|
85
92
|
else:
|
|
86
|
-
print(" Error: {public_ipv6_result
|
|
93
|
+
print(" Error: {public_ipv6_result}".format(public_ipv6_result=PUBLIC_IPV6_ERROR))
|
|
87
94
|
|
|
88
95
|
|
|
89
96
|
def main() -> None: # pragma: no cover
|
|
@@ -109,20 +116,22 @@ def main() -> None: # pragma: no cover
|
|
|
109
116
|
parser.add_argument('--timeout', help='timeout for the API request', type=float, default=5.0)
|
|
110
117
|
parser.add_argument('--max-retries', help='number of retries', type=int, default=0)
|
|
111
118
|
parser.add_argument('--retry-delay', help='delay between retries (in seconds)', type=float, default=1.0)
|
|
119
|
+
parser.add_argument('--backoff-factor', help='backoff factor', type=float, default=1.0)
|
|
112
120
|
|
|
113
121
|
args = parser.parse_args()
|
|
114
122
|
if args.version:
|
|
115
123
|
print(IPSPOT_VERSION)
|
|
116
124
|
elif args.info:
|
|
117
|
-
|
|
125
|
+
_print_ipspot_info()
|
|
118
126
|
else:
|
|
119
127
|
ipv4_api = IPv4API(args.ipv4_api)
|
|
120
128
|
ipv6_api = IPv6API(args.ipv6_api)
|
|
121
129
|
geo = not args.no_geo
|
|
122
|
-
|
|
130
|
+
_print_report(
|
|
123
131
|
ipv4_api=ipv4_api,
|
|
124
132
|
ipv6_api=ipv6_api,
|
|
125
133
|
geo=geo,
|
|
126
134
|
timeout=args.timeout,
|
|
127
135
|
max_retries=args.max_retries,
|
|
128
|
-
retry_delay=args.retry_delay
|
|
136
|
+
retry_delay=args.retry_delay,
|
|
137
|
+
backoff_factor=args.backoff_factor)
|
ipspot/ipv4.py
CHANGED
|
@@ -36,8 +36,8 @@ def get_private_ipv4() -> Dict[str, Union[bool, Dict[str, str], str]]:
|
|
|
36
36
|
return {"status": False, "error": str(e)}
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
def _ip_sb_ipv4(geo: bool
|
|
40
|
-
|
|
39
|
+
def _ip_sb_ipv4(geo: bool, timeout: Union[float, Tuple[float, float]]
|
|
40
|
+
) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
41
41
|
"""
|
|
42
42
|
Get public IP and geolocation using ip.sb.
|
|
43
43
|
|
|
@@ -64,8 +64,8 @@ def _ip_sb_ipv4(geo: bool=False, timeout: Union[float, Tuple[float, float]]
|
|
|
64
64
|
return {"status": False, "error": str(e)}
|
|
65
65
|
|
|
66
66
|
|
|
67
|
-
def _ipleak_net_ipv4(geo: bool
|
|
68
|
-
|
|
67
|
+
def _ipleak_net_ipv4(geo: bool, timeout: Union[float, Tuple[float, float]]
|
|
68
|
+
) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
69
69
|
"""
|
|
70
70
|
Get public IP and geolocation using ipleak.net.
|
|
71
71
|
|
|
@@ -92,8 +92,8 @@ def _ipleak_net_ipv4(geo: bool=False, timeout: Union[float, Tuple[float, float]]
|
|
|
92
92
|
return {"status": False, "error": str(e)}
|
|
93
93
|
|
|
94
94
|
|
|
95
|
-
def _my_ip_io_ipv4(geo: bool
|
|
96
|
-
|
|
95
|
+
def _my_ip_io_ipv4(geo: bool, timeout: Union[float, Tuple[float, float]]
|
|
96
|
+
) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
97
97
|
"""
|
|
98
98
|
Get public IP and geolocation using my-ip.io.
|
|
99
99
|
|
|
@@ -120,8 +120,9 @@ def _my_ip_io_ipv4(geo: bool=False, timeout: Union[float, Tuple[float, float]]
|
|
|
120
120
|
return {"status": False, "error": str(e)}
|
|
121
121
|
|
|
122
122
|
|
|
123
|
-
|
|
124
|
-
|
|
123
|
+
# very low rate limit
|
|
124
|
+
def _ifconfig_co_ipv4(geo: bool, timeout: Union[float, Tuple[float, float]]
|
|
125
|
+
) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
125
126
|
"""
|
|
126
127
|
Get public IP and geolocation using ifconfig.co.
|
|
127
128
|
|
|
@@ -148,8 +149,8 @@ def _ifconfig_co_ipv4(geo: bool=False, timeout: Union[float, Tuple[float, float]
|
|
|
148
149
|
return {"status": False, "error": str(e)}
|
|
149
150
|
|
|
150
151
|
|
|
151
|
-
def _ipapi_co_ipv4(geo: bool
|
|
152
|
-
|
|
152
|
+
def _ipapi_co_ipv4(geo: bool, timeout: Union[float, Tuple[float, float]]
|
|
153
|
+
) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
153
154
|
"""
|
|
154
155
|
Get public IP and geolocation using ipapi.co.
|
|
155
156
|
|
|
@@ -176,8 +177,8 @@ def _ipapi_co_ipv4(geo: bool=False, timeout: Union[float, Tuple[float, float]]
|
|
|
176
177
|
return {"status": False, "error": str(e)}
|
|
177
178
|
|
|
178
179
|
|
|
179
|
-
def _ip_api_com_ipv4(geo: bool
|
|
180
|
-
|
|
180
|
+
def _ip_api_com_ipv4(geo: bool, timeout: Union[float, Tuple[float, float]]
|
|
181
|
+
) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
181
182
|
"""
|
|
182
183
|
Get public IP and geolocation using ip-api.com.
|
|
183
184
|
|
|
@@ -206,8 +207,8 @@ def _ip_api_com_ipv4(geo: bool=False, timeout: Union[float, Tuple[float, float]]
|
|
|
206
207
|
return {"status": False, "error": str(e)}
|
|
207
208
|
|
|
208
209
|
|
|
209
|
-
def _ipinfo_io_ipv4(geo: bool
|
|
210
|
-
|
|
210
|
+
def _ipinfo_io_ipv4(geo: bool, timeout: Union[float, Tuple[float, float]]
|
|
211
|
+
) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
211
212
|
"""
|
|
212
213
|
Get public IP and geolocation using ipinfo.io.
|
|
213
214
|
|
|
@@ -235,8 +236,8 @@ def _ipinfo_io_ipv4(geo: bool=False, timeout: Union[float, Tuple[float, float]]
|
|
|
235
236
|
return {"status": False, "error": str(e)}
|
|
236
237
|
|
|
237
238
|
|
|
238
|
-
def _reallyfreegeoip_org_ipv4(
|
|
239
|
-
|
|
239
|
+
def _reallyfreegeoip_org_ipv4(
|
|
240
|
+
geo: bool, timeout: Union[float, Tuple[float, float]]) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
240
241
|
"""
|
|
241
242
|
Get public IP and geolocation using reallyfreegeoip.org.
|
|
242
243
|
|
|
@@ -263,8 +264,8 @@ def _reallyfreegeoip_org_ipv4(geo: bool=False, timeout: Union[float, Tuple[float
|
|
|
263
264
|
return {"status": False, "error": str(e)}
|
|
264
265
|
|
|
265
266
|
|
|
266
|
-
def _ident_me_ipv4(geo: bool
|
|
267
|
-
|
|
267
|
+
def _ident_me_ipv4(geo: bool, timeout: Union[float, Tuple[float, float]]
|
|
268
|
+
) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
268
269
|
"""
|
|
269
270
|
Get public IP and geolocation using ident.me.
|
|
270
271
|
|
|
@@ -291,8 +292,8 @@ def _ident_me_ipv4(geo: bool=False, timeout: Union[float, Tuple[float, float]]
|
|
|
291
292
|
return {"status": False, "error": str(e)}
|
|
292
293
|
|
|
293
294
|
|
|
294
|
-
def _tnedi_me_ipv4(geo: bool
|
|
295
|
-
|
|
295
|
+
def _tnedi_me_ipv4(geo: bool, timeout: Union[float, Tuple[float, float]]
|
|
296
|
+
) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
296
297
|
"""
|
|
297
298
|
Get public IP and geolocation using tnedi.me.
|
|
298
299
|
|
|
@@ -319,7 +320,7 @@ def _tnedi_me_ipv4(geo: bool=False, timeout: Union[float, Tuple[float, float]]
|
|
|
319
320
|
return {"status": False, "error": str(e)}
|
|
320
321
|
|
|
321
322
|
|
|
322
|
-
def _myip_la_ipv4(geo: bool
|
|
323
|
+
def _myip_la_ipv4(geo: bool, timeout: Union[float, Tuple[float, float]]
|
|
323
324
|
) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
324
325
|
"""
|
|
325
326
|
Get public IP and geolocation using myip.la.
|
|
@@ -348,7 +349,7 @@ def _myip_la_ipv4(geo: bool=False, timeout: Union[float, Tuple[float, float]]=5
|
|
|
348
349
|
return {"status": False, "error": str(e)}
|
|
349
350
|
|
|
350
351
|
|
|
351
|
-
def _freeipapi_com_ipv4(geo: bool
|
|
352
|
+
def _freeipapi_com_ipv4(geo: bool, timeout: Union[float, Tuple[float, float]]
|
|
352
353
|
) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
353
354
|
"""
|
|
354
355
|
Get public IP and geolocation using freeipapi.com.
|
|
@@ -377,7 +378,7 @@ def _freeipapi_com_ipv4(geo: bool=False, timeout: Union[float, Tuple[float, floa
|
|
|
377
378
|
return {"status": False, "error": str(e)}
|
|
378
379
|
|
|
379
380
|
|
|
380
|
-
def _ipquery_io_ipv4(geo: bool
|
|
381
|
+
def _ipquery_io_ipv4(geo: bool, timeout: Union[float, Tuple[float, float]]
|
|
381
382
|
) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
382
383
|
"""
|
|
383
384
|
Get public IP and geolocation using ipquery.io.
|
|
@@ -407,7 +408,7 @@ def _ipquery_io_ipv4(geo: bool=False, timeout: Union[float, Tuple[float, float]]
|
|
|
407
408
|
return {"status": False, "error": str(e)}
|
|
408
409
|
|
|
409
410
|
|
|
410
|
-
def _ipwho_is_ipv4(geo: bool
|
|
411
|
+
def _ipwho_is_ipv4(geo: bool, timeout: Union[float, Tuple[float, float]]
|
|
411
412
|
) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
412
413
|
"""
|
|
413
414
|
Get public IP and geolocation using ipwho.is.
|
|
@@ -437,7 +438,7 @@ def _ipwho_is_ipv4(geo: bool=False, timeout: Union[float, Tuple[float, float]]=5
|
|
|
437
438
|
return {"status": False, "error": str(e)}
|
|
438
439
|
|
|
439
440
|
|
|
440
|
-
def _wtfismyip_com_ipv4(geo: bool
|
|
441
|
+
def _wtfismyip_com_ipv4(geo: bool, timeout: Union[float, Tuple[float, float]]
|
|
441
442
|
) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
442
443
|
"""
|
|
443
444
|
Get public IP and geolocation using wtfismyip.com.
|
|
@@ -547,7 +548,8 @@ IPV4_API_MAP = {
|
|
|
547
548
|
def get_public_ipv4(api: IPv4API=IPv4API.AUTO_SAFE, geo: bool=False,
|
|
548
549
|
timeout: Union[float, Tuple[float, float]]=5,
|
|
549
550
|
max_retries: int = 0,
|
|
550
|
-
retry_delay: float = 1.0
|
|
551
|
+
retry_delay: float = 1.0,
|
|
552
|
+
backoff_factor: float = 1.0) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
551
553
|
"""
|
|
552
554
|
Get public IPv4 and geolocation info based on the selected API.
|
|
553
555
|
|
|
@@ -556,6 +558,7 @@ def get_public_ipv4(api: IPv4API=IPv4API.AUTO_SAFE, geo: bool=False,
|
|
|
556
558
|
:param timeout: timeout value for API
|
|
557
559
|
:param max_retries: number of retries
|
|
558
560
|
:param retry_delay: delay between retries (in seconds)
|
|
561
|
+
:param backoff_factor: backoff factor
|
|
559
562
|
"""
|
|
560
563
|
if api in [IPv4API.AUTO, IPv4API.AUTO_SAFE]:
|
|
561
564
|
for _, api_data in IPV4_API_MAP.items():
|
|
@@ -566,6 +569,7 @@ def get_public_ipv4(api: IPv4API=IPv4API.AUTO_SAFE, geo: bool=False,
|
|
|
566
569
|
func=func,
|
|
567
570
|
max_retries=max_retries,
|
|
568
571
|
retry_delay=retry_delay,
|
|
572
|
+
backoff_factor=backoff_factor,
|
|
569
573
|
geo=geo,
|
|
570
574
|
timeout=timeout)
|
|
571
575
|
if result["status"]:
|
|
@@ -579,6 +583,7 @@ def get_public_ipv4(api: IPv4API=IPv4API.AUTO_SAFE, geo: bool=False,
|
|
|
579
583
|
func=func,
|
|
580
584
|
max_retries=max_retries,
|
|
581
585
|
retry_delay=retry_delay,
|
|
586
|
+
backoff_factor=backoff_factor,
|
|
582
587
|
geo=geo,
|
|
583
588
|
timeout=timeout)
|
|
584
589
|
return {"status": False, "error": "Unsupported API: {api}".format(api=api)}
|
ipspot/ipv6.py
CHANGED
|
@@ -37,8 +37,8 @@ def get_private_ipv6() -> Dict[str, Union[bool, Dict[str, str], str]]:
|
|
|
37
37
|
return {"status": False, "error": str(e)}
|
|
38
38
|
|
|
39
39
|
|
|
40
|
-
def _ip_sb_ipv6(geo: bool
|
|
41
|
-
|
|
40
|
+
def _ip_sb_ipv6(geo: bool, timeout: Union[float, Tuple[float, float]]
|
|
41
|
+
) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
42
42
|
"""
|
|
43
43
|
Get public IP and geolocation using ip.sb.
|
|
44
44
|
|
|
@@ -65,8 +65,8 @@ def _ip_sb_ipv6(geo: bool=False, timeout: Union[float, Tuple[float, float]]
|
|
|
65
65
|
return {"status": False, "error": str(e)}
|
|
66
66
|
|
|
67
67
|
|
|
68
|
-
def _ident_me_ipv6(geo: bool
|
|
69
|
-
|
|
68
|
+
def _ident_me_ipv6(geo: bool, timeout: Union[float, Tuple[float, float]]
|
|
69
|
+
) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
70
70
|
"""
|
|
71
71
|
Get public IP and geolocation using ident.me.
|
|
72
72
|
|
|
@@ -93,8 +93,8 @@ def _ident_me_ipv6(geo: bool=False, timeout: Union[float, Tuple[float, float]]
|
|
|
93
93
|
return {"status": False, "error": str(e)}
|
|
94
94
|
|
|
95
95
|
|
|
96
|
-
def _tnedi_me_ipv6(geo: bool
|
|
97
|
-
|
|
96
|
+
def _tnedi_me_ipv6(geo: bool, timeout: Union[float, Tuple[float, float]]
|
|
97
|
+
) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
98
98
|
"""
|
|
99
99
|
Get public IP and geolocation using tnedi.me.
|
|
100
100
|
|
|
@@ -121,8 +121,8 @@ def _tnedi_me_ipv6(geo: bool=False, timeout: Union[float, Tuple[float, float]]
|
|
|
121
121
|
return {"status": False, "error": str(e)}
|
|
122
122
|
|
|
123
123
|
|
|
124
|
-
def _ipleak_net_ipv6(geo: bool
|
|
125
|
-
|
|
124
|
+
def _ipleak_net_ipv6(geo: bool, timeout: Union[float, Tuple[float, float]]
|
|
125
|
+
) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
126
126
|
"""
|
|
127
127
|
Get public IP and geolocation using ipleak.net.
|
|
128
128
|
|
|
@@ -149,8 +149,8 @@ def _ipleak_net_ipv6(geo: bool=False, timeout: Union[float, Tuple[float, float]]
|
|
|
149
149
|
return {"status": False, "error": str(e)}
|
|
150
150
|
|
|
151
151
|
|
|
152
|
-
def _my_ip_io_ipv6(geo: bool
|
|
153
|
-
|
|
152
|
+
def _my_ip_io_ipv6(geo: bool, timeout: Union[float, Tuple[float, float]]
|
|
153
|
+
) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
154
154
|
"""
|
|
155
155
|
Get public IP and geolocation using my-ip.io.
|
|
156
156
|
|
|
@@ -177,8 +177,9 @@ def _my_ip_io_ipv6(geo: bool=False, timeout: Union[float, Tuple[float, float]]
|
|
|
177
177
|
return {"status": False, "error": str(e)}
|
|
178
178
|
|
|
179
179
|
|
|
180
|
-
|
|
181
|
-
|
|
180
|
+
# very low rate limit
|
|
181
|
+
def _ifconfig_co_ipv6(geo: bool, timeout: Union[float, Tuple[float, float]]
|
|
182
|
+
) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
182
183
|
"""
|
|
183
184
|
Get public IP and geolocation using ifconfig.co.
|
|
184
185
|
|
|
@@ -205,8 +206,8 @@ def _ifconfig_co_ipv6(geo: bool=False, timeout: Union[float, Tuple[float, float]
|
|
|
205
206
|
return {"status": False, "error": str(e)}
|
|
206
207
|
|
|
207
208
|
|
|
208
|
-
def _reallyfreegeoip_org_ipv6(
|
|
209
|
-
|
|
209
|
+
def _reallyfreegeoip_org_ipv6(
|
|
210
|
+
geo: bool, timeout: Union[float, Tuple[float, float]]) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
210
211
|
"""
|
|
211
212
|
Get public IP and geolocation using reallyfreegeoip.org.
|
|
212
213
|
|
|
@@ -233,8 +234,8 @@ def _reallyfreegeoip_org_ipv6(geo: bool=False, timeout: Union[float, Tuple[float
|
|
|
233
234
|
return {"status": False, "error": str(e)}
|
|
234
235
|
|
|
235
236
|
|
|
236
|
-
def _myip_la_ipv6(geo: bool
|
|
237
|
-
|
|
237
|
+
def _myip_la_ipv6(geo: bool, timeout: Union[float, Tuple[float, float]]
|
|
238
|
+
) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
238
239
|
"""
|
|
239
240
|
Get public IP and geolocation using myip.la.
|
|
240
241
|
|
|
@@ -262,8 +263,8 @@ def _myip_la_ipv6(geo: bool=False, timeout: Union[float, Tuple[float, float]]
|
|
|
262
263
|
return {"status": False, "error": str(e)}
|
|
263
264
|
|
|
264
265
|
|
|
265
|
-
def _freeipapi_com_ipv6(geo: bool
|
|
266
|
-
|
|
266
|
+
def _freeipapi_com_ipv6(geo: bool, timeout: Union[float, Tuple[float, float]]
|
|
267
|
+
) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
267
268
|
"""
|
|
268
269
|
Get public IP and geolocation using freeipapi.com.
|
|
269
270
|
|
|
@@ -343,7 +344,8 @@ IPV6_API_MAP = {
|
|
|
343
344
|
def get_public_ipv6(api: IPv6API=IPv6API.AUTO_SAFE, geo: bool=False,
|
|
344
345
|
timeout: Union[float, Tuple[float, float]]=5,
|
|
345
346
|
max_retries: int = 0,
|
|
346
|
-
retry_delay: float = 1.0
|
|
347
|
+
retry_delay: float = 1.0,
|
|
348
|
+
backoff_factor: float = 1.0) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
347
349
|
"""
|
|
348
350
|
Get public IPv6 and geolocation info based on the selected API.
|
|
349
351
|
|
|
@@ -352,6 +354,7 @@ def get_public_ipv6(api: IPv6API=IPv6API.AUTO_SAFE, geo: bool=False,
|
|
|
352
354
|
:param timeout: timeout value for API
|
|
353
355
|
:param max_retries: number of retries
|
|
354
356
|
:param retry_delay: delay between retries (in seconds)
|
|
357
|
+
:param backoff_factor: backoff factor
|
|
355
358
|
"""
|
|
356
359
|
if api in [IPv6API.AUTO, IPv6API.AUTO_SAFE]:
|
|
357
360
|
for _, api_data in IPV6_API_MAP.items():
|
|
@@ -362,6 +365,7 @@ def get_public_ipv6(api: IPv6API=IPv6API.AUTO_SAFE, geo: bool=False,
|
|
|
362
365
|
func=func,
|
|
363
366
|
max_retries=max_retries,
|
|
364
367
|
retry_delay=retry_delay,
|
|
368
|
+
backoff_factor=backoff_factor,
|
|
365
369
|
geo=geo,
|
|
366
370
|
timeout=timeout)
|
|
367
371
|
if result["status"]:
|
|
@@ -375,6 +379,7 @@ def get_public_ipv6(api: IPv6API=IPv6API.AUTO_SAFE, geo: bool=False,
|
|
|
375
379
|
func=func,
|
|
376
380
|
max_retries=max_retries,
|
|
377
381
|
retry_delay=retry_delay,
|
|
382
|
+
backoff_factor=backoff_factor,
|
|
378
383
|
geo=geo,
|
|
379
384
|
timeout=timeout)
|
|
380
385
|
return {"status": False, "error": "Unsupported API: {api}".format(api=api)}
|
ipspot/params.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"""ipspot params."""
|
|
3
3
|
from enum import Enum
|
|
4
4
|
|
|
5
|
-
IPSPOT_VERSION = "0.
|
|
5
|
+
IPSPOT_VERSION = "0.7"
|
|
6
6
|
|
|
7
7
|
IPSPOT_OVERVIEW = '''
|
|
8
8
|
IPSpot is a Python library for retrieving the current system's IP address and location information.
|
|
@@ -68,3 +68,8 @@ PARAMETERS_NAME_MAP = {
|
|
|
68
68
|
"organization": "Organization",
|
|
69
69
|
"api": "API"
|
|
70
70
|
}
|
|
71
|
+
|
|
72
|
+
PUBLIC_IPV4_ERROR = "Unable to retrieve public IPv4 information."
|
|
73
|
+
PRIVATE_IPV4_ERROR = "Unable to retrieve private IPv4 address."
|
|
74
|
+
PUBLIC_IPV6_ERROR = "Unable to retrieve public IPv6 information."
|
|
75
|
+
PRIVATE_IPV6_ERROR = "Unable to retrieve private IPv6 address."
|
ipspot/utils.py
CHANGED
|
@@ -74,22 +74,27 @@ def _get_json_force_ip(url: str, timeout: Union[float, Tuple[float, float]],
|
|
|
74
74
|
def _attempt_with_retries(
|
|
75
75
|
func: Callable,
|
|
76
76
|
max_retries: int,
|
|
77
|
-
retry_delay: float,
|
|
77
|
+
retry_delay: float,
|
|
78
|
+
backoff_factor: float,
|
|
79
|
+
**kwargs: dict) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
78
80
|
"""
|
|
79
81
|
Attempt a function call with retries and delay.
|
|
80
82
|
|
|
81
83
|
:param func: function to execute
|
|
82
84
|
:param max_retries: number of retries
|
|
83
85
|
:param retry_delay: delay between retries (in seconds)
|
|
86
|
+
:param backoff_factor: backoff factor
|
|
84
87
|
:param kwargs: keyword arguments to pass to the function
|
|
85
88
|
"""
|
|
86
89
|
max_retries = max(0, max_retries)
|
|
87
90
|
result = {"status": False, "error": ""}
|
|
91
|
+
next_delay = retry_delay
|
|
88
92
|
for attempt in range(max_retries + 1):
|
|
89
93
|
result = func(**kwargs)
|
|
90
94
|
if result["status"]:
|
|
91
95
|
break
|
|
92
|
-
time.sleep(
|
|
96
|
+
time.sleep(next_delay)
|
|
97
|
+
next_delay *= backoff_factor
|
|
93
98
|
return result
|
|
94
99
|
|
|
95
100
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ipspot
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7
|
|
4
4
|
Summary: IPSpot: A Python Tool to Fetch the System's IP Address
|
|
5
5
|
Home-page: https://github.com/openscilab/ipspot
|
|
6
|
-
Download-URL: https://github.com/openscilab/ipspot/tarball/v0.
|
|
6
|
+
Download-URL: https://github.com/openscilab/ipspot/tarball/v0.7
|
|
7
7
|
Author: IPSpot Development Team
|
|
8
8
|
Author-email: ipspot@openscilab.com
|
|
9
9
|
License: MIT
|
|
@@ -20,6 +20,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.11
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.12
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
23
24
|
Classifier: Intended Audience :: Developers
|
|
24
25
|
Classifier: Intended Audience :: Education
|
|
25
26
|
Classifier: Intended Audience :: End Users/Desktop
|
|
@@ -103,13 +104,13 @@ Dynamic: summary
|
|
|
103
104
|
## Installation
|
|
104
105
|
|
|
105
106
|
### Source Code
|
|
106
|
-
- Download [Version 0.
|
|
107
|
+
- Download [Version 0.7](https://github.com/openscilab/ipspot/archive/v0.7.zip) or [Latest Source](https://github.com/openscilab/ipspot/archive/dev.zip)
|
|
107
108
|
- `pip install .`
|
|
108
109
|
|
|
109
110
|
### PyPI
|
|
110
111
|
|
|
111
112
|
- Check [Python Packaging User Guide](https://packaging.python.org/installing/)
|
|
112
|
-
- `pip install ipspot==0.
|
|
113
|
+
- `pip install ipspot==0.7`
|
|
113
114
|
|
|
114
115
|
|
|
115
116
|
## Usage
|
|
@@ -124,7 +125,7 @@ Dynamic: summary
|
|
|
124
125
|
{'status': True, 'data': {'ip': 'xx.xx.xx.xx', 'api': 'ip-api.com'}}
|
|
125
126
|
>>> get_public_ipv4(api=IPv4API.IP_API_COM, geo=True, timeout=10)
|
|
126
127
|
{'data': {'country_code': 'GB', 'latitude': 50.9097, 'longitude': -1.4043, 'api': 'ip-api.com', 'country': 'United Kingdom', 'timezone': 'Europe/London', 'organization': '', 'region': 'England', 'ip': 'xx.xx.xx.xx', 'city': 'Southampton'}, 'status': True}
|
|
127
|
-
>>> get_public_ipv4(api=IPv4API.IP_API_COM, geo=True, timeout=10, max_retries=5, retry_delay=4)
|
|
128
|
+
>>> get_public_ipv4(api=IPv4API.IP_API_COM, geo=True, timeout=10, max_retries=5, retry_delay=4, backoff_factor=1.2)
|
|
128
129
|
{'data': {'country_code': 'GB', 'latitude': 50.9097, 'longitude': -1.4043, 'api': 'ip-api.com', 'country': 'United Kingdom', 'timezone': 'Europe/London', 'organization': '', 'region': 'England', 'ip': 'xx.xx.xx.xx', 'city': 'Southampton'}, 'status': True}
|
|
129
130
|
```
|
|
130
131
|
|
|
@@ -144,7 +145,7 @@ Dynamic: summary
|
|
|
144
145
|
{'data': {'api': 'ip.sb', 'ip': 'xx:xx:xx:xx::xx'}, 'status': True}
|
|
145
146
|
>>> get_public_ipv6(api=IPv6API.IP_SB, geo=True, timeout=10)
|
|
146
147
|
{'data': {'latitude': 51.2993, 'region': None, 'city': None, 'country_code': 'DE', 'api': 'ip.sb', 'longitude': 9.491, 'country': 'Germany', 'organization': 'Hetzner Online', 'timezone': 'Europe/Berlin', 'ip': 'xx:xx:xx:xx::xx'}, 'status': True}
|
|
147
|
-
>>> get_public_ipv6(api=IPv6API.IP_SB, geo=True, timeout=10, max_retries=5, retry_delay=4)
|
|
148
|
+
>>> get_public_ipv6(api=IPv6API.IP_SB, geo=True, timeout=10, max_retries=5, retry_delay=4, backoff_factor=1.2)
|
|
148
149
|
{'data': {'latitude': 51.2993, 'region': None, 'city': None, 'country_code': 'DE', 'api': 'ip.sb', 'longitude': 9.491, 'country': 'Germany', 'organization': 'Hetzner Online', 'timezone': 'Europe/Berlin', 'ip': 'xx:xx:xx:xx::xx'}, 'status': True}
|
|
149
150
|
```
|
|
150
151
|
|
|
@@ -165,7 +166,7 @@ Dynamic: summary
|
|
|
165
166
|
```console
|
|
166
167
|
> ipspot --version
|
|
167
168
|
|
|
168
|
-
0.
|
|
169
|
+
0.7
|
|
169
170
|
```
|
|
170
171
|
|
|
171
172
|
#### Info
|
|
@@ -173,18 +174,18 @@ Dynamic: summary
|
|
|
173
174
|
```console
|
|
174
175
|
> ipspot --info
|
|
175
176
|
|
|
176
|
-
___ ____ ____ _
|
|
177
|
-
|_ _|| _ \ / ___| _ __ ___ | |_
|
|
177
|
+
___ ____ ____ _
|
|
178
|
+
|_ _|| _ \ / ___| _ __ ___ | |_
|
|
178
179
|
| | | |_) |\___ \ | '_ \ / _ \ | __|
|
|
179
|
-
| | | __/ ___) || |_) || (_) || |_
|
|
180
|
+
| | | __/ ___) || |_) || (_) || |_
|
|
180
181
|
|___||_| |____/ | .__/ \___/ \__|
|
|
181
|
-
|_|
|
|
182
|
+
|_|
|
|
182
183
|
|
|
183
|
-
__ __ ___
|
|
184
|
-
\ \ / / _ / _ \
|
|
185
|
-
\ \ / / (_)| | | |
|
|
186
|
-
\ V / _ | |_| | _
|
|
187
|
-
\_/ (_) \___/ (_)
|
|
184
|
+
__ __ ___ _____
|
|
185
|
+
\ \ / / _ / _ \ |___ |
|
|
186
|
+
\ \ / / (_)| | | | / /
|
|
187
|
+
\ V / _ | |_| | _ / /
|
|
188
|
+
\_/ (_) \___/ (_) /_/
|
|
188
189
|
|
|
189
190
|
|
|
190
191
|
|
|
@@ -376,6 +377,17 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|
|
376
377
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
377
378
|
|
|
378
379
|
## [Unreleased]
|
|
380
|
+
## [0.7] - 2025-12-09
|
|
381
|
+
### Added
|
|
382
|
+
- `--backoff-factor` argument
|
|
383
|
+
### Changed
|
|
384
|
+
- CLI messages updated
|
|
385
|
+
- `Python 3.14` added to `test.yml`
|
|
386
|
+
- Internal functions default values removed
|
|
387
|
+
- `README.md` updated
|
|
388
|
+
- Test system modified
|
|
389
|
+
- `ipspot_info` function renamed to `_print_ipspot_info`
|
|
390
|
+
- `display_ip_info` function renamed to `_print_report`
|
|
379
391
|
## [0.6] - 2025-11-18
|
|
380
392
|
### Added
|
|
381
393
|
- `ForceIPHTTPAdapter` class
|
|
@@ -468,7 +480,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
|
468
480
|
- `--no-geo` argument
|
|
469
481
|
- Logo
|
|
470
482
|
|
|
471
|
-
[Unreleased]: https://github.com/openscilab/ipspot/compare/v0.
|
|
483
|
+
[Unreleased]: https://github.com/openscilab/ipspot/compare/v0.7...dev
|
|
484
|
+
[0.7]: https://github.com/openscilab/ipspot/compare/v0.6...v0.7
|
|
472
485
|
[0.6]: https://github.com/openscilab/ipspot/compare/v0.5...v0.6
|
|
473
486
|
[0.5]: https://github.com/openscilab/ipspot/compare/v0.4...v0.5
|
|
474
487
|
[0.4]: https://github.com/openscilab/ipspot/compare/v0.3...v0.4
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
ipspot/__init__.py,sha256=B47uAOAidLkXps1A4zDig6NN2kB3HcdMC20UOrrEfB4,281
|
|
2
|
+
ipspot/__main__.py,sha256=xKHY_tc94SWktkIHV0O9YADAHPZvT8yXOFSm_L2yMno,105
|
|
3
|
+
ipspot/cli.py,sha256=Y48HA_s6SrTCtjn-iAFNMplAARLwBUx8zpxesG0hARE,4980
|
|
4
|
+
ipspot/ipv4.py,sha256=QGeVZWruziLwe0bxtvo7k0xrnY73-znsXtSsvELYdyE,21613
|
|
5
|
+
ipspot/ipv6.py,sha256=xkgKyTSP_3TTijeM0BftiKL1KlIqMtRucb16-2QrkzA,14081
|
|
6
|
+
ipspot/params.py,sha256=u8eEDVB40Fo52DRhD7-mPg30U62Brtc2aGi9ZhqYuC8,2142
|
|
7
|
+
ipspot/utils.py,sha256=W3HJ61_KVtdg4gWr4m9xXblQc_E30rJoF1aKk36Zqzg,4591
|
|
8
|
+
ipspot-0.7.dist-info/licenses/AUTHORS.md,sha256=5ZvxP1KnuVkurB4psQDSqnqiAyn44q1aeiXUsnYgps4,411
|
|
9
|
+
ipspot-0.7.dist-info/licenses/LICENSE,sha256=0aOd4wzZRoSH_35UZXRHS7alPFTtuFEBJrajLuonEIw,1067
|
|
10
|
+
ipspot-0.7.dist-info/METADATA,sha256=P0uWs_6IZgVWPXJd53rsfvrepgJwLUq7Y8v_FNTDzB0,15395
|
|
11
|
+
ipspot-0.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
12
|
+
ipspot-0.7.dist-info/entry_points.txt,sha256=DJVLepYr8H3UcvWekU5Jy-tcr_xmWrphzgWGNOd3hlk,43
|
|
13
|
+
ipspot-0.7.dist-info/top_level.txt,sha256=v0WgE1z2iCy_bXU53fVcllwHLTvGNBIvq8u3KPC2_Sc,7
|
|
14
|
+
ipspot-0.7.dist-info/RECORD,,
|
ipspot-0.6.dist-info/RECORD
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
ipspot/__init__.py,sha256=B47uAOAidLkXps1A4zDig6NN2kB3HcdMC20UOrrEfB4,281
|
|
2
|
-
ipspot/__main__.py,sha256=xKHY_tc94SWktkIHV0O9YADAHPZvT8yXOFSm_L2yMno,105
|
|
3
|
-
ipspot/cli.py,sha256=MdyMh-9miuT8zQgklVrvsimaXnqD17sviWRJbUWlk58,4637
|
|
4
|
-
ipspot/ipv4.py,sha256=ZTv4HFyyxpiF8X-N8Pgk9_aJ7f9T58SpuuB3UKS0WII,21571
|
|
5
|
-
ipspot/ipv6.py,sha256=zqP_ImJQeKpVIhmGQZmPLJsOuviUNnVg70tVhk4UQU0,13991
|
|
6
|
-
ipspot/params.py,sha256=UqhiD8ybTnxRpecZ9RudKXxXyD-j63z23b6Cqbv1LJs,1881
|
|
7
|
-
ipspot/utils.py,sha256=wZxz6e14aDqK0g27AdiRMrbiz8pk4UfxZvbFRDZzhSI,4445
|
|
8
|
-
ipspot-0.6.dist-info/licenses/AUTHORS.md,sha256=5ZvxP1KnuVkurB4psQDSqnqiAyn44q1aeiXUsnYgps4,411
|
|
9
|
-
ipspot-0.6.dist-info/licenses/LICENSE,sha256=0aOd4wzZRoSH_35UZXRHS7alPFTtuFEBJrajLuonEIw,1067
|
|
10
|
-
ipspot-0.6.dist-info/METADATA,sha256=tYTL9nqZZP5YhOzV0IE2Y0CkUAytt-7b_dXWAdUCO08,14879
|
|
11
|
-
ipspot-0.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
12
|
-
ipspot-0.6.dist-info/entry_points.txt,sha256=DJVLepYr8H3UcvWekU5Jy-tcr_xmWrphzgWGNOd3hlk,43
|
|
13
|
-
ipspot-0.6.dist-info/top_level.txt,sha256=v0WgE1z2iCy_bXU53fVcllwHLTvGNBIvq8u3KPC2_Sc,7
|
|
14
|
-
ipspot-0.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|