ipspot 0.1__tar.gz → 0.2__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.1 → ipspot-0.2}/CHANGELOG.md +10 -1
- {ipspot-0.1 → ipspot-0.2}/PKG-INFO +37 -14
- {ipspot-0.1 → ipspot-0.2}/README.md +25 -11
- {ipspot-0.1 → ipspot-0.2}/SECURITY.md +2 -2
- {ipspot-0.1 → ipspot-0.2}/dev-requirements.txt +3 -1
- {ipspot-0.1 → ipspot-0.2}/ipspot/functions.py +55 -16
- {ipspot-0.1 → ipspot-0.2}/ipspot/params.py +8 -2
- {ipspot-0.1 → ipspot-0.2}/ipspot.egg-info/PKG-INFO +37 -14
- {ipspot-0.1 → ipspot-0.2}/ipspot.egg-info/SOURCES.txt +3 -1
- {ipspot-0.1 → ipspot-0.2}/setup.py +2 -2
- ipspot-0.2/tests/test_functions.py +24 -0
- ipspot-0.2/tests/test_ipv4.py +108 -0
- {ipspot-0.1 → ipspot-0.2}/AUTHORS.md +0 -0
- {ipspot-0.1 → ipspot-0.2}/LICENSE +0 -0
- {ipspot-0.1 → ipspot-0.2}/MANIFEST.in +0 -0
- {ipspot-0.1 → ipspot-0.2}/ipspot/__init__.py +0 -0
- {ipspot-0.1 → ipspot-0.2}/ipspot/__main__.py +0 -0
- {ipspot-0.1 → ipspot-0.2}/ipspot.egg-info/dependency_links.txt +0 -0
- {ipspot-0.1 → ipspot-0.2}/ipspot.egg-info/entry_points.txt +0 -0
- {ipspot-0.1 → ipspot-0.2}/ipspot.egg-info/requires.txt +0 -0
- {ipspot-0.1 → ipspot-0.2}/ipspot.egg-info/top_level.txt +0 -0
- {ipspot-0.1 → ipspot-0.2}/requirements.txt +0 -0
- {ipspot-0.1 → ipspot-0.2}/setup.cfg +0 -0
|
@@ -5,6 +5,14 @@ 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.2] - 2025-05-04
|
|
9
|
+
### Added
|
|
10
|
+
- Support [ip.sb](https://api.ip.sb/geoip)
|
|
11
|
+
- `--timeout` argument
|
|
12
|
+
### Changed
|
|
13
|
+
- `README.md` updated
|
|
14
|
+
- Requests header updated
|
|
15
|
+
- Test system modified
|
|
8
16
|
## [0.1] - 2025-04-25
|
|
9
17
|
### Added
|
|
10
18
|
- Support [ipinfo.io](https://ipinfo.io)
|
|
@@ -16,7 +24,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
|
16
24
|
- `--no-geo` argument
|
|
17
25
|
- Logo
|
|
18
26
|
|
|
19
|
-
[Unreleased]: https://github.com/openscilab/ipspot/compare/v0.
|
|
27
|
+
[Unreleased]: https://github.com/openscilab/ipspot/compare/v0.2...dev
|
|
28
|
+
[0.2]: https://github.com/openscilab/ipspot/compare/v0.1...v0.2
|
|
20
29
|
[0.1]: https://github.com/openscilab/ipspot/compare/3216fb7...v0.1
|
|
21
30
|
|
|
22
31
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ipspot
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2
|
|
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.2
|
|
7
7
|
Author: IPSpot Development Team
|
|
8
8
|
Author-email: ipspot@openscilab.com
|
|
9
9
|
License: MIT
|
|
@@ -55,6 +55,7 @@ Dynamic: summary
|
|
|
55
55
|
<a href="https://badge.fury.io/py/ipspot"><img src="https://badge.fury.io/py/ipspot.svg" alt="PyPI version"></a>
|
|
56
56
|
<a href="https://www.python.org/"><img src="https://img.shields.io/badge/built%20with-Python3-green.svg" alt="built with Python3"></a>
|
|
57
57
|
<a href="https://github.com/openscilab/ipspot"><img alt="GitHub repo size" src="https://img.shields.io/github/repo-size/openscilab/ipspot"></a>
|
|
58
|
+
<a href="https://discord.gg/yyDV3T4cwU"><img src="https://img.shields.io/discord/1064533716615049236.svg" alt="Discord Channel"></a>
|
|
58
59
|
</div>
|
|
59
60
|
|
|
60
61
|
## Overview
|
|
@@ -89,17 +90,25 @@ Dynamic: summary
|
|
|
89
90
|
</tr>
|
|
90
91
|
</table>
|
|
91
92
|
|
|
93
|
+
<table>
|
|
94
|
+
<tr>
|
|
95
|
+
<td align="center">Code Quality</td>
|
|
96
|
+
<td align="center"><a href="https://app.codacy.com/gh/openscilab/ipspot/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade"><img src="https://app.codacy.com/project/badge/Grade/cb2ab6584eb443b8a33da4d4252480bc"/></a></td>
|
|
97
|
+
<td align="center"><a href="https://www.codefactor.io/repository/github/openscilab/ipspot"><img src="https://www.codefactor.io/repository/github/openscilab/ipspot/badge" alt="CodeFactor"></a></td>
|
|
98
|
+
</tr>
|
|
99
|
+
</table>
|
|
100
|
+
|
|
92
101
|
|
|
93
102
|
## Installation
|
|
94
103
|
|
|
95
104
|
### Source Code
|
|
96
|
-
- Download [Version 0.
|
|
105
|
+
- Download [Version 0.2](https://github.com/openscilab/ipspot/archive/v0.2.zip) or [Latest Source](https://github.com/openscilab/ipspot/archive/dev.zip)
|
|
97
106
|
- `pip install .`
|
|
98
107
|
|
|
99
108
|
### PyPI
|
|
100
109
|
|
|
101
110
|
- Check [Python Packaging User Guide](https://packaging.python.org/installing/)
|
|
102
|
-
- `pip install ipspot==0.
|
|
111
|
+
- `pip install ipspot==0.2`
|
|
103
112
|
|
|
104
113
|
|
|
105
114
|
## Usage
|
|
@@ -112,7 +121,7 @@ Dynamic: summary
|
|
|
112
121
|
>>> from ipspot import get_public_ipv4, IPv4API
|
|
113
122
|
>>> get_public_ipv4(api=IPv4API.IPAPI)
|
|
114
123
|
{'status': True, 'data': {'ip': 'xx.xx.xx.xx', 'api': 'ip-api.com'}}
|
|
115
|
-
>>> get_public_ipv4(api=IPv4API.IPAPI, geo=True)
|
|
124
|
+
>>> get_public_ipv4(api=IPv4API.IPAPI, geo=True, timeout=10)
|
|
116
125
|
{'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}
|
|
117
126
|
```
|
|
118
127
|
|
|
@@ -133,7 +142,7 @@ Dynamic: summary
|
|
|
133
142
|
```console
|
|
134
143
|
> ipspot --version
|
|
135
144
|
|
|
136
|
-
0.
|
|
145
|
+
0.2
|
|
137
146
|
```
|
|
138
147
|
|
|
139
148
|
#### Info
|
|
@@ -148,11 +157,11 @@ Dynamic: summary
|
|
|
148
157
|
|___||_| |____/ | .__/ \___/ \__|
|
|
149
158
|
|_|
|
|
150
159
|
|
|
151
|
-
__ __ ___
|
|
152
|
-
\ \ / / _ / _ \
|
|
153
|
-
\ \ / / (_)| | | |
|
|
154
|
-
\ V / _ | |_| | _
|
|
155
|
-
\_/ (_) \___/ (_)|
|
|
160
|
+
__ __ ___ ____
|
|
161
|
+
\ \ / / _ / _ \ |___ \
|
|
162
|
+
\ \ / / (_)| | | | __) |
|
|
163
|
+
\ V / _ | |_| | _ / __/
|
|
164
|
+
\_/ (_) \___/ (_)|_____|
|
|
156
165
|
|
|
157
166
|
|
|
158
167
|
|
|
@@ -188,7 +197,7 @@ Public IP and Location Info:
|
|
|
188
197
|
|
|
189
198
|
#### IPv4 API
|
|
190
199
|
|
|
191
|
-
ℹ️ `ipv4-api` valid choices: [`auto`, `ipapi`, `ipinfo`]
|
|
200
|
+
ℹ️ `ipv4-api` valid choices: [`auto`, `ipapi`, `ipinfo`, `ipsb`]
|
|
192
201
|
|
|
193
202
|
ℹ️ The default value: `auto`
|
|
194
203
|
|
|
@@ -231,7 +240,12 @@ Public IP:
|
|
|
231
240
|
Just fill an issue and describe it. We'll check it ASAP!
|
|
232
241
|
|
|
233
242
|
- Please complete the issue template
|
|
234
|
-
|
|
243
|
+
|
|
244
|
+
You can also join our discord server
|
|
245
|
+
|
|
246
|
+
<a href="https://discord.gg/yyDV3T4cwU">
|
|
247
|
+
<img src="https://img.shields.io/discord/1064533716615049236.svg?style=for-the-badge" alt="Discord Channel">
|
|
248
|
+
</a>
|
|
235
249
|
|
|
236
250
|
## Show Your Support
|
|
237
251
|
|
|
@@ -253,6 +267,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|
|
253
267
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
254
268
|
|
|
255
269
|
## [Unreleased]
|
|
270
|
+
## [0.2] - 2025-05-04
|
|
271
|
+
### Added
|
|
272
|
+
- Support [ip.sb](https://api.ip.sb/geoip)
|
|
273
|
+
- `--timeout` argument
|
|
274
|
+
### Changed
|
|
275
|
+
- `README.md` updated
|
|
276
|
+
- Requests header updated
|
|
277
|
+
- Test system modified
|
|
256
278
|
## [0.1] - 2025-04-25
|
|
257
279
|
### Added
|
|
258
280
|
- Support [ipinfo.io](https://ipinfo.io)
|
|
@@ -264,7 +286,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
|
264
286
|
- `--no-geo` argument
|
|
265
287
|
- Logo
|
|
266
288
|
|
|
267
|
-
[Unreleased]: https://github.com/openscilab/ipspot/compare/v0.
|
|
289
|
+
[Unreleased]: https://github.com/openscilab/ipspot/compare/v0.2...dev
|
|
290
|
+
[0.2]: https://github.com/openscilab/ipspot/compare/v0.1...v0.2
|
|
268
291
|
[0.1]: https://github.com/openscilab/ipspot/compare/3216fb7...v0.1
|
|
269
292
|
|
|
270
293
|
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
<a href="https://badge.fury.io/py/ipspot"><img src="https://badge.fury.io/py/ipspot.svg" alt="PyPI version"></a>
|
|
6
6
|
<a href="https://www.python.org/"><img src="https://img.shields.io/badge/built%20with-Python3-green.svg" alt="built with Python3"></a>
|
|
7
7
|
<a href="https://github.com/openscilab/ipspot"><img alt="GitHub repo size" src="https://img.shields.io/github/repo-size/openscilab/ipspot"></a>
|
|
8
|
+
<a href="https://discord.gg/yyDV3T4cwU"><img src="https://img.shields.io/discord/1064533716615049236.svg" alt="Discord Channel"></a>
|
|
8
9
|
</div>
|
|
9
10
|
|
|
10
11
|
## Overview
|
|
@@ -39,17 +40,25 @@
|
|
|
39
40
|
</tr>
|
|
40
41
|
</table>
|
|
41
42
|
|
|
43
|
+
<table>
|
|
44
|
+
<tr>
|
|
45
|
+
<td align="center">Code Quality</td>
|
|
46
|
+
<td align="center"><a href="https://app.codacy.com/gh/openscilab/ipspot/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade"><img src="https://app.codacy.com/project/badge/Grade/cb2ab6584eb443b8a33da4d4252480bc"/></a></td>
|
|
47
|
+
<td align="center"><a href="https://www.codefactor.io/repository/github/openscilab/ipspot"><img src="https://www.codefactor.io/repository/github/openscilab/ipspot/badge" alt="CodeFactor"></a></td>
|
|
48
|
+
</tr>
|
|
49
|
+
</table>
|
|
50
|
+
|
|
42
51
|
|
|
43
52
|
## Installation
|
|
44
53
|
|
|
45
54
|
### Source Code
|
|
46
|
-
- Download [Version 0.
|
|
55
|
+
- Download [Version 0.2](https://github.com/openscilab/ipspot/archive/v0.2.zip) or [Latest Source](https://github.com/openscilab/ipspot/archive/dev.zip)
|
|
47
56
|
- `pip install .`
|
|
48
57
|
|
|
49
58
|
### PyPI
|
|
50
59
|
|
|
51
60
|
- Check [Python Packaging User Guide](https://packaging.python.org/installing/)
|
|
52
|
-
- `pip install ipspot==0.
|
|
61
|
+
- `pip install ipspot==0.2`
|
|
53
62
|
|
|
54
63
|
|
|
55
64
|
## Usage
|
|
@@ -62,7 +71,7 @@
|
|
|
62
71
|
>>> from ipspot import get_public_ipv4, IPv4API
|
|
63
72
|
>>> get_public_ipv4(api=IPv4API.IPAPI)
|
|
64
73
|
{'status': True, 'data': {'ip': 'xx.xx.xx.xx', 'api': 'ip-api.com'}}
|
|
65
|
-
>>> get_public_ipv4(api=IPv4API.IPAPI, geo=True)
|
|
74
|
+
>>> get_public_ipv4(api=IPv4API.IPAPI, geo=True, timeout=10)
|
|
66
75
|
{'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}
|
|
67
76
|
```
|
|
68
77
|
|
|
@@ -83,7 +92,7 @@
|
|
|
83
92
|
```console
|
|
84
93
|
> ipspot --version
|
|
85
94
|
|
|
86
|
-
0.
|
|
95
|
+
0.2
|
|
87
96
|
```
|
|
88
97
|
|
|
89
98
|
#### Info
|
|
@@ -98,11 +107,11 @@
|
|
|
98
107
|
|___||_| |____/ | .__/ \___/ \__|
|
|
99
108
|
|_|
|
|
100
109
|
|
|
101
|
-
__ __ ___
|
|
102
|
-
\ \ / / _ / _ \
|
|
103
|
-
\ \ / / (_)| | | |
|
|
104
|
-
\ V / _ | |_| | _
|
|
105
|
-
\_/ (_) \___/ (_)|
|
|
110
|
+
__ __ ___ ____
|
|
111
|
+
\ \ / / _ / _ \ |___ \
|
|
112
|
+
\ \ / / (_)| | | | __) |
|
|
113
|
+
\ V / _ | |_| | _ / __/
|
|
114
|
+
\_/ (_) \___/ (_)|_____|
|
|
106
115
|
|
|
107
116
|
|
|
108
117
|
|
|
@@ -138,7 +147,7 @@ Public IP and Location Info:
|
|
|
138
147
|
|
|
139
148
|
#### IPv4 API
|
|
140
149
|
|
|
141
|
-
ℹ️ `ipv4-api` valid choices: [`auto`, `ipapi`, `ipinfo`]
|
|
150
|
+
ℹ️ `ipv4-api` valid choices: [`auto`, `ipapi`, `ipinfo`, `ipsb`]
|
|
142
151
|
|
|
143
152
|
ℹ️ The default value: `auto`
|
|
144
153
|
|
|
@@ -181,7 +190,12 @@ Public IP:
|
|
|
181
190
|
Just fill an issue and describe it. We'll check it ASAP!
|
|
182
191
|
|
|
183
192
|
- Please complete the issue template
|
|
184
|
-
|
|
193
|
+
|
|
194
|
+
You can also join our discord server
|
|
195
|
+
|
|
196
|
+
<a href="https://discord.gg/yyDV3T4cwU">
|
|
197
|
+
<img src="https://img.shields.io/discord/1064533716615049236.svg?style=for-the-badge" alt="Discord Channel">
|
|
198
|
+
</a>
|
|
185
199
|
|
|
186
200
|
## Show Your Support
|
|
187
201
|
|
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
"""ipspot functions."""
|
|
3
3
|
import argparse
|
|
4
4
|
import socket
|
|
5
|
-
from typing import Union, Dict, Any
|
|
5
|
+
from typing import Union, Dict, Tuple, Any
|
|
6
6
|
import requests
|
|
7
7
|
from art import tprint
|
|
8
|
-
from .params import IPv4API, PARAMETERS_NAME_MAP
|
|
8
|
+
from .params import REQUEST_HEADERS, IPv4API, PARAMETERS_NAME_MAP
|
|
9
9
|
from .params import IPSPOT_OVERVIEW, IPSPOT_REPO, IPSPOT_VERSION
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
def ipspot_info() -> None:
|
|
12
|
+
def ipspot_info() -> None: # pragma: no cover
|
|
13
13
|
"""Print ipspot details."""
|
|
14
14
|
tprint("IPSpot")
|
|
15
15
|
tprint("V:" + IPSPOT_VERSION)
|
|
16
16
|
print(IPSPOT_OVERVIEW)
|
|
17
|
-
print(IPSPOT_REPO)
|
|
17
|
+
print("Repo : " + IPSPOT_REPO)
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
def get_private_ipv4() -> Dict[str, Union[bool, Dict[str, str], str]]:
|
|
@@ -27,14 +27,46 @@ def get_private_ipv4() -> Dict[str, Union[bool, Dict[str, str], str]]:
|
|
|
27
27
|
return {"status": False, "error": str(e)}
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
def
|
|
30
|
+
def _ipsb_ipv4(geo: bool=False, timeout: Union[float, Tuple[float, float]]
|
|
31
|
+
=5) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
32
|
+
"""
|
|
33
|
+
Get public IP and geolocation using ip.sb.
|
|
34
|
+
|
|
35
|
+
:param geo: geolocation flag
|
|
36
|
+
:param timeout: timeout value for API
|
|
37
|
+
"""
|
|
38
|
+
try:
|
|
39
|
+
response = requests.get("https://api.ip.sb/geoip", headers=REQUEST_HEADERS, timeout=timeout)
|
|
40
|
+
response.raise_for_status()
|
|
41
|
+
data = response.json()
|
|
42
|
+
result = {"status": True, "data": {"ip": data.get("ip"), "api": "ip.sb"}}
|
|
43
|
+
if geo:
|
|
44
|
+
geo_data = {
|
|
45
|
+
"city": data.get("city"),
|
|
46
|
+
"region": data.get("region"),
|
|
47
|
+
"country": data.get("country"),
|
|
48
|
+
"country_code": data.get("country_code"),
|
|
49
|
+
"latitude": data.get("latitude"),
|
|
50
|
+
"longitude": data.get("longitude"),
|
|
51
|
+
"organization": data.get("organization"),
|
|
52
|
+
"timezone": data.get("timezone")
|
|
53
|
+
}
|
|
54
|
+
result["data"].update(geo_data)
|
|
55
|
+
return result
|
|
56
|
+
except Exception as e:
|
|
57
|
+
return {"status": False, "error": str(e)}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _ipapi_ipv4(geo: bool=False, timeout: Union[float, Tuple[float, float]]
|
|
61
|
+
=5) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
31
62
|
"""
|
|
32
63
|
Get public IP and geolocation using ip-api.com.
|
|
33
64
|
|
|
34
65
|
:param geo: geolocation flag
|
|
66
|
+
:param timeout: timeout value for API
|
|
35
67
|
"""
|
|
36
68
|
try:
|
|
37
|
-
response = requests.get("http://ip-api.com/json/", timeout=
|
|
69
|
+
response = requests.get("http://ip-api.com/json/", headers=REQUEST_HEADERS, timeout=timeout)
|
|
38
70
|
response.raise_for_status()
|
|
39
71
|
data = response.json()
|
|
40
72
|
|
|
@@ -58,14 +90,16 @@ def _ipapi_ipv4(geo: bool=False) -> Dict[str, Union[bool, Dict[str, Union[str, f
|
|
|
58
90
|
return {"status": False, "error": str(e)}
|
|
59
91
|
|
|
60
92
|
|
|
61
|
-
def _ipinfo_ipv4(geo: bool=False
|
|
93
|
+
def _ipinfo_ipv4(geo: bool=False, timeout: Union[float, Tuple[float, float]]
|
|
94
|
+
=5) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
62
95
|
"""
|
|
63
96
|
Get public IP and geolocation using ipinfo.io.
|
|
64
97
|
|
|
65
98
|
:param geo: geolocation flag
|
|
99
|
+
:param timeout: timeout value for API
|
|
66
100
|
"""
|
|
67
101
|
try:
|
|
68
|
-
response = requests.get("https://ipinfo.io/json", timeout=
|
|
102
|
+
response = requests.get("https://ipinfo.io/json", headers=REQUEST_HEADERS, timeout=timeout)
|
|
69
103
|
response.raise_for_status()
|
|
70
104
|
data = response.json()
|
|
71
105
|
result = {"status": True, "data": {"ip": data.get("ip"), "api": "ipinfo.io"}}
|
|
@@ -87,29 +121,31 @@ def _ipinfo_ipv4(geo: bool=False) -> Dict[str, Union[bool, Dict[str, Union[str,
|
|
|
87
121
|
return {"status": False, "error": str(e)}
|
|
88
122
|
|
|
89
123
|
|
|
90
|
-
def get_public_ipv4(api: IPv4API=IPv4API.AUTO,
|
|
91
|
-
|
|
124
|
+
def get_public_ipv4(api: IPv4API=IPv4API.AUTO, geo: bool=False,
|
|
125
|
+
timeout: Union[float, Tuple[float, float]]=5) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
|
|
92
126
|
"""
|
|
93
127
|
Get public IPv4 and geolocation info based on the selected API.
|
|
94
128
|
|
|
95
129
|
:param api: public IPv4 API
|
|
96
130
|
:param geo: geolocation flag
|
|
131
|
+
:param timeout: timeout value for API
|
|
97
132
|
"""
|
|
98
133
|
api_map = {
|
|
99
134
|
IPv4API.IPAPI: _ipapi_ipv4,
|
|
100
135
|
IPv4API.IPINFO: _ipinfo_ipv4,
|
|
136
|
+
IPv4API.IPSB: _ipsb_ipv4
|
|
101
137
|
}
|
|
102
138
|
|
|
103
139
|
if api == IPv4API.AUTO:
|
|
104
140
|
for _, func in api_map.items():
|
|
105
|
-
result = func(geo=geo)
|
|
141
|
+
result = func(geo=geo, timeout=timeout)
|
|
106
142
|
if result["status"]:
|
|
107
143
|
return result
|
|
108
144
|
return {"status": False, "error": "All attempts failed."}
|
|
109
145
|
else:
|
|
110
146
|
func = api_map.get(api)
|
|
111
147
|
if func:
|
|
112
|
-
return func(geo=geo)
|
|
148
|
+
return func(geo=geo, timeout=timeout)
|
|
113
149
|
return {"status": False, "error": "Unsupported API: {api}".format(api=api)}
|
|
114
150
|
|
|
115
151
|
|
|
@@ -126,12 +162,14 @@ def filter_parameter(parameter: Any) -> Any:
|
|
|
126
162
|
return parameter
|
|
127
163
|
|
|
128
164
|
|
|
129
|
-
def display_ip_info(ipv4_api: IPv4API = IPv4API.AUTO, geo: bool=False
|
|
165
|
+
def display_ip_info(ipv4_api: IPv4API = IPv4API.AUTO, geo: bool=False,
|
|
166
|
+
timeout: Union[float, Tuple[float, float]]=5) -> None: # pragma: no cover
|
|
130
167
|
"""
|
|
131
168
|
Print collected IP and location data.
|
|
132
169
|
|
|
133
170
|
:param ipv4_api: public IPv4 API
|
|
134
171
|
:param geo: geolocation flag
|
|
172
|
+
:param timeout: timeout value for API
|
|
135
173
|
"""
|
|
136
174
|
private_result = get_private_ipv4()
|
|
137
175
|
print("Private IP:\n")
|
|
@@ -143,7 +181,7 @@ def display_ip_info(ipv4_api: IPv4API = IPv4API.AUTO, geo: bool=False) -> None:
|
|
|
143
181
|
public_title += " and Location Info"
|
|
144
182
|
public_title += ":\n"
|
|
145
183
|
print(public_title)
|
|
146
|
-
public_result = get_public_ipv4(ipv4_api, geo=geo)
|
|
184
|
+
public_result = get_public_ipv4(ipv4_api, geo=geo, timeout=timeout)
|
|
147
185
|
if public_result["status"]:
|
|
148
186
|
for name, parameter in sorted(public_result["data"].items()):
|
|
149
187
|
print(
|
|
@@ -154,7 +192,7 @@ def display_ip_info(ipv4_api: IPv4API = IPv4API.AUTO, geo: bool=False) -> None:
|
|
|
154
192
|
print(" Error: {public_result[error]}".format(public_result=public_result))
|
|
155
193
|
|
|
156
194
|
|
|
157
|
-
def main() -> None:
|
|
195
|
+
def main() -> None: # pragma: no cover
|
|
158
196
|
"""CLI main function."""
|
|
159
197
|
parser = argparse.ArgumentParser()
|
|
160
198
|
parser.add_argument(
|
|
@@ -167,6 +205,7 @@ def main() -> None:
|
|
|
167
205
|
parser.add_argument('--info', help='info', nargs="?", const=1)
|
|
168
206
|
parser.add_argument('--version', help='version', nargs="?", const=1)
|
|
169
207
|
parser.add_argument('--no-geo', help='no geolocation data', nargs="?", const=1, default=False)
|
|
208
|
+
parser.add_argument('--timeout', help='timeout for the API request', type=float, default=5.0)
|
|
170
209
|
|
|
171
210
|
args = parser.parse_args()
|
|
172
211
|
if args.version:
|
|
@@ -176,4 +215,4 @@ def main() -> None:
|
|
|
176
215
|
else:
|
|
177
216
|
ipv4_api = IPv4API(args.ipv4_api)
|
|
178
217
|
geo = not args.no_geo
|
|
179
|
-
display_ip_info(ipv4_api=ipv4_api, geo=geo)
|
|
218
|
+
display_ip_info(ipv4_api=ipv4_api, geo=geo, timeout=args.timeout)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"""ipspot params."""
|
|
3
3
|
from enum import Enum
|
|
4
4
|
|
|
5
|
-
IPSPOT_VERSION = "0.
|
|
5
|
+
IPSPOT_VERSION = "0.2"
|
|
6
6
|
|
|
7
7
|
IPSPOT_OVERVIEW = '''
|
|
8
8
|
IPSpot is a Python library for retrieving the current system's IP address and location information.
|
|
@@ -10,7 +10,12 @@ It currently supports public and private IPv4 detection using multiple API provi
|
|
|
10
10
|
Designed with simplicity and modularity in mind, IPSpot offers quick IP and geolocation lookups directly from your machine.
|
|
11
11
|
'''
|
|
12
12
|
|
|
13
|
-
IPSPOT_REPO = "
|
|
13
|
+
IPSPOT_REPO = "https://github.com/openscilab/ipspot"
|
|
14
|
+
|
|
15
|
+
REQUEST_HEADERS = {
|
|
16
|
+
'User-Agent': 'IPSpot/{version} ({repo})'.format(version=IPSPOT_VERSION, repo=IPSPOT_REPO),
|
|
17
|
+
'Accept': 'application/json'
|
|
18
|
+
}
|
|
14
19
|
|
|
15
20
|
|
|
16
21
|
class IPv4API(Enum):
|
|
@@ -19,6 +24,7 @@ class IPv4API(Enum):
|
|
|
19
24
|
AUTO = "auto"
|
|
20
25
|
IPAPI = "ipapi"
|
|
21
26
|
IPINFO = "ipinfo"
|
|
27
|
+
IPSB = "ipsb"
|
|
22
28
|
|
|
23
29
|
|
|
24
30
|
PARAMETERS_NAME_MAP = {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ipspot
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2
|
|
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.2
|
|
7
7
|
Author: IPSpot Development Team
|
|
8
8
|
Author-email: ipspot@openscilab.com
|
|
9
9
|
License: MIT
|
|
@@ -55,6 +55,7 @@ Dynamic: summary
|
|
|
55
55
|
<a href="https://badge.fury.io/py/ipspot"><img src="https://badge.fury.io/py/ipspot.svg" alt="PyPI version"></a>
|
|
56
56
|
<a href="https://www.python.org/"><img src="https://img.shields.io/badge/built%20with-Python3-green.svg" alt="built with Python3"></a>
|
|
57
57
|
<a href="https://github.com/openscilab/ipspot"><img alt="GitHub repo size" src="https://img.shields.io/github/repo-size/openscilab/ipspot"></a>
|
|
58
|
+
<a href="https://discord.gg/yyDV3T4cwU"><img src="https://img.shields.io/discord/1064533716615049236.svg" alt="Discord Channel"></a>
|
|
58
59
|
</div>
|
|
59
60
|
|
|
60
61
|
## Overview
|
|
@@ -89,17 +90,25 @@ Dynamic: summary
|
|
|
89
90
|
</tr>
|
|
90
91
|
</table>
|
|
91
92
|
|
|
93
|
+
<table>
|
|
94
|
+
<tr>
|
|
95
|
+
<td align="center">Code Quality</td>
|
|
96
|
+
<td align="center"><a href="https://app.codacy.com/gh/openscilab/ipspot/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade"><img src="https://app.codacy.com/project/badge/Grade/cb2ab6584eb443b8a33da4d4252480bc"/></a></td>
|
|
97
|
+
<td align="center"><a href="https://www.codefactor.io/repository/github/openscilab/ipspot"><img src="https://www.codefactor.io/repository/github/openscilab/ipspot/badge" alt="CodeFactor"></a></td>
|
|
98
|
+
</tr>
|
|
99
|
+
</table>
|
|
100
|
+
|
|
92
101
|
|
|
93
102
|
## Installation
|
|
94
103
|
|
|
95
104
|
### Source Code
|
|
96
|
-
- Download [Version 0.
|
|
105
|
+
- Download [Version 0.2](https://github.com/openscilab/ipspot/archive/v0.2.zip) or [Latest Source](https://github.com/openscilab/ipspot/archive/dev.zip)
|
|
97
106
|
- `pip install .`
|
|
98
107
|
|
|
99
108
|
### PyPI
|
|
100
109
|
|
|
101
110
|
- Check [Python Packaging User Guide](https://packaging.python.org/installing/)
|
|
102
|
-
- `pip install ipspot==0.
|
|
111
|
+
- `pip install ipspot==0.2`
|
|
103
112
|
|
|
104
113
|
|
|
105
114
|
## Usage
|
|
@@ -112,7 +121,7 @@ Dynamic: summary
|
|
|
112
121
|
>>> from ipspot import get_public_ipv4, IPv4API
|
|
113
122
|
>>> get_public_ipv4(api=IPv4API.IPAPI)
|
|
114
123
|
{'status': True, 'data': {'ip': 'xx.xx.xx.xx', 'api': 'ip-api.com'}}
|
|
115
|
-
>>> get_public_ipv4(api=IPv4API.IPAPI, geo=True)
|
|
124
|
+
>>> get_public_ipv4(api=IPv4API.IPAPI, geo=True, timeout=10)
|
|
116
125
|
{'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}
|
|
117
126
|
```
|
|
118
127
|
|
|
@@ -133,7 +142,7 @@ Dynamic: summary
|
|
|
133
142
|
```console
|
|
134
143
|
> ipspot --version
|
|
135
144
|
|
|
136
|
-
0.
|
|
145
|
+
0.2
|
|
137
146
|
```
|
|
138
147
|
|
|
139
148
|
#### Info
|
|
@@ -148,11 +157,11 @@ Dynamic: summary
|
|
|
148
157
|
|___||_| |____/ | .__/ \___/ \__|
|
|
149
158
|
|_|
|
|
150
159
|
|
|
151
|
-
__ __ ___
|
|
152
|
-
\ \ / / _ / _ \
|
|
153
|
-
\ \ / / (_)| | | |
|
|
154
|
-
\ V / _ | |_| | _
|
|
155
|
-
\_/ (_) \___/ (_)|
|
|
160
|
+
__ __ ___ ____
|
|
161
|
+
\ \ / / _ / _ \ |___ \
|
|
162
|
+
\ \ / / (_)| | | | __) |
|
|
163
|
+
\ V / _ | |_| | _ / __/
|
|
164
|
+
\_/ (_) \___/ (_)|_____|
|
|
156
165
|
|
|
157
166
|
|
|
158
167
|
|
|
@@ -188,7 +197,7 @@ Public IP and Location Info:
|
|
|
188
197
|
|
|
189
198
|
#### IPv4 API
|
|
190
199
|
|
|
191
|
-
ℹ️ `ipv4-api` valid choices: [`auto`, `ipapi`, `ipinfo`]
|
|
200
|
+
ℹ️ `ipv4-api` valid choices: [`auto`, `ipapi`, `ipinfo`, `ipsb`]
|
|
192
201
|
|
|
193
202
|
ℹ️ The default value: `auto`
|
|
194
203
|
|
|
@@ -231,7 +240,12 @@ Public IP:
|
|
|
231
240
|
Just fill an issue and describe it. We'll check it ASAP!
|
|
232
241
|
|
|
233
242
|
- Please complete the issue template
|
|
234
|
-
|
|
243
|
+
|
|
244
|
+
You can also join our discord server
|
|
245
|
+
|
|
246
|
+
<a href="https://discord.gg/yyDV3T4cwU">
|
|
247
|
+
<img src="https://img.shields.io/discord/1064533716615049236.svg?style=for-the-badge" alt="Discord Channel">
|
|
248
|
+
</a>
|
|
235
249
|
|
|
236
250
|
## Show Your Support
|
|
237
251
|
|
|
@@ -253,6 +267,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|
|
253
267
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
254
268
|
|
|
255
269
|
## [Unreleased]
|
|
270
|
+
## [0.2] - 2025-05-04
|
|
271
|
+
### Added
|
|
272
|
+
- Support [ip.sb](https://api.ip.sb/geoip)
|
|
273
|
+
- `--timeout` argument
|
|
274
|
+
### Changed
|
|
275
|
+
- `README.md` updated
|
|
276
|
+
- Requests header updated
|
|
277
|
+
- Test system modified
|
|
256
278
|
## [0.1] - 2025-04-25
|
|
257
279
|
### Added
|
|
258
280
|
- Support [ipinfo.io](https://ipinfo.io)
|
|
@@ -264,7 +286,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
|
264
286
|
- `--no-geo` argument
|
|
265
287
|
- Logo
|
|
266
288
|
|
|
267
|
-
[Unreleased]: https://github.com/openscilab/ipspot/compare/v0.
|
|
289
|
+
[Unreleased]: https://github.com/openscilab/ipspot/compare/v0.2...dev
|
|
290
|
+
[0.2]: https://github.com/openscilab/ipspot/compare/v0.1...v0.2
|
|
268
291
|
[0.1]: https://github.com/openscilab/ipspot/compare/3216fb7...v0.1
|
|
269
292
|
|
|
270
293
|
|
|
@@ -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.2',
|
|
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.2',
|
|
44
44
|
keywords="ip ipv4 geo geolocation network location ipspot cli",
|
|
45
45
|
project_urls={
|
|
46
46
|
'Source': 'https://github.com/openscilab/ipspot'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from ipspot.functions import filter_parameter
|
|
2
|
+
|
|
3
|
+
TEST_CASE_NAME = "Functions tests"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_filter_parameter1():
|
|
7
|
+
assert filter_parameter(None) == "N/A"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_filter_parameter2():
|
|
11
|
+
assert filter_parameter("") == "N/A"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_filter_parameter3():
|
|
15
|
+
assert filter_parameter(" ") == "N/A"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_filter_parameter4():
|
|
19
|
+
assert filter_parameter("GB") == "GB"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from unittest import mock
|
|
3
|
+
from ipspot import get_private_ipv4
|
|
4
|
+
from ipspot import get_public_ipv4, IPv4API
|
|
5
|
+
|
|
6
|
+
TEST_CASE_NAME = "IPv4 tests"
|
|
7
|
+
IPV4_REGEX = re.compile(r'^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$')
|
|
8
|
+
DATA_ITEMS = {'country_code', 'latitude', 'longitude', 'api', 'country', 'timezone', 'organization', 'region', 'ip', 'city'}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_private_ipv4_success():
|
|
12
|
+
result = get_private_ipv4()
|
|
13
|
+
assert result["status"]
|
|
14
|
+
assert IPV4_REGEX.match(result["data"]["ip"])
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_private_ipv4_error():
|
|
18
|
+
with mock.patch("socket.gethostbyname", side_effect=Exception("Test error")):
|
|
19
|
+
result = get_private_ipv4()
|
|
20
|
+
assert not result["status"]
|
|
21
|
+
assert result["error"] == "Test error"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_public_ipv4_auto_success():
|
|
25
|
+
result = get_public_ipv4(api=IPv4API.AUTO, geo=True)
|
|
26
|
+
assert result["status"]
|
|
27
|
+
assert IPV4_REGEX.match(result["data"]["ip"])
|
|
28
|
+
assert set(result["data"].keys()) == DATA_ITEMS
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_public_ipv4_auto_timeout_error():
|
|
32
|
+
result = get_public_ipv4(api=IPv4API.AUTO, geo=True, timeout="5")
|
|
33
|
+
assert not result["status"]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_public_ipv4_auto_net_error():
|
|
37
|
+
with mock.patch("requests.get", side_effect=Exception("No Internet")):
|
|
38
|
+
result = get_public_ipv4(api=IPv4API.AUTO)
|
|
39
|
+
assert not result["status"]
|
|
40
|
+
assert result["error"] == "All attempts failed."
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_public_ipv4_ipapi_success():
|
|
44
|
+
result = get_public_ipv4(api=IPv4API.IPAPI, geo=True)
|
|
45
|
+
assert result["status"]
|
|
46
|
+
assert IPV4_REGEX.match(result["data"]["ip"])
|
|
47
|
+
assert set(result["data"].keys()) == DATA_ITEMS
|
|
48
|
+
assert result["data"]["api"] == "ip-api.com"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_public_ipv4_ipapi_timeout_error():
|
|
52
|
+
result = get_public_ipv4(api=IPv4API.IPAPI, geo=True, timeout="5")
|
|
53
|
+
assert not result["status"]
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_public_ipv4_ipapi_net_error():
|
|
57
|
+
with mock.patch("requests.get", side_effect=Exception("No Internet")):
|
|
58
|
+
result = get_public_ipv4(api=IPv4API.IPAPI)
|
|
59
|
+
assert not result["status"]
|
|
60
|
+
assert result["error"] == "No Internet"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_public_ipv4_ipinfo_success():
|
|
64
|
+
result = get_public_ipv4(api=IPv4API.IPINFO, geo=True)
|
|
65
|
+
assert result["status"]
|
|
66
|
+
assert IPV4_REGEX.match(result["data"]["ip"])
|
|
67
|
+
assert set(result["data"].keys()) == DATA_ITEMS
|
|
68
|
+
assert result["data"]["api"] == "ipinfo.io"
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_public_ipv4_ipinfo_timeout_error():
|
|
72
|
+
result = get_public_ipv4(api=IPv4API.IPINFO, geo=True, timeout="5")
|
|
73
|
+
assert not result["status"]
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def test_public_ipv4_ipinfo_net_error():
|
|
77
|
+
with mock.patch("requests.get", side_effect=Exception("No Internet")):
|
|
78
|
+
result = get_public_ipv4(api=IPv4API.IPINFO)
|
|
79
|
+
assert not result["status"]
|
|
80
|
+
assert result["error"] == "No Internet"
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_public_ipv4_ipsb_success():
|
|
84
|
+
result = get_public_ipv4(api=IPv4API.IPSB, geo=True)
|
|
85
|
+
assert result["status"]
|
|
86
|
+
assert IPV4_REGEX.match(result["data"]["ip"])
|
|
87
|
+
assert set(result["data"].keys()) == DATA_ITEMS
|
|
88
|
+
assert result["data"]["api"] == "ip.sb"
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def test_public_ipv4_ipsb_timeout_error():
|
|
92
|
+
result = get_public_ipv4(api=IPv4API.IPSB, geo=True, timeout="5")
|
|
93
|
+
assert not result["status"]
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def test_public_ipv4_ipsb_net_error():
|
|
98
|
+
with mock.patch("requests.get", side_effect=Exception("No Internet")):
|
|
99
|
+
result = get_public_ipv4(api=IPv4API.IPSB)
|
|
100
|
+
assert not result["status"]
|
|
101
|
+
assert result["error"] == "No Internet"
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def test_public_ipv4_api_error():
|
|
105
|
+
result = get_public_ipv4(api="api1", geo=True)
|
|
106
|
+
assert not result["status"]
|
|
107
|
+
assert result["error"] == "Unsupported API: api1"
|
|
108
|
+
|
|
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
|