ipspot 0.6__py3-none-any.whl → 0.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
ipspot/cli.py CHANGED
@@ -8,9 +8,11 @@ from .ipv6 import get_public_ipv6, get_private_ipv6
8
8
  from .utils import _filter_parameter
9
9
  from .params import IPv4API, IPv6API, PARAMETERS_NAME_MAP
10
10
  from .params import IPSPOT_OVERVIEW, IPSPOT_REPO, IPSPOT_VERSION
11
+ from .params import PUBLIC_IPV4_ERROR, PRIVATE_IPV4_ERROR
12
+ from .params import PUBLIC_IPV6_ERROR, PRIVATE_IPV6_ERROR
11
13
 
12
14
 
13
- def ipspot_info() -> None: # pragma: no cover
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 display_ip_info(ipv4_api: IPv4API = IPv4API.AUTO_SAFE,
22
- ipv6_api: IPv6API = IPv6API.AUTO_SAFE,
23
- geo: bool=False,
24
- timeout: Union[float, Tuple[float, float]]=5,
25
- max_retries: int = 0, retry_delay: float = 1.0) -> None: # pragma: no cover
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 = private_ipv4_result["error"]
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 = private_ipv6_result["error"]
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[error]}".format(public_ipv4_result=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[error]}".format(public_ipv6_result=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
- ipspot_info()
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
- display_ip_info(
130
+ _print_report(
123
131
  ipv4_api=ipv4_api,
124
132
  ipv6_api=ipv6_api,
125
133
  geo=geo,
126
134
  timeout=args.timeout,
127
135
  max_retries=args.max_retries,
128
- retry_delay=args.retry_delay)
136
+ retry_delay=args.retry_delay,
137
+ backoff_factor=args.backoff_factor)
ipspot/ipv4.py CHANGED
@@ -36,8 +36,8 @@ def get_private_ipv4() -> Dict[str, Union[bool, Dict[str, str], str]]:
36
36
  return {"status": False, "error": str(e)}
37
37
 
38
38
 
39
- def _ip_sb_ipv4(geo: bool=False, timeout: Union[float, Tuple[float, float]]
40
- =5) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
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=False, timeout: Union[float, Tuple[float, float]]
68
- =5) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
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=False, timeout: Union[float, Tuple[float, float]]
96
- =5) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
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
- def _ifconfig_co_ipv4(geo: bool=False, timeout: Union[float, Tuple[float, float]] # very low rate limit
124
- =5) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
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=False, timeout: Union[float, Tuple[float, float]]
152
- =5) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
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=False, timeout: Union[float, Tuple[float, float]]
180
- =5) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
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=False, timeout: Union[float, Tuple[float, float]]
210
- =5) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
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(geo: bool=False, timeout: Union[float, Tuple[float, float]]
239
- =5) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
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=False, timeout: Union[float, Tuple[float, float]]
267
- =5) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
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=False, timeout: Union[float, Tuple[float, float]]
295
- =5) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
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=False, timeout: Union[float, Tuple[float, float]]=5
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=False, timeout: Union[float, Tuple[float, float]]=5
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=False, timeout: Union[float, Tuple[float, float]]=5
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=False, timeout: Union[float, Tuple[float, float]]=5
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=False, timeout: Union[float, Tuple[float, float]]=5
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.
@@ -465,6 +466,62 @@ def _wtfismyip_com_ipv4(geo: bool=False, timeout: Union[float, Tuple[float, floa
465
466
  return {"status": False, "error": str(e)}
466
467
 
467
468
 
469
+ def _myip_wtf_ipv4(geo: bool, timeout: Union[float, Tuple[float, float]]
470
+ ) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
471
+ """
472
+ Get public IP and geolocation using myip.wtf.
473
+
474
+ :param geo: geolocation flag
475
+ :param timeout: timeout value for API
476
+ """
477
+ try:
478
+ data = _get_json_standard(url="https://json.ipv4.myip.wtf", timeout=timeout)
479
+ result = {"status": True, "data": {"ip": data["YourFuckingIPAddress"], "api": "myip.wtf"}}
480
+ if geo:
481
+ geo_data = {
482
+ "city": data.get("YourFuckingCity"),
483
+ "region": None,
484
+ "country": data.get("YourFuckingCountry"),
485
+ "country_code": data.get("YourFuckingCountryCode"),
486
+ "latitude": None,
487
+ "longitude": None,
488
+ "organization": data.get("YourFuckingISP"),
489
+ "timezone": None
490
+ }
491
+ result["data"].update(geo_data)
492
+ return result
493
+ except Exception as e:
494
+ return {"status": False, "error": str(e)}
495
+
496
+
497
+ def _db_ip_com_ipv4(geo: bool, timeout: Union[float, Tuple[float, float]]
498
+ ) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
499
+ """
500
+ Get public IP and geolocation using db-ip.com.
501
+
502
+ :param geo: geolocation flag
503
+ :param timeout: timeout value for API
504
+ """
505
+ try:
506
+ data = _get_json_force_ip(url="https://api.db-ip.com/v2/free/self", timeout=timeout, version="ipv4")
507
+ result = {"status": True, "data": {"ip": data["ipAddress"], "api": "db-ip.com"}}
508
+ if geo:
509
+ geo_data = {
510
+ "city": data.get("city"),
511
+ "region": data.get("stateProv"),
512
+ "country": data.get("countryName"),
513
+ "country_code": data.get("countryCode"),
514
+ "latitude": None, # not provided by free API
515
+ "longitude": None, # not provided by free API
516
+ "organization": None, # not provided by free API
517
+ "timezone": None # not provided by free API
518
+ }
519
+ result["data"].update(geo_data)
520
+ return result
521
+ except Exception as e:
522
+ return {"status": False, "error": str(e)}
523
+
524
+
468
525
  IPV4_API_MAP = {
469
526
  IPv4API.IFCONFIG_CO: {
470
527
  "thread_safe": False,
@@ -541,13 +598,24 @@ IPV4_API_MAP = {
541
598
  "geo": True,
542
599
  "function": _wtfismyip_com_ipv4
543
600
  },
601
+ IPv4API.MYIP_WTF: {
602
+ "thread_safe": True,
603
+ "geo": True,
604
+ "function": _myip_wtf_ipv4
605
+ },
606
+ IPv4API.DB_IP_COM: {
607
+ "thread_safe": False,
608
+ "geo": True,
609
+ "function": _db_ip_com_ipv4
610
+ },
544
611
  }
545
612
 
546
613
 
547
- def get_public_ipv4(api: IPv4API=IPv4API.AUTO_SAFE, geo: bool=False,
548
- timeout: Union[float, Tuple[float, float]]=5,
614
+ def get_public_ipv4(api: IPv4API = IPv4API.AUTO_SAFE, geo: bool = False,
615
+ timeout: Union[float, Tuple[float, float]] = 5,
549
616
  max_retries: int = 0,
550
- retry_delay: float = 1.0) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
617
+ retry_delay: float = 1.0,
618
+ backoff_factor: float = 1.0) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
551
619
  """
552
620
  Get public IPv4 and geolocation info based on the selected API.
553
621
 
@@ -556,6 +624,7 @@ def get_public_ipv4(api: IPv4API=IPv4API.AUTO_SAFE, geo: bool=False,
556
624
  :param timeout: timeout value for API
557
625
  :param max_retries: number of retries
558
626
  :param retry_delay: delay between retries (in seconds)
627
+ :param backoff_factor: backoff factor
559
628
  """
560
629
  if api in [IPv4API.AUTO, IPv4API.AUTO_SAFE]:
561
630
  for _, api_data in IPV4_API_MAP.items():
@@ -566,6 +635,7 @@ def get_public_ipv4(api: IPv4API=IPv4API.AUTO_SAFE, geo: bool=False,
566
635
  func=func,
567
636
  max_retries=max_retries,
568
637
  retry_delay=retry_delay,
638
+ backoff_factor=backoff_factor,
569
639
  geo=geo,
570
640
  timeout=timeout)
571
641
  if result["status"]:
@@ -579,6 +649,7 @@ def get_public_ipv4(api: IPv4API=IPv4API.AUTO_SAFE, geo: bool=False,
579
649
  func=func,
580
650
  max_retries=max_retries,
581
651
  retry_delay=retry_delay,
652
+ backoff_factor=backoff_factor,
582
653
  geo=geo,
583
654
  timeout=timeout)
584
655
  return {"status": False, "error": "Unsupported API: {api}".format(api=api)}
ipspot/ipv6.py CHANGED
@@ -37,8 +37,8 @@ def get_private_ipv6() -> Dict[str, Union[bool, Dict[str, str], str]]:
37
37
  return {"status": False, "error": str(e)}
38
38
 
39
39
 
40
- def _ip_sb_ipv6(geo: bool=False, timeout: Union[float, Tuple[float, float]]
41
- =5) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
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=False, timeout: Union[float, Tuple[float, float]]
69
- =5) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
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=False, timeout: Union[float, Tuple[float, float]]
97
- =5) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
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=False, timeout: Union[float, Tuple[float, float]]
125
- =5) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
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=False, timeout: Union[float, Tuple[float, float]]
153
- =5) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
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
- def _ifconfig_co_ipv6(geo: bool=False, timeout: Union[float, Tuple[float, float]] # very low rate limit
181
- =5) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
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(geo: bool=False, timeout: Union[float, Tuple[float, float]]
209
- =5) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
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=False, timeout: Union[float, Tuple[float, float]]
237
- =5) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
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=False, timeout: Union[float, Tuple[float, float]]
266
- =5) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
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
 
