ipspot 0.6__tar.gz → 0.7__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.
- {ipspot-0.6 → ipspot-0.7}/CHANGELOG.md +13 -1
- {ipspot-0.6 → ipspot-0.7}/PKG-INFO +30 -17
- {ipspot-0.6 → ipspot-0.7}/README.md +14 -14
- {ipspot-0.6 → ipspot-0.7}/SECURITY.md +2 -2
- {ipspot-0.6 → ipspot-0.7}/ipspot/cli.py +24 -15
- {ipspot-0.6 → ipspot-0.7}/ipspot/ipv4.py +31 -26
- {ipspot-0.6 → ipspot-0.7}/ipspot/ipv6.py +24 -19
- {ipspot-0.6 → ipspot-0.7}/ipspot/params.py +6 -1
- {ipspot-0.6 → ipspot-0.7}/ipspot/utils.py +7 -2
- {ipspot-0.6 → ipspot-0.7}/ipspot.egg-info/PKG-INFO +30 -17
- {ipspot-0.6 → ipspot-0.7}/setup.py +3 -2
- {ipspot-0.6 → ipspot-0.7}/tests/test_ipv4_api.py +15 -15
- {ipspot-0.6 → ipspot-0.7}/tests/test_ipv6_api.py +10 -10
- {ipspot-0.6 → ipspot-0.7}/tests/test_utils.py +6 -6
- {ipspot-0.6 → ipspot-0.7}/AUTHORS.md +0 -0
- {ipspot-0.6 → ipspot-0.7}/LICENSE +0 -0
- {ipspot-0.6 → ipspot-0.7}/MANIFEST.in +0 -0
- {ipspot-0.6 → ipspot-0.7}/dev-requirements.txt +0 -0
- {ipspot-0.6 → ipspot-0.7}/ipspot/__init__.py +0 -0
- {ipspot-0.6 → ipspot-0.7}/ipspot/__main__.py +0 -0
- {ipspot-0.6 → ipspot-0.7}/ipspot.egg-info/SOURCES.txt +0 -0
- {ipspot-0.6 → ipspot-0.7}/ipspot.egg-info/dependency_links.txt +0 -0
- {ipspot-0.6 → ipspot-0.7}/ipspot.egg-info/entry_points.txt +0 -0
- {ipspot-0.6 → ipspot-0.7}/ipspot.egg-info/requires.txt +0 -0
- {ipspot-0.6 → ipspot-0.7}/ipspot.egg-info/top_level.txt +0 -0
- {ipspot-0.6 → ipspot-0.7}/requirements.txt +0 -0
- {ipspot-0.6 → ipspot-0.7}/setup.cfg +0 -0
- {ipspot-0.6 → ipspot-0.7}/tests/test_ipv4_functions.py +0 -0
- {ipspot-0.6 → ipspot-0.7}/tests/test_ipv6_functions.py +0 -0
|
@@ -5,6 +5,17 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|
|
5
5
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
|
+
## [0.7] - 2025-12-09
|
|
9
|
+
### Added
|
|
10
|
+
- `--backoff-factor` argument
|
|
11
|
+
### Changed
|
|
12
|
+
- CLI messages updated
|
|
13
|
+
- `Python 3.14` added to `test.yml`
|
|
14
|
+
- Internal functions default values removed
|
|
15
|
+
- `README.md` updated
|
|
16
|
+
- Test system modified
|
|
17
|
+
- `ipspot_info` function renamed to `_print_ipspot_info`
|
|
18
|
+
- `display_ip_info` function renamed to `_print_report`
|
|
8
19
|
## [0.6] - 2025-11-18
|
|
9
20
|
### Added
|
|
10
21
|
- `ForceIPHTTPAdapter` class
|
|
@@ -97,7 +108,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
|
97
108
|
- `--no-geo` argument
|
|
98
109
|
- Logo
|
|
99
110
|
|
|
100
|
-
[Unreleased]: https://github.com/openscilab/ipspot/compare/v0.
|
|
111
|
+
[Unreleased]: https://github.com/openscilab/ipspot/compare/v0.7...dev
|
|
112
|
+
[0.7]: https://github.com/openscilab/ipspot/compare/v0.6...v0.7
|
|
101
113
|
[0.6]: https://github.com/openscilab/ipspot/compare/v0.5...v0.6
|
|
102
114
|
[0.5]: https://github.com/openscilab/ipspot/compare/v0.4...v0.5
|
|
103
115
|
[0.4]: https://github.com/openscilab/ipspot/compare/v0.3...v0.4
|
|
@@ -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
|
|
@@ -53,13 +53,13 @@
|
|
|
53
53
|
## Installation
|
|
54
54
|
|
|
55
55
|
### Source Code
|
|
56
|
-
- Download [Version 0.
|
|
56
|
+
- Download [Version 0.7](https://github.com/openscilab/ipspot/archive/v0.7.zip) or [Latest Source](https://github.com/openscilab/ipspot/archive/dev.zip)
|
|
57
57
|
- `pip install .`
|
|
58
58
|
|
|
59
59
|
### PyPI
|
|
60
60
|
|
|
61
61
|
- Check [Python Packaging User Guide](https://packaging.python.org/installing/)
|
|
62
|
-
- `pip install ipspot==0.
|
|
62
|
+
- `pip install ipspot==0.7`
|
|
63
63
|
|
|
64
64
|
|
|
65
65
|
## Usage
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
{'status': True, 'data': {'ip': 'xx.xx.xx.xx', 'api': 'ip-api.com'}}
|
|
75
75
|
>>> get_public_ipv4(api=IPv4API.IP_API_COM, geo=True, timeout=10)
|
|
76
76
|
{'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}
|
|
77
|
-
>>> get_public_ipv4(api=IPv4API.IP_API_COM, geo=True, timeout=10, max_retries=5, retry_delay=4)
|
|
77
|
+
>>> get_public_ipv4(api=IPv4API.IP_API_COM, geo=True, timeout=10, max_retries=5, retry_delay=4, backoff_factor=1.2)
|
|
78
78
|
{'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}
|
|
79
79
|
```
|
|
80
80
|
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
{'data': {'api': 'ip.sb', 'ip': 'xx:xx:xx:xx::xx'}, 'status': True}
|
|
95
95
|
>>> get_public_ipv6(api=IPv6API.IP_SB, geo=True, timeout=10)
|
|
96
96
|
{'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}
|
|
97
|
-
>>> get_public_ipv6(api=IPv6API.IP_SB, geo=True, timeout=10, max_retries=5, retry_delay=4)
|
|
97
|
+
>>> get_public_ipv6(api=IPv6API.IP_SB, geo=True, timeout=10, max_retries=5, retry_delay=4, backoff_factor=1.2)
|
|
98
98
|
{'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}
|
|
99
99
|
```
|
|
100
100
|
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
```console
|
|
116
116
|
> ipspot --version
|
|
117
117
|
|
|
118
|
-
0.
|
|
118
|
+
0.7
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
#### Info
|
|
@@ -123,18 +123,18 @@
|
|
|
123
123
|
```console
|
|
124
124
|
> ipspot --info
|
|
125
125
|
|
|
126
|
-
___ ____ ____ _
|
|
127
|
-
|_ _|| _ \ / ___| _ __ ___ | |_
|
|
126
|
+
___ ____ ____ _
|
|
127
|
+
|_ _|| _ \ / ___| _ __ ___ | |_
|
|
128
128
|
| | | |_) |\___ \ | '_ \ / _ \ | __|
|
|
129
|
-
| | | __/ ___) || |_) || (_) || |_
|
|
129
|
+
| | | __/ ___) || |_) || (_) || |_
|
|
130
130
|
|___||_| |____/ | .__/ \___/ \__|
|
|
131
|
-
|_|
|
|
131
|
+
|_|
|
|
132
132
|
|
|
133
|
-
__ __ ___
|
|
134
|
-
\ \ / / _ / _ \
|
|
135
|
-
\ \ / / (_)| | | |
|
|
136
|
-
\ V / _ | |_| | _
|
|
137
|
-
\_/ (_) \___/ (_)
|
|
133
|
+
__ __ ___ _____
|
|
134
|
+
\ \ / / _ / _ \ |___ |
|
|
135
|
+
\ \ / / (_)| | | | / /
|
|
136
|
+
\ V / _ | |_| | _ / /
|
|
137
|
+
\_/ (_) \___/ (_) /_/
|
|
138
138
|
|
|
139
139
|
|
|
140
140
|
|
|
@@ -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)
|
|
@@ -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)}
|
|
@@ -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)}
|
|
@@ -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."
|
|
@@ -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
|
|
@@ -32,7 +32,7 @@ def read_description() -> str:
|
|
|
32
32
|
setup(
|
|
33
33
|
name='ipspot',
|
|
34
34
|
packages=['ipspot'],
|
|
35
|
-
version='0.
|
|
35
|
+
version='0.7',
|
|
36
36
|
description='IPSpot: A Python Tool to Fetch the System\'s IP Address',
|
|
37
37
|
long_description=read_description(),
|
|
38
38
|
long_description_content_type='text/markdown',
|
|
@@ -40,7 +40,7 @@ setup(
|
|
|
40
40
|
author='IPSpot Development Team',
|
|
41
41
|
author_email='ipspot@openscilab.com',
|
|
42
42
|
url='https://github.com/openscilab/ipspot',
|
|
43
|
-
download_url='https://github.com/openscilab/ipspot/tarball/v0.
|
|
43
|
+
download_url='https://github.com/openscilab/ipspot/tarball/v0.7',
|
|
44
44
|
keywords="ip ipv4 geo geolocation network location ipspot cli",
|
|
45
45
|
project_urls={
|
|
46
46
|
'Source': 'https://github.com/openscilab/ipspot'
|
|
@@ -59,6 +59,7 @@ setup(
|
|
|
59
59
|
'Programming Language :: Python :: 3.11',
|
|
60
60
|
'Programming Language :: Python :: 3.12',
|
|
61
61
|
'Programming Language :: Python :: 3.13',
|
|
62
|
+
'Programming Language :: Python :: 3.14',
|
|
62
63
|
'Intended Audience :: Developers',
|
|
63
64
|
'Intended Audience :: Education',
|
|
64
65
|
'Intended Audience :: End Users/Desktop',
|
|
@@ -20,7 +20,7 @@ def test_public_ipv4_auto_safe_success():
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
def test_public_ipv4_ipapi_co_success():
|
|
23
|
-
result = get_public_ipv4(api=IPv4API.IPAPI_CO, geo=True, timeout=40, max_retries=4, retry_delay=90)
|
|
23
|
+
result = get_public_ipv4(api=IPv4API.IPAPI_CO, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1)
|
|
24
24
|
assert result["status"]
|
|
25
25
|
assert is_ipv4(result["data"]["ip"])
|
|
26
26
|
assert set(result["data"].keys()) == DATA_ITEMS
|
|
@@ -28,7 +28,7 @@ def test_public_ipv4_ipapi_co_success():
|
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
def test_public_ipv4_ipleak_net_success():
|
|
31
|
-
result = get_public_ipv4(api=IPv4API.IPLEAK_NET, geo=True, timeout=40, max_retries=4, retry_delay=90)
|
|
31
|
+
result = get_public_ipv4(api=IPv4API.IPLEAK_NET, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1)
|
|
32
32
|
assert result["status"]
|
|
33
33
|
assert is_ipv4(result["data"]["ip"])
|
|
34
34
|
assert set(result["data"].keys()) == DATA_ITEMS
|
|
@@ -36,7 +36,7 @@ def test_public_ipv4_ipleak_net_success():
|
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
def test_public_ipv4_my_ip_io_success():
|
|
39
|
-
result = get_public_ipv4(api=IPv4API.MY_IP_IO, geo=True, timeout=40, max_retries=4, retry_delay=90)
|
|
39
|
+
result = get_public_ipv4(api=IPv4API.MY_IP_IO, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1)
|
|
40
40
|
assert result["status"]
|
|
41
41
|
assert is_ipv4(result["data"]["ip"])
|
|
42
42
|
assert set(result["data"].keys()) == DATA_ITEMS
|
|
@@ -44,7 +44,7 @@ def test_public_ipv4_my_ip_io_success():
|
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
def test_public_ipv4_ifconfig_co_success():
|
|
47
|
-
result = get_public_ipv4(api=IPv4API.IFCONFIG_CO, geo=True, timeout=40, max_retries=4, retry_delay=90)
|
|
47
|
+
result = get_public_ipv4(api=IPv4API.IFCONFIG_CO, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1)
|
|
48
48
|
assert result["status"]
|
|
49
49
|
assert is_ipv4(result["data"]["ip"])
|
|
50
50
|
assert set(result["data"].keys()) == DATA_ITEMS
|
|
@@ -52,7 +52,7 @@ def test_public_ipv4_ifconfig_co_success():
|
|
|
52
52
|
|
|
53
53
|
|
|
54
54
|
def test_public_ipv4_myip_la_success():
|
|
55
|
-
result = get_public_ipv4(api=IPv4API.MYIP_LA, geo=True, timeout=40, max_retries=4, retry_delay=90)
|
|
55
|
+
result = get_public_ipv4(api=IPv4API.MYIP_LA, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1)
|
|
56
56
|
assert result["status"]
|
|
57
57
|
assert is_ipv4(result["data"]["ip"])
|
|
58
58
|
assert set(result["data"].keys()) == DATA_ITEMS
|
|
@@ -60,7 +60,7 @@ def test_public_ipv4_myip_la_success():
|
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
def test_public_ipv4_ipquery_io_success():
|
|
63
|
-
result = get_public_ipv4(api=IPv4API.IPQUERY_IO, geo=True, timeout=40, max_retries=4, retry_delay=90)
|
|
63
|
+
result = get_public_ipv4(api=IPv4API.IPQUERY_IO, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1)
|
|
64
64
|
assert result["status"]
|
|
65
65
|
assert is_ipv4(result["data"]["ip"])
|
|
66
66
|
assert set(result["data"].keys()) == DATA_ITEMS
|
|
@@ -68,7 +68,7 @@ def test_public_ipv4_ipquery_io_success():
|
|
|
68
68
|
|
|
69
69
|
|
|
70
70
|
def test_public_ipv4_ipwho_is_success():
|
|
71
|
-
result = get_public_ipv4(api=IPv4API.IPWHO_IS, geo=True, timeout=40, max_retries=4, retry_delay=90)
|
|
71
|
+
result = get_public_ipv4(api=IPv4API.IPWHO_IS, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1)
|
|
72
72
|
assert result["status"]
|
|
73
73
|
assert is_ipv4(result["data"]["ip"])
|
|
74
74
|
assert set(result["data"].keys()) == DATA_ITEMS
|
|
@@ -76,7 +76,7 @@ def test_public_ipv4_ipwho_is_success():
|
|
|
76
76
|
|
|
77
77
|
|
|
78
78
|
def test_public_ipv4_freeipapi_com_success():
|
|
79
|
-
result = get_public_ipv4(api=IPv4API.FREEIPAPI_COM, geo=True, timeout=40, max_retries=4, retry_delay=90)
|
|
79
|
+
result = get_public_ipv4(api=IPv4API.FREEIPAPI_COM, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1)
|
|
80
80
|
assert result["status"]
|
|
81
81
|
assert is_ipv4(result["data"]["ip"])
|
|
82
82
|
assert set(result["data"].keys()) == DATA_ITEMS
|
|
@@ -84,7 +84,7 @@ def test_public_ipv4_freeipapi_com_success():
|
|
|
84
84
|
|
|
85
85
|
|
|
86
86
|
def test_public_ipv4_ip_api_com_success():
|
|
87
|
-
result = get_public_ipv4(api=IPv4API.IP_API_COM, geo=True, timeout=40, max_retries=4, retry_delay=90)
|
|
87
|
+
result = get_public_ipv4(api=IPv4API.IP_API_COM, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1)
|
|
88
88
|
assert result["status"]
|
|
89
89
|
assert is_ipv4(result["data"]["ip"])
|
|
90
90
|
assert set(result["data"].keys()) == DATA_ITEMS
|
|
@@ -92,7 +92,7 @@ def test_public_ipv4_ip_api_com_success():
|
|
|
92
92
|
|
|
93
93
|
|
|
94
94
|
def test_public_ipv4_ipinfo_io_success():
|
|
95
|
-
result = get_public_ipv4(api=IPv4API.IPINFO_IO, geo=True, timeout=40, max_retries=4, retry_delay=90)
|
|
95
|
+
result = get_public_ipv4(api=IPv4API.IPINFO_IO, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1)
|
|
96
96
|
assert result["status"]
|
|
97
97
|
assert is_ipv4(result["data"]["ip"])
|
|
98
98
|
assert set(result["data"].keys()) == DATA_ITEMS
|
|
@@ -100,7 +100,7 @@ def test_public_ipv4_ipinfo_io_success():
|
|
|
100
100
|
|
|
101
101
|
|
|
102
102
|
def test_public_ipv4_ip_sb_success():
|
|
103
|
-
result = get_public_ipv4(api=IPv4API.IP_SB, geo=True, timeout=40, max_retries=4, retry_delay=90)
|
|
103
|
+
result = get_public_ipv4(api=IPv4API.IP_SB, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1)
|
|
104
104
|
assert result["status"]
|
|
105
105
|
assert is_ipv4(result["data"]["ip"])
|
|
106
106
|
assert set(result["data"].keys()) == DATA_ITEMS
|
|
@@ -108,7 +108,7 @@ def test_public_ipv4_ip_sb_success():
|
|
|
108
108
|
|
|
109
109
|
|
|
110
110
|
def test_public_ipv4_ident_me_success():
|
|
111
|
-
result = get_public_ipv4(api=IPv4API.IDENT_ME, geo=True, timeout=40, max_retries=4, retry_delay=90)
|
|
111
|
+
result = get_public_ipv4(api=IPv4API.IDENT_ME, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1)
|
|
112
112
|
assert result["status"]
|
|
113
113
|
assert is_ipv4(result["data"]["ip"])
|
|
114
114
|
assert set(result["data"].keys()) == DATA_ITEMS
|
|
@@ -116,7 +116,7 @@ def test_public_ipv4_ident_me_success():
|
|
|
116
116
|
|
|
117
117
|
|
|
118
118
|
def test_public_ipv4_tnedi_me_success():
|
|
119
|
-
result = get_public_ipv4(api=IPv4API.TNEDI_ME, geo=True, timeout=40, max_retries=4, retry_delay=90)
|
|
119
|
+
result = get_public_ipv4(api=IPv4API.TNEDI_ME, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1)
|
|
120
120
|
assert result["status"]
|
|
121
121
|
assert is_ipv4(result["data"]["ip"])
|
|
122
122
|
assert set(result["data"].keys()) == DATA_ITEMS
|
|
@@ -124,7 +124,7 @@ def test_public_ipv4_tnedi_me_success():
|
|
|
124
124
|
|
|
125
125
|
|
|
126
126
|
def test_public_ipv4_reallyfreegeoip_org_success():
|
|
127
|
-
result = get_public_ipv4(api=IPv4API.REALLYFREEGEOIP_ORG, geo=True, timeout=40, max_retries=4, retry_delay=90)
|
|
127
|
+
result = get_public_ipv4(api=IPv4API.REALLYFREEGEOIP_ORG, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1)
|
|
128
128
|
assert result["status"]
|
|
129
129
|
assert is_ipv4(result["data"]["ip"])
|
|
130
130
|
assert set(result["data"].keys()) == DATA_ITEMS
|
|
@@ -132,7 +132,7 @@ def test_public_ipv4_reallyfreegeoip_org_success():
|
|
|
132
132
|
|
|
133
133
|
|
|
134
134
|
def test_public_ipv4_wtfismyip_com_success():
|
|
135
|
-
result = get_public_ipv4(api=IPv4API.WTFISMYIP_COM, geo=True, timeout=40, max_retries=4, retry_delay=90)
|
|
135
|
+
result = get_public_ipv4(api=IPv4API.WTFISMYIP_COM, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1)
|
|
136
136
|
assert result["status"]
|
|
137
137
|
assert is_ipv4(result["data"]["ip"])
|
|
138
138
|
assert set(result["data"].keys()) == DATA_ITEMS
|
|
@@ -13,7 +13,7 @@ def test_public_ipv6_ip_sb_success():
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
def test_public_ipv6_ident_me_success():
|
|
16
|
-
result = get_public_ipv6(api=IPv6API.IDENT_ME, geo=True, timeout=40, max_retries=4, retry_delay=90)
|
|
16
|
+
result = get_public_ipv6(api=IPv6API.IDENT_ME, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1)
|
|
17
17
|
assert result["status"]
|
|
18
18
|
assert is_ipv6(result["data"]["ip"])
|
|
19
19
|
assert set(result["data"].keys()) == DATA_ITEMS
|
|
@@ -21,7 +21,7 @@ def test_public_ipv6_ident_me_success():
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
def test_public_ipv6_tnedi_me_success():
|
|
24
|
-
result = get_public_ipv6(api=IPv6API.TNEDI_ME, geo=True, timeout=40, max_retries=4, retry_delay=90)
|
|
24
|
+
result = get_public_ipv6(api=IPv6API.TNEDI_ME, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1)
|
|
25
25
|
assert result["status"]
|
|
26
26
|
assert is_ipv6(result["data"]["ip"])
|
|
27
27
|
assert set(result["data"].keys()) == DATA_ITEMS
|
|
@@ -29,7 +29,7 @@ def test_public_ipv6_tnedi_me_success():
|
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
def test_public_ipv6_ipleak_net_success():
|
|
32
|
-
result = get_public_ipv6(api=IPv6API.IPLEAK_NET, geo=True, timeout=40, max_retries=4, retry_delay=90)
|
|
32
|
+
result = get_public_ipv6(api=IPv6API.IPLEAK_NET, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1)
|
|
33
33
|
assert result["status"]
|
|
34
34
|
assert is_ipv6(result["data"]["ip"])
|
|
35
35
|
assert set(result["data"].keys()) == DATA_ITEMS
|
|
@@ -37,7 +37,7 @@ def test_public_ipv6_ipleak_net_success():
|
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
def test_public_ipv6_my_ip_io_success():
|
|
40
|
-
result = get_public_ipv6(api=IPv6API.MY_IP_IO, geo=True, timeout=40, max_retries=4, retry_delay=90)
|
|
40
|
+
result = get_public_ipv6(api=IPv6API.MY_IP_IO, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1)
|
|
41
41
|
assert result["status"]
|
|
42
42
|
assert is_ipv6(result["data"]["ip"])
|
|
43
43
|
assert set(result["data"].keys()) == DATA_ITEMS
|
|
@@ -45,7 +45,7 @@ def test_public_ipv6_my_ip_io_success():
|
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
def test_public_ipv6_ifconfig_co_success():
|
|
48
|
-
result = get_public_ipv6(api=IPv6API.IFCONFIG_CO, geo=True, timeout=40, max_retries=4, retry_delay=90)
|
|
48
|
+
result = get_public_ipv6(api=IPv6API.IFCONFIG_CO, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1)
|
|
49
49
|
assert result["status"]
|
|
50
50
|
assert is_ipv6(result["data"]["ip"])
|
|
51
51
|
assert set(result["data"].keys()) == DATA_ITEMS
|
|
@@ -53,7 +53,7 @@ def test_public_ipv6_ifconfig_co_success():
|
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
def test_public_ipv6_reallyfreegeoip_org_success():
|
|
56
|
-
result = get_public_ipv6(api=IPv6API.REALLYFREEGEOIP_ORG, geo=True, timeout=40, max_retries=4, retry_delay=90)
|
|
56
|
+
result = get_public_ipv6(api=IPv6API.REALLYFREEGEOIP_ORG, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1)
|
|
57
57
|
assert result["status"]
|
|
58
58
|
assert is_ipv6(result["data"]["ip"])
|
|
59
59
|
assert set(result["data"].keys()) == DATA_ITEMS
|
|
@@ -61,7 +61,7 @@ def test_public_ipv6_reallyfreegeoip_org_success():
|
|
|
61
61
|
|
|
62
62
|
|
|
63
63
|
def test_public_ipv6_myip_la_success():
|
|
64
|
-
result = get_public_ipv6(api=IPv6API.MYIP_LA, geo=True, timeout=40, max_retries=4, retry_delay=90)
|
|
64
|
+
result = get_public_ipv6(api=IPv6API.MYIP_LA, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1)
|
|
65
65
|
assert result["status"]
|
|
66
66
|
assert is_ipv6(result["data"]["ip"])
|
|
67
67
|
assert set(result["data"].keys()) == DATA_ITEMS
|
|
@@ -69,7 +69,7 @@ def test_public_ipv6_myip_la_success():
|
|
|
69
69
|
|
|
70
70
|
|
|
71
71
|
def test_public_freeipapi_com_success():
|
|
72
|
-
result = get_public_ipv6(api=IPv6API.FREEIPAPI_COM, geo=True, timeout=40, max_retries=4, retry_delay=90)
|
|
72
|
+
result = get_public_ipv6(api=IPv6API.FREEIPAPI_COM, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1)
|
|
73
73
|
assert result["status"]
|
|
74
74
|
assert is_ipv6(result["data"]["ip"])
|
|
75
75
|
assert set(result["data"].keys()) == DATA_ITEMS
|
|
@@ -77,14 +77,14 @@ def test_public_freeipapi_com_success():
|
|
|
77
77
|
|
|
78
78
|
|
|
79
79
|
def test_public_ipv6_auto_success():
|
|
80
|
-
result = get_public_ipv6(api=IPv6API.AUTO, geo=True, timeout=40, max_retries=4, retry_delay=90)
|
|
80
|
+
result = get_public_ipv6(api=IPv6API.AUTO, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1)
|
|
81
81
|
assert result["status"]
|
|
82
82
|
assert is_ipv6(result["data"]["ip"])
|
|
83
83
|
assert set(result["data"].keys()) == DATA_ITEMS
|
|
84
84
|
|
|
85
85
|
|
|
86
86
|
def test_public_ipv6_auto_safe_success():
|
|
87
|
-
result = get_public_ipv6(api=IPv6API.AUTO_SAFE, geo=True, timeout=40, max_retries=4, retry_delay=90)
|
|
87
|
+
result = get_public_ipv6(api=IPv6API.AUTO_SAFE, geo=True, timeout=40, max_retries=4, retry_delay=90, backoff_factor=1.1)
|
|
88
88
|
assert result["status"]
|
|
89
89
|
assert is_ipv6(result["data"]["ip"])
|
|
90
90
|
assert set(result["data"].keys()) == DATA_ITEMS
|
|
@@ -21,7 +21,7 @@ def test_filter_parameter4():
|
|
|
21
21
|
|
|
22
22
|
def test_attempt_with_retries1():
|
|
23
23
|
mock_func = Mock(return_value={"status": True, "data": {"message": "ok"}})
|
|
24
|
-
result = _attempt_with_retries(mock_func, max_retries=3, retry_delay=0.01)
|
|
24
|
+
result = _attempt_with_retries(mock_func, max_retries=3, retry_delay=0.01, backoff_factor=1.3)
|
|
25
25
|
assert result["status"] is True
|
|
26
26
|
assert mock_func.call_count == 1
|
|
27
27
|
|
|
@@ -31,33 +31,33 @@ def test_attempt_with_retries2():
|
|
|
31
31
|
{"status": False, "error": "fail again"},
|
|
32
32
|
{"status": True, "data": {"message": "ok"}}
|
|
33
33
|
])
|
|
34
|
-
result = _attempt_with_retries(mock_func, max_retries=5, retry_delay=0.01)
|
|
34
|
+
result = _attempt_with_retries(mock_func, max_retries=5, retry_delay=0.01, backoff_factor=1.3)
|
|
35
35
|
assert result["status"] is True
|
|
36
36
|
assert mock_func.call_count == 3
|
|
37
37
|
|
|
38
38
|
def test_attempt_with_retries3():
|
|
39
39
|
mock_func = Mock(return_value={"status": False, "error": "permanent failure"})
|
|
40
|
-
result = _attempt_with_retries(mock_func, max_retries=2, retry_delay=0.01)
|
|
40
|
+
result = _attempt_with_retries(mock_func, max_retries=2, retry_delay=0.01, backoff_factor=1.3)
|
|
41
41
|
assert result["status"] is False
|
|
42
42
|
assert result["error"] == "permanent failure"
|
|
43
43
|
assert mock_func.call_count == 3
|
|
44
44
|
|
|
45
45
|
def test_attempt_with_retries4():
|
|
46
46
|
mock_func = Mock(return_value={"status": False, "error": "no retry"})
|
|
47
|
-
result = _attempt_with_retries(mock_func, max_retries=0, retry_delay=0.01)
|
|
47
|
+
result = _attempt_with_retries(mock_func, max_retries=0, retry_delay=0.01, backoff_factor=1.3)
|
|
48
48
|
assert result["status"] is False
|
|
49
49
|
assert mock_func.call_count == 1
|
|
50
50
|
|
|
51
51
|
def test_attempt_with_retries5():
|
|
52
52
|
mock_func = Mock(return_value={"status": False, "error": "invalid"})
|
|
53
|
-
result = _attempt_with_retries(mock_func, max_retries=-5, retry_delay=0.01)
|
|
53
|
+
result = _attempt_with_retries(mock_func, max_retries=-5, retry_delay=0.01, backoff_factor=1.3)
|
|
54
54
|
assert result["status"] is False
|
|
55
55
|
assert mock_func.call_count == 1
|
|
56
56
|
|
|
57
57
|
def test_attempt_with_retries6():
|
|
58
58
|
def example_func(x, y):
|
|
59
59
|
return {"status": x + y > 0, "data": {"sum": x + y} if x + y > 0 else {}, "error": "" if x + y > 0 else "negative"}
|
|
60
|
-
result = _attempt_with_retries(example_func, max_retries=1, retry_delay=0.01, x=1, y=2)
|
|
60
|
+
result = _attempt_with_retries(example_func, max_retries=1, retry_delay=0.01, backoff_factor=1.3, x=1, y=2)
|
|
61
61
|
assert result["status"] is True
|
|
62
62
|
assert result["data"]["sum"] == 3
|
|
63
63
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|