ipdata 4.0.7__tar.gz → 4.0.8__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.
- {ipdata-4.0.7 → ipdata-4.0.8}/PKG-INFO +225 -2
- ipdata-4.0.7/src/ipdata.egg-info/PKG-INFO → ipdata-4.0.8/README.md +209 -15
- {ipdata-4.0.7 → ipdata-4.0.8}/setup.cfg +6 -1
- {ipdata-4.0.7 → ipdata-4.0.8}/src/ipdata/__init__.py +1 -0
- ipdata-4.0.8/src/ipdata/iptrie.py +380 -0
- ipdata-4.0.8/src/ipdata/test_iptrie.py +327 -0
- ipdata-4.0.7/README.md → ipdata-4.0.8/src/ipdata.egg-info/PKG-INFO +238 -0
- {ipdata-4.0.7 → ipdata-4.0.8}/src/ipdata.egg-info/SOURCES.txt +2 -0
- {ipdata-4.0.7 → ipdata-4.0.8}/src/ipdata.egg-info/requires.txt +1 -0
- {ipdata-4.0.7 → ipdata-4.0.8}/LICENSE +0 -0
- {ipdata-4.0.7 → ipdata-4.0.8}/pyproject.toml +0 -0
- {ipdata-4.0.7 → ipdata-4.0.8}/src/ipdata/cli.py +0 -0
- {ipdata-4.0.7 → ipdata-4.0.8}/src/ipdata/codes.py +0 -0
- {ipdata-4.0.7 → ipdata-4.0.8}/src/ipdata/geofeeds.py +0 -0
- {ipdata-4.0.7 → ipdata-4.0.8}/src/ipdata/ipdata.py +0 -0
- {ipdata-4.0.7 → ipdata-4.0.8}/src/ipdata/lolcat.py +0 -0
- {ipdata-4.0.7 → ipdata-4.0.8}/src/ipdata/test_geofeeds.py +0 -0
- {ipdata-4.0.7 → ipdata-4.0.8}/src/ipdata/test_ipdata.py +0 -0
- {ipdata-4.0.7 → ipdata-4.0.8}/src/ipdata.egg-info/dependency_links.txt +0 -0
- {ipdata-4.0.7 → ipdata-4.0.8}/src/ipdata.egg-info/entry_points.txt +0 -0
- {ipdata-4.0.7 → ipdata-4.0.8}/src/ipdata.egg-info/top_level.txt +0 -0
|
@@ -1,20 +1,36 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: ipdata
|
|
3
|
-
Version: 4.0.
|
|
3
|
+
Version: 4.0.8
|
|
4
4
|
Summary: This is the official IPData client library for Python
|
|
5
5
|
Home-page: https://github.com/ipdata/python
|
|
6
6
|
Author: Jonathan Kosgei
|
|
7
7
|
Author-email: jonathan@ipdata.co
|
|
8
8
|
Project-URL: Bug Tracker, https://github.com/ipdata/python/issues
|
|
9
9
|
Classifier: Programming Language :: Python :: 3.9
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
10
14
|
Classifier: License :: OSI Approved :: MIT License
|
|
11
15
|
Classifier: Operating System :: OS Independent
|
|
12
16
|
Requires-Python: >=3.9
|
|
13
17
|
Description-Content-Type: text/markdown
|
|
14
18
|
License-File: LICENSE
|
|
19
|
+
Requires-Dist: requests
|
|
20
|
+
Requires-Dist: rich
|
|
21
|
+
Requires-Dist: click
|
|
22
|
+
Requires-Dist: click_default_group
|
|
23
|
+
Requires-Dist: pyperclip
|
|
24
|
+
Requires-Dist: pytest
|
|
25
|
+
Requires-Dist: hypothesis
|
|
26
|
+
Requires-Dist: python-dotenv
|
|
27
|
+
Requires-Dist: pytricia
|
|
28
|
+
Dynamic: license-file
|
|
15
29
|
|
|
16
30
|
[](https://badge.fury.io/py/ipdata) 
|
|
17
31
|
|
|
32
|
+
> **🎉 Introducing IPTrie** — A fast, type-safe data structure for IP lookups with longest-prefix matching. Supports both IPv4 and IPv6. [Learn more →](#iptrie)
|
|
33
|
+
|
|
18
34
|
# Official Python client library and CLI for the ipdata API
|
|
19
35
|
|
|
20
36
|
This is a Python client and command line interface (CLI) for the [ipdata.co](https://ipdata.co) IP Geolocation API. ipdata offers a fast, highly-available API to enrich IP Addresses with Location, Company, Threat Intelligence and numerous other data attributes.
|
|
@@ -25,6 +41,43 @@ Visit our [Documentation](https://docs.ipdata.co/) for more examples and tutoria
|
|
|
25
41
|
|
|
26
42
|
[](https://asciinema.org/a/371292)
|
|
27
43
|
|
|
44
|
+
## Table of Contents
|
|
45
|
+
|
|
46
|
+
- [Installation](#installation)
|
|
47
|
+
- [Library Usage](#library-usage)
|
|
48
|
+
- [Looking up the calling IP Address](#looking-up-the-calling-ip-address)
|
|
49
|
+
- [Looking up any IP Address](#looking-up-any-ip-address)
|
|
50
|
+
- [Getting only one field](#getting-only-one-field)
|
|
51
|
+
- [Getting a number of specific fields](#getting-a-number-of-specific-fields)
|
|
52
|
+
- [Bulk Lookups](#bulk-lookups)
|
|
53
|
+
- [Using the ipdata CLI](#using-the-ipdata-cli)
|
|
54
|
+
- [Windows Installation Notes](#windows-installation-notes)
|
|
55
|
+
- [Available commands](#available-commands)
|
|
56
|
+
- [Initialize the cli with your API Key](#initialize-the-cli-with-your-api-key)
|
|
57
|
+
- [Look up your own IP address](#look-up-your-own-ip-address)
|
|
58
|
+
- [Look up any IP address](#look-up-any-ip-address-1)
|
|
59
|
+
- [Copying results to clipboard](#copying-results-to-clipboard)
|
|
60
|
+
- [Filtering results by a list of fields](#filtering-results-by-a-list-of-fields)
|
|
61
|
+
- [Batch lookup](#batch-lookup)
|
|
62
|
+
- [Available Fields](#available-fields)
|
|
63
|
+
- [Geofeed tools](#geofeed-tools)
|
|
64
|
+
- [IPTrie](#iptrie)
|
|
65
|
+
- [Features](#features)
|
|
66
|
+
- [Quick Start](#quick-start)
|
|
67
|
+
- [IPv6 Support](#ipv6-support)
|
|
68
|
+
- [Use Cases](#use-cases)
|
|
69
|
+
- [Network Classification](#network-classification)
|
|
70
|
+
- [GeoIP Lookup](#geoip-lookup)
|
|
71
|
+
- [Access Control Lists](#access-control-lists)
|
|
72
|
+
- [API Reference](#api-reference)
|
|
73
|
+
- [Constructor](#constructor)
|
|
74
|
+
- [Methods](#methods)
|
|
75
|
+
- [Exceptions](#exceptions)
|
|
76
|
+
- [Input Validation](#input-validation)
|
|
77
|
+
- [Performance](#performance)
|
|
78
|
+
- [Errors](#errors)
|
|
79
|
+
- [Tests](#tests)
|
|
80
|
+
|
|
28
81
|
## Installation
|
|
29
82
|
|
|
30
83
|
Install the latest version of the cli with `pip`.
|
|
@@ -540,6 +593,176 @@ or
|
|
|
540
593
|
ipdata validate geofeed.txt
|
|
541
594
|
```
|
|
542
595
|
|
|
596
|
+
## IPTrie
|
|
597
|
+
|
|
598
|
+
IPTrie is a production-ready, type-safe trie for IP addresses and CIDR prefixes with longest-prefix matching.
|
|
599
|
+
|
|
600
|
+
### Features
|
|
601
|
+
|
|
602
|
+
- **Dual-stack support**: Handles both IPv4 and IPv6 addresses seamlessly
|
|
603
|
+
- **Longest-prefix matching**: Automatically finds the most specific matching prefix
|
|
604
|
+
- **Type-safe**: Full generic type support with comprehensive type hints
|
|
605
|
+
- **Pythonic API**: Familiar dictionary-like interface (`[]`, `in`, `del`, `len`, iteration)
|
|
606
|
+
- **Input validation**: Robust validation using Python's `ipaddress` module
|
|
607
|
+
- **Custom exceptions**: Clear, specific exceptions for better error handling
|
|
608
|
+
- **Well-tested**: Comprehensive test suite with edge cases covered
|
|
609
|
+
|
|
610
|
+
### Quick Start
|
|
611
|
+
|
|
612
|
+
```python
|
|
613
|
+
from ipdata import IPTrie
|
|
614
|
+
|
|
615
|
+
# Create an IPTrie with string values
|
|
616
|
+
ip_trie: IPTrie[str] = IPTrie()
|
|
617
|
+
|
|
618
|
+
# Add network prefixes
|
|
619
|
+
ip_trie["10.0.0.0/8"] = "class-a-private"
|
|
620
|
+
ip_trie["10.1.0.0/16"] = "datacenter"
|
|
621
|
+
ip_trie["10.1.1.0/24"] = "web-servers"
|
|
622
|
+
|
|
623
|
+
# Longest-prefix matching
|
|
624
|
+
print(ip_trie["10.1.1.100"]) # "web-servers"
|
|
625
|
+
print(ip_trie["10.1.2.100"]) # "datacenter"
|
|
626
|
+
print(ip_trie["10.2.0.1"]) # "class-a-private"
|
|
627
|
+
|
|
628
|
+
# Check membership
|
|
629
|
+
print("10.1.1.50" in ip_trie) # True
|
|
630
|
+
print("192.168.1.1" in ip_trie) # False
|
|
631
|
+
|
|
632
|
+
# Get the matching prefix
|
|
633
|
+
print(ip_trie.parent("10.1.1.100")) # "10.1.1.0/24"
|
|
634
|
+
|
|
635
|
+
# Safe access with default
|
|
636
|
+
print(ip_trie.get("8.8.8.8", "unknown")) # "unknown"
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
### IPv6 Support
|
|
640
|
+
|
|
641
|
+
```python
|
|
642
|
+
ip_trie: IPTrie[str] = IPTrie()
|
|
643
|
+
|
|
644
|
+
ip_trie["2001:db8::/32"] = "documentation"
|
|
645
|
+
ip_trie["2001:db8:1::/48"] = "specific-block"
|
|
646
|
+
|
|
647
|
+
print(ip_trie["2001:db8:1::1"]) # "specific-block"
|
|
648
|
+
print(ip_trie["2001:db8:2::1"]) # "documentation"
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
### Use Cases
|
|
652
|
+
|
|
653
|
+
#### Network Classification
|
|
654
|
+
|
|
655
|
+
```python
|
|
656
|
+
from ipdata import IPTrie
|
|
657
|
+
|
|
658
|
+
classifier: IPTrie[dict] = IPTrie()
|
|
659
|
+
classifier["10.0.0.0/8"] = {"type": "private", "rfc": "1918"}
|
|
660
|
+
classifier["172.16.0.0/12"] = {"type": "private", "rfc": "1918"}
|
|
661
|
+
classifier["192.168.0.0/16"] = {"type": "private", "rfc": "1918"}
|
|
662
|
+
classifier["0.0.0.0/0"] = {"type": "public", "rfc": None}
|
|
663
|
+
|
|
664
|
+
def classify_ip(ip: str) -> dict:
|
|
665
|
+
return classifier.get(ip, {"type": "unknown"})
|
|
666
|
+
|
|
667
|
+
print(classify_ip("192.168.1.100")) # {"type": "private", "rfc": "1918"}
|
|
668
|
+
print(classify_ip("8.8.8.8")) # {"type": "public", "rfc": None}
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
#### GeoIP Lookup
|
|
672
|
+
|
|
673
|
+
```python
|
|
674
|
+
from ipdata import IPTrie
|
|
675
|
+
|
|
676
|
+
geo_db: IPTrie[str] = IPTrie()
|
|
677
|
+
geo_db["8.8.8.0/24"] = "US"
|
|
678
|
+
geo_db["1.1.1.0/24"] = "AU"
|
|
679
|
+
|
|
680
|
+
def get_country(ip: str) -> str:
|
|
681
|
+
return geo_db.get(ip, "Unknown")
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
#### Access Control Lists
|
|
685
|
+
|
|
686
|
+
```python
|
|
687
|
+
from ipdata import IPTrie
|
|
688
|
+
|
|
689
|
+
acl: IPTrie[bool] = IPTrie()
|
|
690
|
+
acl["192.168.1.0/24"] = True # Allow internal
|
|
691
|
+
acl["10.0.0.0/8"] = True # Allow VPN
|
|
692
|
+
acl["0.0.0.0/0"] = False # Deny all others
|
|
693
|
+
|
|
694
|
+
def is_allowed(ip: str) -> bool:
|
|
695
|
+
return acl.get(ip, False)
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
### API Reference
|
|
699
|
+
|
|
700
|
+
#### Constructor
|
|
701
|
+
|
|
702
|
+
```python
|
|
703
|
+
IPTrie[T]() # Create an empty IPTrie with value type T
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
#### Methods
|
|
707
|
+
|
|
708
|
+
| Method | Description |
|
|
709
|
+
|--------|-------------|
|
|
710
|
+
| `__setitem__(key, value)` | Set value for IP/prefix |
|
|
711
|
+
| `__getitem__(key)` | Get value using longest-prefix match (raises `KeyNotFoundError`) |
|
|
712
|
+
| `get(key, default=None)` | Get value or default if not found |
|
|
713
|
+
| `__delitem__(key)` | Delete exact prefix |
|
|
714
|
+
| `__contains__(key)` | Check if IP matches any prefix |
|
|
715
|
+
| `has_key(key)` | Check if exact prefix exists |
|
|
716
|
+
| `parent(key)` | Get the longest matching prefix string |
|
|
717
|
+
| `children(key)` | Get all more specific prefixes |
|
|
718
|
+
| `__len__()` | Count of all prefixes |
|
|
719
|
+
| `__iter__()` | Iterate over all prefixes |
|
|
720
|
+
| `keys()` | Iterator over prefixes |
|
|
721
|
+
| `values()` | Iterator over values |
|
|
722
|
+
| `items()` | Iterator over (prefix, value) tuples |
|
|
723
|
+
| `clear()` | Remove all entries |
|
|
724
|
+
|
|
725
|
+
#### Exceptions
|
|
726
|
+
|
|
727
|
+
| Exception | Description |
|
|
728
|
+
|-----------|-------------|
|
|
729
|
+
| `IPTrieError` | Base exception class |
|
|
730
|
+
| `InvalidIPError` | Invalid IP address or network format |
|
|
731
|
+
| `KeyNotFoundError` | No matching prefix found (also a `KeyError`) |
|
|
732
|
+
|
|
733
|
+
### Input Validation
|
|
734
|
+
|
|
735
|
+
IPTrie validates all inputs using Python's `ipaddress` module:
|
|
736
|
+
|
|
737
|
+
```python
|
|
738
|
+
from ipdata import IPTrie, InvalidIPError
|
|
739
|
+
|
|
740
|
+
ip_trie: IPTrie[str] = IPTrie()
|
|
741
|
+
|
|
742
|
+
# These work
|
|
743
|
+
ip_trie["192.168.1.0/24"] = "valid"
|
|
744
|
+
ip_trie["2001:db8::1"] = "valid"
|
|
745
|
+
|
|
746
|
+
# These raise InvalidIPError
|
|
747
|
+
try:
|
|
748
|
+
ip_trie["not-an-ip"] = "invalid"
|
|
749
|
+
except InvalidIPError as e:
|
|
750
|
+
print(f"Error: {e}")
|
|
751
|
+
|
|
752
|
+
try:
|
|
753
|
+
ip_trie[""] = "empty"
|
|
754
|
+
except InvalidIPError as e:
|
|
755
|
+
print(f"Error: {e}")
|
|
756
|
+
```
|
|
757
|
+
|
|
758
|
+
### Performance
|
|
759
|
+
|
|
760
|
+
IPTrie uses Patricia tries (via `pytricia`) internally, providing:
|
|
761
|
+
|
|
762
|
+
- **O(k)** lookup time where k is the prefix length (32 for IPv4, 128 for IPv6)
|
|
763
|
+
- **Memory efficient** storage of overlapping prefixes
|
|
764
|
+
- **Fast iteration** over all prefixes
|
|
765
|
+
|
|
543
766
|
## Errors
|
|
544
767
|
|
|
545
768
|
A list of possible errors is available at [Status Codes](https://docs.ipdata.co/api-reference/status-codes)
|
|
@@ -1,20 +1,7 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: ipdata
|
|
3
|
-
Version: 4.0.7
|
|
4
|
-
Summary: This is the official IPData client library for Python
|
|
5
|
-
Home-page: https://github.com/ipdata/python
|
|
6
|
-
Author: Jonathan Kosgei
|
|
7
|
-
Author-email: jonathan@ipdata.co
|
|
8
|
-
Project-URL: Bug Tracker, https://github.com/ipdata/python/issues
|
|
9
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
10
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
-
Classifier: Operating System :: OS Independent
|
|
12
|
-
Requires-Python: >=3.9
|
|
13
|
-
Description-Content-Type: text/markdown
|
|
14
|
-
License-File: LICENSE
|
|
15
|
-
|
|
16
1
|
[](https://badge.fury.io/py/ipdata) 
|
|
17
2
|
|
|
3
|
+
> **🎉 Introducing IPTrie** — A fast, type-safe data structure for IP lookups with longest-prefix matching. Supports both IPv4 and IPv6. [Learn more →](#iptrie)
|
|
4
|
+
|
|
18
5
|
# Official Python client library and CLI for the ipdata API
|
|
19
6
|
|
|
20
7
|
This is a Python client and command line interface (CLI) for the [ipdata.co](https://ipdata.co) IP Geolocation API. ipdata offers a fast, highly-available API to enrich IP Addresses with Location, Company, Threat Intelligence and numerous other data attributes.
|
|
@@ -25,6 +12,43 @@ Visit our [Documentation](https://docs.ipdata.co/) for more examples and tutoria
|
|
|
25
12
|
|
|
26
13
|
[](https://asciinema.org/a/371292)
|
|
27
14
|
|
|
15
|
+
## Table of Contents
|
|
16
|
+
|
|
17
|
+
- [Installation](#installation)
|
|
18
|
+
- [Library Usage](#library-usage)
|
|
19
|
+
- [Looking up the calling IP Address](#looking-up-the-calling-ip-address)
|
|
20
|
+
- [Looking up any IP Address](#looking-up-any-ip-address)
|
|
21
|
+
- [Getting only one field](#getting-only-one-field)
|
|
22
|
+
- [Getting a number of specific fields](#getting-a-number-of-specific-fields)
|
|
23
|
+
- [Bulk Lookups](#bulk-lookups)
|
|
24
|
+
- [Using the ipdata CLI](#using-the-ipdata-cli)
|
|
25
|
+
- [Windows Installation Notes](#windows-installation-notes)
|
|
26
|
+
- [Available commands](#available-commands)
|
|
27
|
+
- [Initialize the cli with your API Key](#initialize-the-cli-with-your-api-key)
|
|
28
|
+
- [Look up your own IP address](#look-up-your-own-ip-address)
|
|
29
|
+
- [Look up any IP address](#look-up-any-ip-address-1)
|
|
30
|
+
- [Copying results to clipboard](#copying-results-to-clipboard)
|
|
31
|
+
- [Filtering results by a list of fields](#filtering-results-by-a-list-of-fields)
|
|
32
|
+
- [Batch lookup](#batch-lookup)
|
|
33
|
+
- [Available Fields](#available-fields)
|
|
34
|
+
- [Geofeed tools](#geofeed-tools)
|
|
35
|
+
- [IPTrie](#iptrie)
|
|
36
|
+
- [Features](#features)
|
|
37
|
+
- [Quick Start](#quick-start)
|
|
38
|
+
- [IPv6 Support](#ipv6-support)
|
|
39
|
+
- [Use Cases](#use-cases)
|
|
40
|
+
- [Network Classification](#network-classification)
|
|
41
|
+
- [GeoIP Lookup](#geoip-lookup)
|
|
42
|
+
- [Access Control Lists](#access-control-lists)
|
|
43
|
+
- [API Reference](#api-reference)
|
|
44
|
+
- [Constructor](#constructor)
|
|
45
|
+
- [Methods](#methods)
|
|
46
|
+
- [Exceptions](#exceptions)
|
|
47
|
+
- [Input Validation](#input-validation)
|
|
48
|
+
- [Performance](#performance)
|
|
49
|
+
- [Errors](#errors)
|
|
50
|
+
- [Tests](#tests)
|
|
51
|
+
|
|
28
52
|
## Installation
|
|
29
53
|
|
|
30
54
|
Install the latest version of the cli with `pip`.
|
|
@@ -540,6 +564,176 @@ or
|
|
|
540
564
|
ipdata validate geofeed.txt
|
|
541
565
|
```
|
|
542
566
|
|
|
567
|
+
## IPTrie
|
|
568
|
+
|
|
569
|
+
IPTrie is a production-ready, type-safe trie for IP addresses and CIDR prefixes with longest-prefix matching.
|
|
570
|
+
|
|
571
|
+
### Features
|
|
572
|
+
|
|
573
|
+
- **Dual-stack support**: Handles both IPv4 and IPv6 addresses seamlessly
|
|
574
|
+
- **Longest-prefix matching**: Automatically finds the most specific matching prefix
|
|
575
|
+
- **Type-safe**: Full generic type support with comprehensive type hints
|
|
576
|
+
- **Pythonic API**: Familiar dictionary-like interface (`[]`, `in`, `del`, `len`, iteration)
|
|
577
|
+
- **Input validation**: Robust validation using Python's `ipaddress` module
|
|
578
|
+
- **Custom exceptions**: Clear, specific exceptions for better error handling
|
|
579
|
+
- **Well-tested**: Comprehensive test suite with edge cases covered
|
|
580
|
+
|
|
581
|
+
### Quick Start
|
|
582
|
+
|
|
583
|
+
```python
|
|
584
|
+
from ipdata import IPTrie
|
|
585
|
+
|
|
586
|
+
# Create an IPTrie with string values
|
|
587
|
+
ip_trie: IPTrie[str] = IPTrie()
|
|
588
|
+
|
|
589
|
+
# Add network prefixes
|
|
590
|
+
ip_trie["10.0.0.0/8"] = "class-a-private"
|
|
591
|
+
ip_trie["10.1.0.0/16"] = "datacenter"
|
|
592
|
+
ip_trie["10.1.1.0/24"] = "web-servers"
|
|
593
|
+
|
|
594
|
+
# Longest-prefix matching
|
|
595
|
+
print(ip_trie["10.1.1.100"]) # "web-servers"
|
|
596
|
+
print(ip_trie["10.1.2.100"]) # "datacenter"
|
|
597
|
+
print(ip_trie["10.2.0.1"]) # "class-a-private"
|
|
598
|
+
|
|
599
|
+
# Check membership
|
|
600
|
+
print("10.1.1.50" in ip_trie) # True
|
|
601
|
+
print("192.168.1.1" in ip_trie) # False
|
|
602
|
+
|
|
603
|
+
# Get the matching prefix
|
|
604
|
+
print(ip_trie.parent("10.1.1.100")) # "10.1.1.0/24"
|
|
605
|
+
|
|
606
|
+
# Safe access with default
|
|
607
|
+
print(ip_trie.get("8.8.8.8", "unknown")) # "unknown"
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
### IPv6 Support
|
|
611
|
+
|
|
612
|
+
```python
|
|
613
|
+
ip_trie: IPTrie[str] = IPTrie()
|
|
614
|
+
|
|
615
|
+
ip_trie["2001:db8::/32"] = "documentation"
|
|
616
|
+
ip_trie["2001:db8:1::/48"] = "specific-block"
|
|
617
|
+
|
|
618
|
+
print(ip_trie["2001:db8:1::1"]) # "specific-block"
|
|
619
|
+
print(ip_trie["2001:db8:2::1"]) # "documentation"
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
### Use Cases
|
|
623
|
+
|
|
624
|
+
#### Network Classification
|
|
625
|
+
|
|
626
|
+
```python
|
|
627
|
+
from ipdata import IPTrie
|
|
628
|
+
|
|
629
|
+
classifier: IPTrie[dict] = IPTrie()
|
|
630
|
+
classifier["10.0.0.0/8"] = {"type": "private", "rfc": "1918"}
|
|
631
|
+
classifier["172.16.0.0/12"] = {"type": "private", "rfc": "1918"}
|
|
632
|
+
classifier["192.168.0.0/16"] = {"type": "private", "rfc": "1918"}
|
|
633
|
+
classifier["0.0.0.0/0"] = {"type": "public", "rfc": None}
|
|
634
|
+
|
|
635
|
+
def classify_ip(ip: str) -> dict:
|
|
636
|
+
return classifier.get(ip, {"type": "unknown"})
|
|
637
|
+
|
|
638
|
+
print(classify_ip("192.168.1.100")) # {"type": "private", "rfc": "1918"}
|
|
639
|
+
print(classify_ip("8.8.8.8")) # {"type": "public", "rfc": None}
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
#### GeoIP Lookup
|
|
643
|
+
|
|
644
|
+
```python
|
|
645
|
+
from ipdata import IPTrie
|
|
646
|
+
|
|
647
|
+
geo_db: IPTrie[str] = IPTrie()
|
|
648
|
+
geo_db["8.8.8.0/24"] = "US"
|
|
649
|
+
geo_db["1.1.1.0/24"] = "AU"
|
|
650
|
+
|
|
651
|
+
def get_country(ip: str) -> str:
|
|
652
|
+
return geo_db.get(ip, "Unknown")
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
#### Access Control Lists
|
|
656
|
+
|
|
657
|
+
```python
|
|
658
|
+
from ipdata import IPTrie
|
|
659
|
+
|
|
660
|
+
acl: IPTrie[bool] = IPTrie()
|
|
661
|
+
acl["192.168.1.0/24"] = True # Allow internal
|
|
662
|
+
acl["10.0.0.0/8"] = True # Allow VPN
|
|
663
|
+
acl["0.0.0.0/0"] = False # Deny all others
|
|
664
|
+
|
|
665
|
+
def is_allowed(ip: str) -> bool:
|
|
666
|
+
return acl.get(ip, False)
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
### API Reference
|
|
670
|
+
|
|
671
|
+
#### Constructor
|
|
672
|
+
|
|
673
|
+
```python
|
|
674
|
+
IPTrie[T]() # Create an empty IPTrie with value type T
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
#### Methods
|
|
678
|
+
|
|
679
|
+
| Method | Description |
|
|
680
|
+
|--------|-------------|
|
|
681
|
+
| `__setitem__(key, value)` | Set value for IP/prefix |
|
|
682
|
+
| `__getitem__(key)` | Get value using longest-prefix match (raises `KeyNotFoundError`) |
|
|
683
|
+
| `get(key, default=None)` | Get value or default if not found |
|
|
684
|
+
| `__delitem__(key)` | Delete exact prefix |
|
|
685
|
+
| `__contains__(key)` | Check if IP matches any prefix |
|
|
686
|
+
| `has_key(key)` | Check if exact prefix exists |
|
|
687
|
+
| `parent(key)` | Get the longest matching prefix string |
|
|
688
|
+
| `children(key)` | Get all more specific prefixes |
|
|
689
|
+
| `__len__()` | Count of all prefixes |
|
|
690
|
+
| `__iter__()` | Iterate over all prefixes |
|
|
691
|
+
| `keys()` | Iterator over prefixes |
|
|
692
|
+
| `values()` | Iterator over values |
|
|
693
|
+
| `items()` | Iterator over (prefix, value) tuples |
|
|
694
|
+
| `clear()` | Remove all entries |
|
|
695
|
+
|
|
696
|
+
#### Exceptions
|
|
697
|
+
|
|
698
|
+
| Exception | Description |
|
|
699
|
+
|-----------|-------------|
|
|
700
|
+
| `IPTrieError` | Base exception class |
|
|
701
|
+
| `InvalidIPError` | Invalid IP address or network format |
|
|
702
|
+
| `KeyNotFoundError` | No matching prefix found (also a `KeyError`) |
|
|
703
|
+
|
|
704
|
+
### Input Validation
|
|
705
|
+
|
|
706
|
+
IPTrie validates all inputs using Python's `ipaddress` module:
|
|
707
|
+
|
|
708
|
+
```python
|
|
709
|
+
from ipdata import IPTrie, InvalidIPError
|
|
710
|
+
|
|
711
|
+
ip_trie: IPTrie[str] = IPTrie()
|
|
712
|
+
|
|
713
|
+
# These work
|
|
714
|
+
ip_trie["192.168.1.0/24"] = "valid"
|
|
715
|
+
ip_trie["2001:db8::1"] = "valid"
|
|
716
|
+
|
|
717
|
+
# These raise InvalidIPError
|
|
718
|
+
try:
|
|
719
|
+
ip_trie["not-an-ip"] = "invalid"
|
|
720
|
+
except InvalidIPError as e:
|
|
721
|
+
print(f"Error: {e}")
|
|
722
|
+
|
|
723
|
+
try:
|
|
724
|
+
ip_trie[""] = "empty"
|
|
725
|
+
except InvalidIPError as e:
|
|
726
|
+
print(f"Error: {e}")
|
|
727
|
+
```
|
|
728
|
+
|
|
729
|
+
### Performance
|
|
730
|
+
|
|
731
|
+
IPTrie uses Patricia tries (via `pytricia`) internally, providing:
|
|
732
|
+
|
|
733
|
+
- **O(k)** lookup time where k is the prefix length (32 for IPv4, 128 for IPv6)
|
|
734
|
+
- **Memory efficient** storage of overlapping prefixes
|
|
735
|
+
- **Fast iteration** over all prefixes
|
|
736
|
+
|
|
543
737
|
## Errors
|
|
544
738
|
|
|
545
739
|
A list of possible errors is available at [Status Codes](https://docs.ipdata.co/api-reference/status-codes)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[metadata]
|
|
2
2
|
name = ipdata
|
|
3
|
-
version = 4.0.
|
|
3
|
+
version = 4.0.8
|
|
4
4
|
author = Jonathan Kosgei
|
|
5
5
|
author_email = jonathan@ipdata.co
|
|
6
6
|
description = This is the official IPData client library for Python
|
|
@@ -11,6 +11,10 @@ project_urls =
|
|
|
11
11
|
Bug Tracker = https://github.com/ipdata/python/issues
|
|
12
12
|
classifiers =
|
|
13
13
|
Programming Language :: Python :: 3.9
|
|
14
|
+
Programming Language :: Python :: 3.10
|
|
15
|
+
Programming Language :: Python :: 3.11
|
|
16
|
+
Programming Language :: Python :: 3.12
|
|
17
|
+
Programming Language :: Python :: 3.13
|
|
14
18
|
License :: OSI Approved :: MIT License
|
|
15
19
|
Operating System :: OS Independent
|
|
16
20
|
|
|
@@ -28,6 +32,7 @@ install_requires =
|
|
|
28
32
|
pytest
|
|
29
33
|
hypothesis
|
|
30
34
|
python-dotenv
|
|
35
|
+
pytricia
|
|
31
36
|
|
|
32
37
|
[options.entry_points]
|
|
33
38
|
console_scripts =
|