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.
Files changed (29) hide show
  1. {ipspot-0.6 → ipspot-0.7}/CHANGELOG.md +13 -1
  2. {ipspot-0.6 → ipspot-0.7}/PKG-INFO +30 -17
  3. {ipspot-0.6 → ipspot-0.7}/README.md +14 -14
  4. {ipspot-0.6 → ipspot-0.7}/SECURITY.md +2 -2
  5. {ipspot-0.6 → ipspot-0.7}/ipspot/cli.py +24 -15
  6. {ipspot-0.6 → ipspot-0.7}/ipspot/ipv4.py +31 -26
  7. {ipspot-0.6 → ipspot-0.7}/ipspot/ipv6.py +24 -19
  8. {ipspot-0.6 → ipspot-0.7}/ipspot/params.py +6 -1
  9. {ipspot-0.6 → ipspot-0.7}/ipspot/utils.py +7 -2
  10. {ipspot-0.6 → ipspot-0.7}/ipspot.egg-info/PKG-INFO +30 -17
  11. {ipspot-0.6 → ipspot-0.7}/setup.py +3 -2
  12. {ipspot-0.6 → ipspot-0.7}/tests/test_ipv4_api.py +15 -15
  13. {ipspot-0.6 → ipspot-0.7}/tests/test_ipv6_api.py +10 -10
  14. {ipspot-0.6 → ipspot-0.7}/tests/test_utils.py +6 -6
  15. {ipspot-0.6 → ipspot-0.7}/AUTHORS.md +0 -0
  16. {ipspot-0.6 → ipspot-0.7}/LICENSE +0 -0
  17. {ipspot-0.6 → ipspot-0.7}/MANIFEST.in +0 -0
  18. {ipspot-0.6 → ipspot-0.7}/dev-requirements.txt +0 -0
  19. {ipspot-0.6 → ipspot-0.7}/ipspot/__init__.py +0 -0
  20. {ipspot-0.6 → ipspot-0.7}/ipspot/__main__.py +0 -0
  21. {ipspot-0.6 → ipspot-0.7}/ipspot.egg-info/SOURCES.txt +0 -0
  22. {ipspot-0.6 → ipspot-0.7}/ipspot.egg-info/dependency_links.txt +0 -0
  23. {ipspot-0.6 → ipspot-0.7}/ipspot.egg-info/entry_points.txt +0 -0
  24. {ipspot-0.6 → ipspot-0.7}/ipspot.egg-info/requires.txt +0 -0
  25. {ipspot-0.6 → ipspot-0.7}/ipspot.egg-info/top_level.txt +0 -0
  26. {ipspot-0.6 → ipspot-0.7}/requirements.txt +0 -0
  27. {ipspot-0.6 → ipspot-0.7}/setup.cfg +0 -0
  28. {ipspot-0.6 → ipspot-0.7}/tests/test_ipv4_functions.py +0 -0
  29. {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.6...dev
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.6
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
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.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.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.6`
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.6
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.6...dev
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.6](https://github.com/openscilab/ipspot/archive/v0.6.zip) or [Latest Source](https://github.com/openscilab/ipspot/archive/dev.zip)
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.6`
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.6
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
 
@@ -4,8 +4,8 @@
4
4
 
5
5
  | Version | Supported |
6
6
  | ------------- | ------------------ |
7
- | 0.6 | :white_check_mark: |
8
- | < 0.6 | :x: |
7
+ | 0.7 | :white_check_mark: |
8
+ | < 0.7 | :x: |
9
9
 
10
10
  ## Reporting a Vulnerability
11
11
 
@@ -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)
@@ -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.
@@ -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) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
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=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
 
@@ -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) -> Dict[str, Union[bool, Dict[str, Union[str, float]], str]]:
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.6"
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, **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,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ipspot
3
- Version: 0.6
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
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.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.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.6`
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.6
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.6...dev
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.6',
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.6',
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