Skip to content

Commit 6d926de

Browse files
committed
feat: initial Python SDK for ipdata.info (v0.1.0)
0 parents  commit 6d926de

20 files changed

Lines changed: 964 additions & 0 deletions

.github/workflows/ci.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: CI
2+
on:
3+
push:
4+
branches: [main]
5+
pull_request:
6+
jobs:
7+
test:
8+
runs-on: ubuntu-latest
9+
strategy:
10+
matrix:
11+
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
12+
steps:
13+
- uses: actions/checkout@v4
14+
- uses: actions/setup-python@v5
15+
with:
16+
python-version: ${{ matrix.python-version }}
17+
- run: python -m pip install -e .
18+
- run: python -m unittest discover -s tests -t . -v
19+
- name: Live smoke test
20+
run: IPDATA_LIVE=1 python -m unittest discover -s tests -t . -v -k test_live_lookup

.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
__pycache__/
2+
*.py[cod]
3+
*.egg-info/
4+
.eggs/
5+
build/
6+
dist/
7+
.venv/
8+
venv/
9+
.pytest_cache/
10+
.mypy_cache/
11+
.ruff_cache/
12+
.env

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Changelog
2+
3+
## [0.1.0] - 2026-07-08
4+
### Added
5+
- Initial release: `lookup`, `geo`, `asn`, `batch`, `asn_detail`,
6+
`asn_whois_history`, `asn_changes`, `threat_domain`, `threat_hash`,
7+
`threat_url`.
8+
- `IpDataError` typed error; `Client(api_key, base_url, timeout)` constructor.
9+
- Zero required runtime dependencies (stdlib `urllib`/`json` only).

