Metadata-Version: 2.4
Name: poptrie
Version: 0.3.0
Summary: High-performance IP and country lookup backed by Rust poptrie
Home-page: https://github.com/swoiow/poptrie-pub
Author: HarmonSir
Author-email: git@pylab.me
License: Apache-2.0
Project-URL: Source, https://github.com/swoiow/poptrie-pub
Project-URL: Issues, https://github.com/swoiow/poptrie-pub/issues
Project-URL: Releases, https://github.com/swoiow/poptrie-pub/releases
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: MacOS
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Rust
Classifier: Topic :: Internet
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: license
Dynamic: license-file
Dynamic: project-url
Dynamic: summary

# poptrie

High-performance IP lookup backed by Rust. This public repository owns the final Python facade and publishes wheels.

Stable public contract:
- `from poptrie import IpSearcher`
- `IpSearcher` resolves to `poptrie.ip_searcher.IpSearcher`
- native extension details are intentionally hidden behind the facade

## Installation

Install from PyPI:

```bash
pip install poptrie
```

## Usage

```python
import socket
from pathlib import Path

from poptrie import IpSearcher


bin_path = Path("china-ip.bin")
searcher = IpSearcher(bin_path)

print("1.0.1.1" in searcher)
print(searcher.contains_ip("1.0.1.1"))
print(searcher.lookup_country("1.0.1.1"))
print(searcher.is_china("1.0.1.1"))

ips = ["1.0.1.1", "8.8.8.8", "240e::1", "2001:db8::"]
print(searcher.contains_ips(ips))
print(searcher.lookup_countries(ips))
print(searcher.matches_countries(ips, "CN"))

v4_ips = ["1.0.1.1", "8.8.8.8", "110.16.0.1", "127.0.0.1"]
packed_v4 = b"".join(socket.inet_pton(socket.AF_INET, ip) for ip in v4_ips)
print(searcher.contains_packed(packed_v4, is_v6=False))
print(searcher.lookup_countries_packed(packed_v4, is_v6=False))
print(searcher.matches_country_packed(packed_v4, "CN", is_v6=False))
```

## Example

```bash
python example.py
```

## Tests

Public facade verification:

```bash
PYTHONPATH=<private-src> python -m unittest discover tests
```

## Notes

- Country codes are returned as u16 in Rust and converted to 2-letter strings in Python.
- `*_packed` methods are the high-throughput APIs for packed inputs (stride 4/16).
- Wheel repack injects the public `__init__.py` and `ip_searcher.py` into the final package.