@@ -291,6 +292,62 @@ def _freeipapi_com_ipv6(geo: bool=False, timeout: Union[float, Tuple[float, floa
291
292
  return {"status": False, "error": str(e)}
292
293
 
293
294
 
295
+ def _wtfismyip_com_ipv6(geo: bool, timeout: Union[float, Tuple[float, float]]
296
+ ) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
297
+ """
298
+ Get public IP and geolocation using wtfismyip.com.
299
+
300
+ :param geo: geolocation flag
301
+ :param timeout: timeout value for API
302
+ """
303
+ try:
304
+ data = _get_json_standard(url="https://json.ipv6.wtfismyip.com", timeout=timeout)
305
+ result = {"status": True, "data": {"ip": data["YourFuckingIPAddress"], "api": "wtfismyip.com"}}
306
+ if geo:
307
+ geo_data = {
308
+ "city": data.get("YourFuckingCity"),
309
+ "region": None,
310
+ "country": data.get("YourFuckingCountry"),
311
+ "country_code": data.get("YourFuckingCountryCode"),
312
+ "latitude": None,
313
+ "longitude": None,
314
+ "organization": data.get("YourFuckingISP"),
315
+ "timezone": None
316
+ }
317
+ result["data"].update(geo_data)
318
+ return result
319
+ except Exception as e:
320
+ return {"status": False, "error": str(e)}
321
+
322
+
323
+ def _myip_wtf_ipv6(geo: bool, timeout: Union[float, Tuple[float, float]]
324
+ ) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
325
+ """
326
+ Get public IP and geolocation using myip.wtf.
327
+
328
+ :param geo: geolocation flag
329
+ :param timeout: timeout value for API
330
+ """
331
+ try:
332
+ data = _get_json_standard(url="https://json.ipv6.myip.wtf", timeout=timeout)
333
+ result = {"status": True, "data": {"ip": data["YourFuckingIPAddress"], "api": "myip.wtf"}}
334
+ if geo:
335
+ geo_data = {
336
+ "city": data.get("YourFuckingCity"),
337
+ "region": None,
338
+ "country": data.get("YourFuckingCountry"),
339
+ "country_code": data.get("YourFuckingCountryCode"),
340
+ "latitude": None,
341
+ "longitude": None,
342
+ "organization": data.get("YourFuckingISP"),
343
+ "timezone": None
344
+ }
345
+ result["data"].update(geo_data)
346
+ return result
347
+ except Exception as e:
348
+ return {"status": False, "error": str(e)}
349
+
350
+
294
351
  IPV6_API_MAP = {
295
352
  IPv6API.IP_SB: {
296
353
  "thread_safe": True,
@@ -336,14 +393,25 @@ IPV6_API_MAP = {
336
393
  "thread_safe": False,
337
394
  "geo": True,
338
395
  "function": _freeipapi_com_ipv6
339
- }
396
+ },
397
+ IPv6API.WTFISMYIP_COM: {
398
+ "thread_safe": True,
399
+ "geo": True,
400
+ "function": _wtfismyip_com_ipv6
401
+ },
402
+ IPv6API.MYIP_WTF: {
403
+ "thread_safe": True,
404
+ "geo": True,
405
+ "function": _myip_wtf_ipv6
406
+ },
340
407
  }
341
408
 
342
409
 
343
- def get_public_ipv6(api: IPv6API=IPv6API.AUTO_SAFE, geo: bool=False,
344
- timeout: Union[float, Tuple[float, float]]=5,
410
+ def get_public_ipv6(api: IPv6API = IPv6API.AUTO_SAFE, geo: bool = False,
411
+ timeout: Union[float, Tuple[float, float]] = 5,
345
412
  max_retries: int = 0,
346
- retry_delay: float = 1.0) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
413
+ retry_delay: float = 1.0,
414
+ backoff_factor: float = 1.0) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
347
415
  """
348
416
  Get public IPv6 and geolocation info based on the selected API.
349
417
 
@@ -352,6 +420,7 @@ def get_public_ipv6(api: IPv6API=IPv6API.AUTO_SAFE, geo: bool=False,
352
420
  :param timeout: timeout value for API
353
421
  :param max_retries: number of retries
354
422
  :param retry_delay: delay between retries (in seconds)
423
+ :param backoff_factor: backoff factor
355
424
  """
356
425
  if api in [IPv6API.AUTO, IPv6API.AUTO_SAFE]:
357
426
  for _, api_data in IPV6_API_MAP.items():
@@ -362,6 +431,7 @@ def get_public_ipv6(api: IPv6API=IPv6API.AUTO_SAFE, geo: bool=False,
362
431
  func=func,
363
432
  max_retries=max_retries,
364
433
  retry_delay=retry_delay,
434
+ backoff_factor=backoff_factor,
365
435
  geo=geo,
366
436
  timeout=timeout)
367
437
  if result["status"]:
@@ -375,6 +445,7 @@ def get_public_ipv6(api: IPv6API=IPv6API.AUTO_SAFE, geo: bool=False,
375
445
  func=func,
376
446
  max_retries=max_retries,
377
447
  retry_delay=retry_delay,
448
+ backoff_factor=backoff_factor,
378
449
  geo=geo,
379
450
  timeout=timeout)
380
451
  return {"status": False, "error": "Unsupported API: {api}".format(api=api)}
ipspot/params.py CHANGED
@@ -2,12 +2,12 @@
2
2
  """ipspot params."""
3
3
  from enum import Enum
4
4
 
5
- IPSPOT_VERSION = "0.6"
5
+ IPSPOT_VERSION = "0.8"
6
6
 
7
7
  IPSPOT_OVERVIEW = '''
8
- IPSpot is a Python library for retrieving the current system's IP address and location information.
9
- It currently supports public and private IPv4 detection using multiple API providers with a fallback mechanism for reliability.
10
- Designed with simplicity and modularity in mind, IPSpot offers quick IP and geolocation lookups directly from your machine.
8
+ IPSpot is a Python library for retrieving the current system's IP data and detailed location information such as region, longitude, and latitude.
9
+ It supports both public and private IPv4 and IPv6 detection through multiple API providers, using a fallback mechanism for improved reliability.
10
+ It has a simple and modular design, making it easy to perform fast IP, geolocation, provider, and regional lookups directly from your machine.
11
11
  '''
12
12
 
13
13
  IPSPOT_REPO = "https://github.com/openscilab/ipspot"
@@ -38,6 +38,8 @@ class IPv4API(Enum):
38
38
  IPQUERY_IO = "ipquery.io"
39
39
  IPWHO_IS = "ipwho.is"
40
40
  WTFISMYIP_COM = "wtfismyip.com"
41
+ MYIP_WTF = "myip.wtf"
42
+ DB_IP_COM = "db-ip.com"
41
43
 
42
44
 
43
45
  class IPv6API(Enum):
@@ -54,6 +56,8 @@ class IPv6API(Enum):
54
56
  REALLYFREEGEOIP_ORG = "reallyfreegeoip.org"
55
57
  MYIP_LA = "myip.la"
56
58
  FREEIPAPI_COM = "freeipapi.com"
59
+ WTFISMYIP_COM = "wtfismyip.com"
60
+ MYIP_WTF = "myip.wtf"
57
61
 
58
62
 
59
63
  PARAMETERS_NAME_MAP = {
@@ -68,3 +72,8 @@ PARAMETERS_NAME_MAP = {
68
72
  "organization": "Organization",
69
73
  "api": "API"
70
74
  }
75
+
76
+ PUBLIC_IPV4_ERROR = "Unable to retrieve public IPv4 information."
77
+ PRIVATE_IPV4_ERROR = "Unable to retrieve private IPv4 address."
78
+ PUBLIC_IPV6_ERROR = "Unable to retrieve public IPv6 information."
79
+ PRIVATE_IPV6_ERROR = "Unable to retrieve private IPv6 address."
ipspot/utils.py CHANGED
@@ -74,22 +74,27 @@ def _get_json_force_ip(url: str, timeout: Union[float, Tuple[float, float]],
74
74
  def _attempt_with_retries(
75
75
  func: Callable,
76
76
  max_retries: int,
77
- retry_delay: float, **kwargs: dict) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
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(retry_delay)
96
+ time.sleep(next_delay)
97
+ next_delay *= backoff_factor
93
98
  return result
94
99
 
95
100
 
@@ -1,14 +1,14 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ipspot
3
- Version: 0.6
4
- Summary: IPSpot: A Python Tool to Fetch the System's IP Address
3
+ Version: 0.8
4
+ Summary: IPSpot: Retrieve IPv4/IPv6 Addresses with Geolocation Data
5
5
  Home-page: https://github.com/openscilab/ipspot
6
- Download-URL: https://github.com/openscilab/ipspot/tarball/v0.6
6
+ Download-URL: https://github.com/openscilab/ipspot/tarball/v0.8
7
7
  Author: IPSpot Development Team
8
8
  Author-email: ipspot@openscilab.com
9
9
  License: MIT
10
10
  Project-URL: Source, https://github.com/openscilab/ipspot
11
- Keywords: ip ipv4 geo geolocation network location ipspot cli
11
+ Keywords: ip ipv4 ipv6 geo geolocation network location ipspot cli
12
12
  Classifier: Development Status :: 4 - Beta
13
13
  Classifier: Natural Language :: English
14
14
  Classifier: License :: OSI Approved :: MIT License
@@ -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
@@ -50,7 +51,7 @@ Dynamic: summary
50
51
 
51
52
  <div align="center">
52
53
  <img src="https://github.com/openscilab/ipspot/raw/main/otherfiles/logo.png" width="350">
53
- <h1>IPSpot: A Python Tool to Fetch the System's IP Address</h1>
54
+ <h1>IPSpot: Retrieve IPv4/IPv6 Addresses with Geolocation Data</h1>
54
55
  <br/>
55
56
  <a href="https://codecov.io/gh/openscilab/ipspot"><img src="https://codecov.io/gh/openscilab/ipspot/graph/badge.svg?token=XCFKASULS8"></a>
56
57
  <a href="https://badge.fury.io/py/ipspot"><img src="https://badge.fury.io/py/ipspot.svg" alt="PyPI version"></a>
@@ -62,7 +63,7 @@ Dynamic: summary
62
63
  ## Overview
63
64
 
64
65
  <p align="justify">
65
- <b>IPSpot</b> is a Python library for retrieving the current system's IP address and location information. It currently supports public and private <b>IPv4</b> detection using multiple API providers with a fallback mechanism for reliability. Designed with simplicity and modularity in mind, <b>IPSpot</b> offers quick IP and geolocation lookups directly from your machine.
66
+ <b>IPSpot</b> is a Python library for retrieving the current system's IP data and detailed location information such as region, longitude, and latitude. It supports both public and private <b>IPv4</b> and <b>IPv6</b> detection through multiple API providers, using a fallback mechanism for improved reliability. It has a simple and modular design, making it easy to perform fast IP, geolocation, provider, and regional lookups directly from your machine.
66
67
  </p>
67
68
 
68
69
  <table>
@@ -103,13 +104,13 @@ Dynamic: summary
103
104
  ## Installation
104
105
 
105
106
  ### Source Code
106
- - Download [Version 0.6](https://github.com/openscilab/ipspot/archive/v0.6.zip) or [Latest Source](https://github.com/openscilab/ipspot/archive/dev.zip)
107
+ - Download [Version 0.8](https://github.com/openscilab/ipspot/archive/v0.8.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.6`
113
+ - `pip install ipspot==0.8`
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.6
169
+ 0.8
169
170
  ```
170
171
 
171
172
  #### Info
@@ -173,24 +174,24 @@ 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
- \ \ / / (_)| | | | | '_ \
184
+ __ __ ___ ___
185
+ \ \ / / _ / _ \ ( _ )
186
+ \ \ / / (_)| | | | / _ \
186
187
  \ V / _ | |_| | _ | (_) |
187
- \_/ (_) \___/ (_) \___/
188
+ \_/ (_) \___/ (_) \___/
188
189
 
189
190
 
190
191
 
191
- IPSpot is a Python library for retrieving the current system's IP address and location information.
192
- It currently supports public and private IPv4 detection using multiple API providers with a fallback mechanism for reliability.
193
- Designed with simplicity and modularity in mind, IPSpot offers quick IP and geolocation lookups directly from your machine.
192
+ IPSpot is a Python library for retrieving the current system's IP data and detailed location information such as region, longitude, and latitude.
193
+ It supports both public and private IPv4 and IPv6 detection through multiple API providers, using a fallback mechanism for improved reliability.
194
+ It has a simple and modular design, making it easy to perform fast IP, geolocation, provider, and regional lookups directly from your machine.
194
195
 
195
196
  Repo : https://github.com/openscilab/ipspot
196
197
 
@@ -237,7 +238,7 @@ Public IP and Location Info:
237
238
 
238
239
  #### IPv4 API
239
240
 
240
- ℹ️ `ipv4-api` valid choices: [`auto-safe`, `auto`, `ip-api.com`, `ipinfo.io`, `ip.sb`, `ident.me`, `tnedi.me`, `ipapi.co`, `ipleak.net`, `my-ip.io`, `ifconfig.co`, `reallyfreegeoip.org`, `freeipapi.com`, `myip.la`, `ipquery.io`, `ipwho.is`, `wtfismyip.com`]
241
+ ℹ️ `ipv4-api` valid choices: [`auto-safe`, `auto`, `ip-api.com`, `ipinfo.io`, `ip.sb`, `ident.me`, `tnedi.me`, `ipapi.co`, `ipleak.net`, `my-ip.io`, `ifconfig.co`, `reallyfreegeoip.org`, `freeipapi.com`, `myip.la`, `ipquery.io`, `ipwho.is`, `wtfismyip.com`, `myip.wtf`, `db-ip.com`]
241
242
 
242
243
  ℹ️ The default value: `auto-safe`
243
244
 
@@ -280,7 +281,7 @@ Public IP and Location Info:
280
281
 
281
282
  #### IPv6 API
282
283
 
283
- ℹ️ `ipv6-api` valid choices: [`auto-safe`, `auto`, `ip.sb`, `ident.me`, `tnedi.me`, `ipleak.net`, `my-ip.io`, `ifconfig.co`, `reallyfreegeoip.org`, `myip.la`, `freeipapi.com`]
284
+ ℹ️ `ipv6-api` valid choices: [`auto-safe`, `auto`, `ip.sb`, `ident.me`, `tnedi.me`, `ipleak.net`, `my-ip.io`, `ifconfig.co`, `reallyfreegeoip.org`, `myip.la`, `freeipapi.com`, `wtfismyip.com`, `myip.wtf`]
284
285
 
285
286
  ℹ️ The default value: `auto-safe`
286
287
 
@@ -376,6 +377,25 @@ 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.8] - 2026-02-05
381
+ ### Added
382
+ - Support [wtfismyip.com](https://wtfismyip.com/json) IPv6 API
383
+ - Support [myip.wtf](https://myip.wtf/) IPv6 API
384
+ - Support [myip.wtf](https://myip.wtf/) IPv4 API
385
+ - Support [db-ip.com](https://api.db-ip.com/v2/free/self) IPv4 API
386
+ ### Changed
387
+ - `README.md` updated
388
+ ## [0.7] - 2025-12-09
389
+ ### Added
390
+ - `--backoff-factor` argument
391
+ ### Changed
392
+ - CLI messages updated
393
+ - `Python 3.14` added to `test.yml`
394
+ - Internal functions default values removed
395
+ - `README.md` updated
396
+ - Test system modified
397
+ - `ipspot_info` function renamed to `_print_ipspot_info`
398
+ - `display_ip_info` function renamed to `_print_report`
379
399
  ## [0.6] - 2025-11-18
380
400
  ### Added
381
401
  - `ForceIPHTTPAdapter` class
@@ -468,7 +488,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
468
488
  - `--no-geo` argument
469
489
  - Logo
470
490
 
471
- [Unreleased]: https://github.com/openscilab/ipspot/compare/v0.6...dev
491
+ [Unreleased]: https://github.com/openscilab/ipspot/compare/v0.8...dev
492
+ [0.8]: https://github.com/openscilab/ipspot/compare/v0.7...v0.8
493
+ [0.7]: https://github.com/openscilab/ipspot/compare/v0.6...v0.7
472
494
  [0.6]: https://github.com/openscilab/ipspot/compare/v0.5...v0.6
473
495
  [0.5]: https://github.com/openscilab/ipspot/compare/v0.4...v0.5
474
496
  [0.4]: https://github.com/openscilab/ipspot/compare/v0.3...v0.4
@@ -0,0 +1,14 @@
1
+ ipspot/__init__.py,sha256=B47uAOAidLkXps1A4zDig6NN2kB3HcdMC20UOrrEfB4,281
2
+ ipspot/__main__.py,sha256=xKHY_tc94SWktkIHV0O9YADAHPZvT8yXOFSm_L2yMno,105
3
+ ipspot/cli.py,sha256=Y48HA_s6SrTCtjn-iAFNMplAARLwBUx8zpxesG0hARE,4980
4
+ ipspot/ipv4.py,sha256=QPTigPv5bIHX2FkCTZnnuq5-X4_i3_xRlk6d3U6VgfQ,24079
5
+ ipspot/ipv6.py,sha256=wKEOcfGA-y-nuygU9KhqzULzRejEqZ5Dfr_mjHndEoA,16485
6
+ ipspot/params.py,sha256=-j5WYVCWfa_Qdub5q8CELl1S8tq2wg7NbWbW4ilfE9o,2340
7
+ ipspot/utils.py,sha256=W3HJ61_KVtdg4gWr4m9xXblQc_E30rJoF1aKk36Zqzg,4591
8
+ ipspot-0.8.dist-info/licenses/AUTHORS.md,sha256=5ZvxP1KnuVkurB4psQDSqnqiAyn44q1aeiXUsnYgps4,411
9
+ ipspot-0.8.dist-info/licenses/LICENSE,sha256=0aOd4wzZRoSH_35UZXRHS7alPFTtuFEBJrajLuonEIw,1067
10
+ ipspot-0.8.dist-info/METADATA,sha256=QG5WjBJEl7Iz0V2MlmB5G0l_xreUHx79A_ApdrAEPVM,15986
11
+ ipspot-0.8.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
12
+ ipspot-0.8.dist-info/entry_points.txt,sha256=DJVLepYr8H3UcvWekU5Jy-tcr_xmWrphzgWGNOd3hlk,43
13
+ ipspot-0.8.dist-info/top_level.txt,sha256=v0WgE1z2iCy_bXU53fVcllwHLTvGNBIvq8u3KPC2_Sc,7
14
+ ipspot-0.8.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,14 +0,0 @@
1
- ipspot/__init__.py,sha256=B47uAOAidLkXps1A4zDig6NN2kB3HcdMC20UOrrEfB4,281
2
- ipspot/__main__.py,sha256=xKHY_tc94SWktkIHV0O9YADAHPZvT8yXOFSm_L2yMno,105
3
- ipspot/cli.py,sha256=MdyMh-9miuT8zQgklVrvsimaXnqD17sviWRJbUWlk58,4637
4
- ipspot/ipv4.py,sha256=ZTv4HFyyxpiF8X-N8Pgk9_aJ7f9T58SpuuB3UKS0WII,21571
5
- ipspot/ipv6.py,sha256=zqP_ImJQeKpVIhmGQZmPLJsOuviUNnVg70tVhk4UQU0,13991
6
- ipspot/params.py,sha256=UqhiD8ybTnxRpecZ9RudKXxXyD-j63z23b6Cqbv1LJs,1881
7
- ipspot/utils.py,sha256=wZxz6e14aDqK0g27AdiRMrbiz8pk4UfxZvbFRDZzhSI,4445
8
- ipspot-0.6.dist-info/licenses/AUTHORS.md,sha256=5ZvxP1KnuVkurB4psQDSqnqiAyn44q1aeiXUsnYgps4,411
9
- ipspot-0.6.dist-info/licenses/LICENSE,sha256=0aOd4wzZRoSH_35UZXRHS7alPFTtuFEBJrajLuonEIw,1067
10
- ipspot-0.6.dist-info/METADATA,sha256=tYTL9nqZZP5YhOzV0IE2Y0CkUAytt-7b_dXWAdUCO08,14879
11
- ipspot-0.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
12
- ipspot-0.6.dist-info/entry_points.txt,sha256=DJVLepYr8H3UcvWekU5Jy-tcr_xmWrphzgWGNOd3hlk,43
13
- ipspot-0.6.dist-info/top_level.txt,sha256=v0WgE1z2iCy_bXU53fVcllwHLTvGNBIvq8u3KPC2_Sc,7
14
- ipspot-0.6.dist-info/RECORD,,