CONTRIBUTING.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Contributing
2+
3+
Thanks for considering a contribution to `ipdatainfo`.
4+
5+
## Setup
6+
7+
```
8+
python3 -m venv .venv
9+
source .venv/bin/activate
10+
pip install -e ".[dev]"
11+
```
12+
13+
## Tests
14+
15+
```
16+
python -m unittest discover -s tests -t . -v
17+
```
18+
19+
To include the live smoke test against `https://ipdata.info` (requires network):
20+
21+
```
22+
IPDATA_LIVE=1 python -m unittest discover -s tests -t . -v
23+
```
24+
25+
## Pull requests
26+
27+
- Keep changes scoped and add/update tests for behavior changes.
28+
- Match the method surface in [`docs/sdk-api-contract.md`](https://github.com/IPDataInfo/ipdata-python)
29+
this SDK must stay behaviorally identical to the other official ipdata.info SDKs.
30+
- Run the test suite before opening a PR.

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 ipdata.info
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# IPData.info Python SDK — Free IP Geolocation & Threat Intelligence API
2+
3+
[![PyPI](https://img.shields.io/pypi/v/ipdatainfo.svg)](https://pypi.org/project/ipdatainfo/) [![CI](../../actions/workflows/ci.yml/badge.svg)](../../actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)
4+
5+
Official Python client for [**ipdata.info**](https://ipdata.info) — a free,
6+
fast IP geolocation, ASN, and threat-intelligence API. Look up country, city,
7+
ASN, timezone, currency, and security flags (proxy/VPN/Tor/hosting) for any IPv4
8+
or IPv6 address. Powered by [ipdata.info](https://ipdata.info).
9+
10+
## Get a free API key
11+
12+
The public endpoint is **free — 50 requests/min, no signup, no key**. For higher
13+
rate limits and batch lookups, [**create a free API key at
14+
ipdata.info/register**](https://ipdata.info/register) and manage it in your
15+
[dashboard](https://ipdata.info/dashboard).
16+
17+
## Install
18+
19+
```
20+
pip install ipdatainfo
21+
```
22+
23+
## Quickstart
24+
25+
```python
26+
from ipdatainfo import Client
27+
28+
# Free tier — no API key needed. For higher limits + batch, get a free key
29+
# at https://ipdata.info/register and use Client(api_key="...").
30+
client = Client()
31+
32+
info = client.lookup("8.8.8.8")
33+
print(info.city, info.country, info.asn_org) # Mountain View United States Google LLC
34+
```
35+
36+
## Methods
37+
38+
| Method | What it returns |
39+
|--------|-----------------|
40+
| `lookup(ip="")` | Full geolocation record (own IP if omitted) |
41+
| `geo(ip)` | Geo subset (city/region/country/lat/lon/tz) |
42+
| `asn(ip)` | ASN + ISP/registry for an IP |
43+
| `batch(ips)` | Many IPs at once (**requires an API key**) |
44+
| `asn_detail(n)` | ASN detail incl. prefixes |
45+
| `asn_whois_history(n)` | ASN whois history |
46+
| `asn_changes()` | ASN change feed |
47+
| `threat_domain/threat_hash/threat_url(x)` | Threat-intel lookup (domain / file hash / URL) |
48+
49+
Full response schema: [ipdata.info API docs](https://ipdata.info/docs) ·
50+
[SDK contract](https://ipdata.info/docs/sdks).
51+
52+
## Configuration
53+
54+
```python
55+
from ipdatainfo import Client
56+
57+
client = Client(
58+
api_key="KEY", # sent as X-Api-Key; switches to pro.ipdata.info
59+
base_url="https://ipdata.info", # override the host
60+
timeout=10.0, # seconds
61+
)
62+
```
63+
64+
Errors from non-2xx responses are raised as `ipdatainfo.IpDataError` with
65+
`.status` and `.message`.
66+
67+
## Rate limits
68+
69+
- Free (`ipdata.info`): 50 req/min, no key.
70+
- Paid (`pro.ipdata.info`): higher limits + `batch`, with an
71+
[API key](https://ipdata.info/register).
72+
73+
## Other SDKs
74+
75+
12 official SDKs — see the full list at
76+
[**ipdata.info/docs/sdks**](https://ipdata.info/docs/sdks): Python, Node.js, Go,
77+
PHP, Java, Rust, .NET, Kotlin, Swift, Dart, Bash, Objective-C.
78+
79+
## License
80+
81+
MIT © [ipdata.info](https://ipdata.info)

examples/asn_lookup.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
"""ASN lookup example. Run: python examples/asn_lookup.py"""
2+
3+
from ipdatainfo import Client
4+
5+
6+
def main() -> None:
7+
client = Client()
8+
9+
brief = client.asn("8.8.8.8")
10+
print(f"ASN {brief.asn} ({brief.asn_org}) via {brief.isp}, registry {brief.registry}")
11+
12+
detail = client.asn_detail(brief.asn)
13+
print(f"AS name: {detail.get('as_name')}, IPv4 prefixes: {detail.get('ipv4_prefix_count')}")
14+
15+
16+
if __name__ == "__main__":
17+
main()

examples/batch_lookup.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""Batch lookup example (requires a paid API key). See https://ipdata.info/register.
2+
3+
Run: IPDATA_API_KEY=your_key python examples/batch_lookup.py
4+
"""
5+
6+
import os
7+
8+
from ipdatainfo import Client, IpDataError
9+
10+
11+
def main() -> None:
12+
api_key = os.environ.get("IPDATA_API_KEY")
13+
client = Client(api_key=api_key)
14+
15+
try:
16+
results = client.batch(["8.8.8.8", "1.1.1.1"])
17+
except IpDataError as exc:
18+
print(f"batch failed ({exc.status}): {exc.message}")
19+
return
20+
21+
for info in results:
22+
print(f"{info.ip}: {info.city}, {info.country}")
23+
24+
25+
if __name__ == "__main__":
26+
main()

examples/quickstart.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
"""Quickstart example for the ipdata.info Python SDK.
2+
3+
Run: python examples/quickstart.py
4+
"""
5+
6+
from ipdatainfo import Client
7+
8+
9+
def main() -> None:
10+
# Free tier -- no API key needed. For higher limits + batch, get a free
11+
# key at https://ipdata.info/register and use Client(api_key="...").
12+
client = Client()
13+
14+
info = client.lookup("8.8.8.8")
15+
print(f"{info.ip} is in {info.city}, {info.country} (ASN {info.asn}{info.asn_org})")
16+
17+
threat = client.threat_domain("example.com")
18+
print(f"example.com listed as a threat: {threat.listed}")
19+
20+
21+
if __name__ == "__main__":
22+
main()

examples/threat_lookup.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
"""Threat-intel lookup example. Run: python examples/threat_lookup.py"""
2+
3+
from ipdatainfo import Client
4+
5+
6+
def main() -> None:
7+
client = Client()
8+
9+
domain = client.threat_domain("example.com")
10+
print(f"domain example.com listed: {domain.listed}")
11+
12+
url = client.threat_url("https://example.com/path")
13+
print(f"url listed: {url.listed}")
14+
15+
file_hash = client.threat_hash("d41d8cd98f00b204e9800998ecf8427e")
16+
print(f"hash listed: {file_hash.listed}")
17+
18+
19+
if __name__ == "__main__":
20+
main()

0 commit comments

Comments
 (0)