maxminddb-rust 0.1.0__tar.gz → 0.2.0__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.
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/.githooks/pre-commit +0 -0
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/.github/workflows/codeql.yml +4 -4
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/.github/workflows/lint.yml +6 -6
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/.github/workflows/release.yml +2 -2
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/.github/workflows/test.yml +2 -2
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/.github/workflows/zizmor.yml +2 -2
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/CHANGELOG.md +8 -0
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/Cargo.lock +3 -3
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/Cargo.toml +2 -2
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/PKG-INFO +13 -10
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/README.md +9 -9
- maxminddb_rust-0.2.0/dev-bin/release.sh +73 -0
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/examples/basic_usage.py +0 -0
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/examples/batch_processing.py +0 -0
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/examples/benchmark.py +0 -0
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/examples/benchmark_batch.py +0 -0
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/examples/context_manager.py +0 -0
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/examples/iterator_demo.py +0 -0
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/pyproject.toml +4 -1
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/src/lib.rs +84 -25
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/tests/maxmind/reader_test.py +2 -2
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/uv.lock +1 -1
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/.github/dependabot.yml +0 -0
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/.gitignore +0 -0
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/.gitmodules +0 -0
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/CONTRIBUTING.md +0 -0
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/LICENSE +0 -0
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/MIGRATION.md +0 -0
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/benchmark_comprehensive.py +0 -0
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/maxminddb_rust.pyi +0 -0
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/precious.toml +0 -0
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/py.typed +0 -0
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/tests/__init__.py +0 -0
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/tests/maxmind/README.md +0 -0
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/tests/maxmind/UPSTREAM_LICENSE +0 -0
- {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/tests/maxmind/__init__.py +0 -0
|
File without changes
|
|
@@ -21,7 +21,7 @@ jobs:
|
|
|
21
21
|
|
|
22
22
|
steps:
|
|
23
23
|
- name: Checkout repository
|
|
24
|
-
uses: actions/checkout@
|
|
24
|
+
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
|
25
25
|
with:
|
|
26
26
|
fetch-depth: 2
|
|
27
27
|
persist-credentials: false
|
|
@@ -36,12 +36,12 @@ jobs:
|
|
|
36
36
|
python-version: "3.x"
|
|
37
37
|
|
|
38
38
|
- name: Install Rust
|
|
39
|
-
uses: dtolnay/rust-toolchain@
|
|
39
|
+
uses: dtolnay/rust-toolchain@0b1efabc08b657293548b77fb76cc02d26091c7e # master
|
|
40
40
|
with:
|
|
41
41
|
toolchain: stable
|
|
42
42
|
|
|
43
43
|
- name: Initialize CodeQL
|
|
44
|
-
uses: github/codeql-action/init@
|
|
44
|
+
uses: github/codeql-action/init@v4
|
|
45
45
|
with:
|
|
46
46
|
languages: python, rust
|
|
47
47
|
|
|
@@ -52,4 +52,4 @@ jobs:
|
|
|
52
52
|
run: maturin build --release
|
|
53
53
|
|
|
54
54
|
- name: Perform CodeQL Analysis
|
|
55
|
-
uses: github/codeql-action/analyze@
|
|
55
|
+
uses: github/codeql-action/analyze@v4
|
|
@@ -13,12 +13,12 @@ jobs:
|
|
|
13
13
|
name: Clippy
|
|
14
14
|
runs-on: ubuntu-latest
|
|
15
15
|
steps:
|
|
16
|
-
- uses: actions/checkout@
|
|
16
|
+
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
|
17
17
|
with:
|
|
18
18
|
persist-credentials: false
|
|
19
19
|
|
|
20
20
|
- name: Install Rust
|
|
21
|
-
uses: dtolnay/rust-toolchain@
|
|
21
|
+
uses: dtolnay/rust-toolchain@0b1efabc08b657293548b77fb76cc02d26091c7e # master
|
|
22
22
|
with:
|
|
23
23
|
toolchain: stable
|
|
24
24
|
components: clippy
|
|
@@ -30,12 +30,12 @@ jobs:
|
|
|
30
30
|
name: Rustfmt
|
|
31
31
|
runs-on: ubuntu-latest
|
|
32
32
|
steps:
|
|
33
|
-
- uses: actions/checkout@
|
|
33
|
+
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
|
34
34
|
with:
|
|
35
35
|
persist-credentials: false
|
|
36
36
|
|
|
37
37
|
- name: Install Rust
|
|
38
|
-
uses: dtolnay/rust-toolchain@
|
|
38
|
+
uses: dtolnay/rust-toolchain@0b1efabc08b657293548b77fb76cc02d26091c7e # master
|
|
39
39
|
with:
|
|
40
40
|
toolchain: stable
|
|
41
41
|
components: rustfmt
|
|
@@ -47,7 +47,7 @@ jobs:
|
|
|
47
47
|
name: Ruff
|
|
48
48
|
runs-on: ubuntu-latest
|
|
49
49
|
steps:
|
|
50
|
-
- uses: actions/checkout@
|
|
50
|
+
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
|
51
51
|
with:
|
|
52
52
|
persist-credentials: false
|
|
53
53
|
|
|
@@ -64,7 +64,7 @@ jobs:
|
|
|
64
64
|
name: Prettier
|
|
65
65
|
runs-on: ubuntu-latest
|
|
66
66
|
steps:
|
|
67
|
-
- uses: actions/checkout@
|
|
67
|
+
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
|
68
68
|
with:
|
|
69
69
|
persist-credentials: false
|
|
70
70
|
|
|
@@ -37,7 +37,7 @@ jobs:
|
|
|
37
37
|
python_versions: "3.11 3.12 3.13 3.14"
|
|
38
38
|
|
|
39
39
|
steps:
|
|
40
|
-
- uses: actions/checkout@
|
|
40
|
+
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
|
41
41
|
with:
|
|
42
42
|
persist-credentials: false
|
|
43
43
|
|
|
@@ -77,7 +77,7 @@ jobs:
|
|
|
77
77
|
name: Build source distribution
|
|
78
78
|
runs-on: ubuntu-latest
|
|
79
79
|
steps:
|
|
80
|
-
- uses: actions/checkout@
|
|
80
|
+
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
|
81
81
|
with:
|
|
82
82
|
persist-credentials: false
|
|
83
83
|
|
|
@@ -21,7 +21,7 @@ jobs:
|
|
|
21
21
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
22
22
|
|
|
23
23
|
steps:
|
|
24
|
-
- uses: actions/checkout@
|
|
24
|
+
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
|
25
25
|
with:
|
|
26
26
|
persist-credentials: false
|
|
27
27
|
submodules: recursive
|
|
@@ -32,7 +32,7 @@ jobs:
|
|
|
32
32
|
python-version: ${{ matrix.python-version }}
|
|
33
33
|
|
|
34
34
|
- name: Install Rust
|
|
35
|
-
uses: dtolnay/rust-toolchain@
|
|
35
|
+
uses: dtolnay/rust-toolchain@0b1efabc08b657293548b77fb76cc02d26091c7e # master
|
|
36
36
|
with:
|
|
37
37
|
toolchain: stable
|
|
38
38
|
|
|
@@ -17,9 +17,9 @@ jobs:
|
|
|
17
17
|
security-events: write
|
|
18
18
|
steps:
|
|
19
19
|
- name: Checkout repository
|
|
20
|
-
uses: actions/checkout@
|
|
20
|
+
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
|
21
21
|
with:
|
|
22
22
|
persist-credentials: false
|
|
23
23
|
|
|
24
24
|
- name: Run zizmor
|
|
25
|
-
uses: zizmorcore/zizmor-action@
|
|
25
|
+
uses: zizmorcore/zizmor-action@e639db99335bc9038abc0e066dfcd72e23d26fb4 # v0.3.0
|
|
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.2.0] - 2025-11-28
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- Upgraded maxminddb crate from 0.26.0 to 0.27.0. This brings internal
|
|
13
|
+
improvements from the upstream Rust library with no breaking changes
|
|
14
|
+
to the Python API.
|
|
15
|
+
|
|
8
16
|
## [0.1.1] - 2025-11-08
|
|
9
17
|
|
|
10
18
|
- Attempt at republishing with tweaked workflow.
|
|
@@ -59,9 +59,9 @@ checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
|
|
|
59
59
|
|
|
60
60
|
[[package]]
|
|
61
61
|
name = "maxminddb"
|
|
62
|
-
version = "0.
|
|
62
|
+
version = "0.27.0"
|
|
63
63
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
64
|
-
checksum = "
|
|
64
|
+
checksum = "7ef0551fc3e7345a6c854c1026b0ddada1e443e51f4fb4cdcf86cc1a71d4b337"
|
|
65
65
|
dependencies = [
|
|
66
66
|
"ipnetwork",
|
|
67
67
|
"log",
|
|
@@ -72,7 +72,7 @@ dependencies = [
|
|
|
72
72
|
|
|
73
73
|
[[package]]
|
|
74
74
|
name = "maxminddb-rust"
|
|
75
|
-
version = "0.
|
|
75
|
+
version = "0.2.0"
|
|
76
76
|
dependencies = [
|
|
77
77
|
"ipnetwork",
|
|
78
78
|
"maxminddb",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "maxminddb-rust"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.2.0"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
authors = ["Gregory Oschwald <oschwald@gmail.com>"]
|
|
6
6
|
description = "Rust-based Python binding for MaxMind DB - high-performance alternative to maxminddb"
|
|
@@ -14,7 +14,7 @@ crate-type = ["cdylib"]
|
|
|
14
14
|
|
|
15
15
|
[dependencies]
|
|
16
16
|
ipnetwork = "0.21"
|
|
17
|
-
maxminddb = "0.
|
|
17
|
+
maxminddb = "0.27.0"
|
|
18
18
|
memmap2 = "0.9"
|
|
19
19
|
pyo3 = { version = "0.27.1", features = ["extension-module", "generate-import-lib"] }
|
|
20
20
|
serde = "1.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: maxminddb-rust
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Classifier: Development Status :: 4 - Beta
|
|
5
5
|
Classifier: Intended Audience :: Developers
|
|
6
6
|
Classifier: License :: OSI Approved :: ISC License (ISCL)
|
|
@@ -29,6 +29,9 @@ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
|
29
29
|
Project-URL: Homepage, https://github.com/oschwald/maxminddb-rust-python
|
|
30
30
|
Project-URL: Repository, https://github.com/oschwald/maxminddb-rust-python
|
|
31
31
|
Project-URL: Bug Tracker, https://github.com/oschwald/maxminddb-rust-python/issues
|
|
32
|
+
Project-URL: Changelog, https://github.com/oschwald/maxminddb-rust-python/blob/main/CHANGELOG.md
|
|
33
|
+
Project-URL: Migration Guide, https://github.com/oschwald/maxminddb-rust-python/blob/main/MIGRATION.md
|
|
34
|
+
Project-URL: Contributing, https://github.com/oschwald/maxminddb-rust-python/blob/main/CONTRIBUTING.md
|
|
32
35
|
|
|
33
36
|
# maxminddb-rust
|
|
34
37
|
|
|
@@ -175,10 +178,10 @@ reader = maxminddb_rust.open_database("/var/lib/GeoIP/GeoIP2-City.mmdb", mode=ma
|
|
|
175
178
|
|
|
176
179
|
The `examples/` directory contains complete working examples demonstrating various use cases:
|
|
177
180
|
|
|
178
|
-
- **[basic_usage.py](examples/basic_usage.py)** - Simple IP lookups, metadata access, and database lifecycle
|
|
179
|
-
- **[context_manager.py](examples/context_manager.py)** - Using `with` statement for automatic resource cleanup
|
|
180
|
-
- **[iterator_demo.py](examples/iterator_demo.py)** - Iterating over all networks in the database
|
|
181
|
-
- **[batch_processing.py](examples/batch_processing.py)** - High-performance batch lookups with `get_many()`
|
|
181
|
+
- **[basic_usage.py](https://github.com/oschwald/maxminddb-rust-python/blob/main/examples/basic_usage.py)** - Simple IP lookups, metadata access, and database lifecycle
|
|
182
|
+
- **[context_manager.py](https://github.com/oschwald/maxminddb-rust-python/blob/main/examples/context_manager.py)** - Using `with` statement for automatic resource cleanup
|
|
183
|
+
- **[iterator_demo.py](https://github.com/oschwald/maxminddb-rust-python/blob/main/examples/iterator_demo.py)** - Iterating over all networks in the database
|
|
184
|
+
- **[batch_processing.py](https://github.com/oschwald/maxminddb-rust-python/blob/main/examples/batch_processing.py)** - High-performance batch lookups with `get_many()`
|
|
182
185
|
|
|
183
186
|
Run any example:
|
|
184
187
|
|
|
@@ -196,8 +199,8 @@ uv run python examples/batch_processing.py
|
|
|
196
199
|
help(maxminddb_rust.Reader.get)
|
|
197
200
|
```
|
|
198
201
|
- **Type Hints**: Full type stub file (`maxminddb_rust.pyi`) included for IDE autocomplete and type checking
|
|
199
|
-
- **Changelog**: See [CHANGELOG.md](CHANGELOG.md) for version history and release notes
|
|
200
|
-
- **Migration Guide**: See [MIGRATION.md](MIGRATION.md) for migrating from the official `maxminddb` package
|
|
202
|
+
- **Changelog**: See [CHANGELOG.md](https://github.com/oschwald/maxminddb-rust-python/blob/main/CHANGELOG.md) for version history and release notes
|
|
203
|
+
- **Migration Guide**: See [MIGRATION.md](https://github.com/oschwald/maxminddb-rust-python/blob/main/MIGRATION.md) for migrating from the official `maxminddb` package
|
|
201
204
|
|
|
202
205
|
## Benchmarking
|
|
203
206
|
|
|
@@ -229,9 +232,9 @@ uv run pytest
|
|
|
229
232
|
uv run pytest -v
|
|
230
233
|
```
|
|
231
234
|
|
|
232
|
-
For contributor information including development setup, code quality tools, and test syncing, see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
235
|
+
For contributor information including development setup, code quality tools, and test syncing, see [CONTRIBUTING.md](https://github.com/oschwald/maxminddb-rust-python/blob/main/CONTRIBUTING.md).
|
|
233
236
|
|
|
234
|
-
For upstream test compatibility and syncing instructions, see [tests/maxmind/README.md](tests/maxmind/README.md).
|
|
237
|
+
For upstream test compatibility and syncing instructions, see [tests/maxmind/README.md](https://github.com/oschwald/maxminddb-rust-python/blob/main/tests/maxmind/README.md).
|
|
235
238
|
|
|
236
239
|
## License
|
|
237
240
|
|
|
@@ -239,5 +242,5 @@ ISC License - see LICENSE file for details.
|
|
|
239
242
|
|
|
240
243
|
## Contributing
|
|
241
244
|
|
|
242
|
-
Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, code quality guidelines, and pull request procedures.
|
|
245
|
+
Contributions are welcome! Please see [CONTRIBUTING.md](https://github.com/oschwald/maxminddb-rust-python/blob/main/CONTRIBUTING.md) for development setup, code quality guidelines, and pull request procedures.
|
|
243
246
|
|
|
@@ -143,10 +143,10 @@ reader = maxminddb_rust.open_database("/var/lib/GeoIP/GeoIP2-City.mmdb", mode=ma
|
|
|
143
143
|
|
|
144
144
|
The `examples/` directory contains complete working examples demonstrating various use cases:
|
|
145
145
|
|
|
146
|
-
- **[basic_usage.py](examples/basic_usage.py)** - Simple IP lookups, metadata access, and database lifecycle
|
|
147
|
-
- **[context_manager.py](examples/context_manager.py)** - Using `with` statement for automatic resource cleanup
|
|
148
|
-
- **[iterator_demo.py](examples/iterator_demo.py)** - Iterating over all networks in the database
|
|
149
|
-
- **[batch_processing.py](examples/batch_processing.py)** - High-performance batch lookups with `get_many()`
|
|
146
|
+
- **[basic_usage.py](https://github.com/oschwald/maxminddb-rust-python/blob/main/examples/basic_usage.py)** - Simple IP lookups, metadata access, and database lifecycle
|
|
147
|
+
- **[context_manager.py](https://github.com/oschwald/maxminddb-rust-python/blob/main/examples/context_manager.py)** - Using `with` statement for automatic resource cleanup
|
|
148
|
+
- **[iterator_demo.py](https://github.com/oschwald/maxminddb-rust-python/blob/main/examples/iterator_demo.py)** - Iterating over all networks in the database
|
|
149
|
+
- **[batch_processing.py](https://github.com/oschwald/maxminddb-rust-python/blob/main/examples/batch_processing.py)** - High-performance batch lookups with `get_many()`
|
|
150
150
|
|
|
151
151
|
Run any example:
|
|
152
152
|
|
|
@@ -164,8 +164,8 @@ uv run python examples/batch_processing.py
|
|
|
164
164
|
help(maxminddb_rust.Reader.get)
|
|
165
165
|
```
|
|
166
166
|
- **Type Hints**: Full type stub file (`maxminddb_rust.pyi`) included for IDE autocomplete and type checking
|
|
167
|
-
- **Changelog**: See [CHANGELOG.md](CHANGELOG.md) for version history and release notes
|
|
168
|
-
- **Migration Guide**: See [MIGRATION.md](MIGRATION.md) for migrating from the official `maxminddb` package
|
|
167
|
+
- **Changelog**: See [CHANGELOG.md](https://github.com/oschwald/maxminddb-rust-python/blob/main/CHANGELOG.md) for version history and release notes
|
|
168
|
+
- **Migration Guide**: See [MIGRATION.md](https://github.com/oschwald/maxminddb-rust-python/blob/main/MIGRATION.md) for migrating from the official `maxminddb` package
|
|
169
169
|
|
|
170
170
|
## Benchmarking
|
|
171
171
|
|
|
@@ -197,9 +197,9 @@ uv run pytest
|
|
|
197
197
|
uv run pytest -v
|
|
198
198
|
```
|
|
199
199
|
|
|
200
|
-
For contributor information including development setup, code quality tools, and test syncing, see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
200
|
+
For contributor information including development setup, code quality tools, and test syncing, see [CONTRIBUTING.md](https://github.com/oschwald/maxminddb-rust-python/blob/main/CONTRIBUTING.md).
|
|
201
201
|
|
|
202
|
-
For upstream test compatibility and syncing instructions, see [tests/maxmind/README.md](tests/maxmind/README.md).
|
|
202
|
+
For upstream test compatibility and syncing instructions, see [tests/maxmind/README.md](https://github.com/oschwald/maxminddb-rust-python/blob/main/tests/maxmind/README.md).
|
|
203
203
|
|
|
204
204
|
## License
|
|
205
205
|
|
|
@@ -207,4 +207,4 @@ ISC License - see LICENSE file for details.
|
|
|
207
207
|
|
|
208
208
|
## Contributing
|
|
209
209
|
|
|
210
|
-
Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, code quality guidelines, and pull request procedures.
|
|
210
|
+
Contributions are welcome! Please see [CONTRIBUTING.md](https://github.com/oschwald/maxminddb-rust-python/blob/main/CONTRIBUTING.md) for development setup, code quality guidelines, and pull request procedures.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -eu -o pipefail
|
|
4
|
+
|
|
5
|
+
changelog=$(cat CHANGELOG.md)
|
|
6
|
+
|
|
7
|
+
regex='## \[([0-9]+\.[0-9]+\.[0-9]+)\] - ([0-9]{4}-[0-9]{2}-[0-9]{2})
|
|
8
|
+
|
|
9
|
+
((.|
|
|
10
|
+
)*)'
|
|
11
|
+
|
|
12
|
+
if [[ ! $changelog =~ $regex ]]; then
|
|
13
|
+
echo "Could not find version and date line in change log!"
|
|
14
|
+
exit 1
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
version="${BASH_REMATCH[1]}"
|
|
18
|
+
date="${BASH_REMATCH[2]}"
|
|
19
|
+
notes_raw="${BASH_REMATCH[3]}"
|
|
20
|
+
|
|
21
|
+
# Extract notes until the next version heading or [Unreleased] or end
|
|
22
|
+
notes="$(echo "$notes_raw" | sed -n -e '/^## \[/q;p')"
|
|
23
|
+
|
|
24
|
+
if [[ "$date" != $(date +"%Y-%m-%d") ]]; then
|
|
25
|
+
echo "$date is not today!"
|
|
26
|
+
exit 1
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
tag="v$version"
|
|
30
|
+
|
|
31
|
+
if [ -n "$(git status --porcelain)" ]; then
|
|
32
|
+
echo ". is not clean." >&2
|
|
33
|
+
exit 1
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# Update version in pyproject.toml
|
|
37
|
+
perl -pi -e "s/(?<=^version = \").+?(?=\")/$version/gsm" pyproject.toml
|
|
38
|
+
|
|
39
|
+
# Update version in Cargo.toml
|
|
40
|
+
perl -pi -e "s/(?<=^version = \").+?(?=\")/$version/gsm" Cargo.toml
|
|
41
|
+
|
|
42
|
+
echo $"Test results:"
|
|
43
|
+
# Run Rust tests
|
|
44
|
+
cargo test
|
|
45
|
+
|
|
46
|
+
# Build the package
|
|
47
|
+
maturin develop
|
|
48
|
+
|
|
49
|
+
# Run Python tests
|
|
50
|
+
uv run pytest
|
|
51
|
+
|
|
52
|
+
echo $'\nDiff:'
|
|
53
|
+
git diff
|
|
54
|
+
|
|
55
|
+
echo $'\nRelease notes:'
|
|
56
|
+
echo "$notes"
|
|
57
|
+
|
|
58
|
+
read -e -p "Commit changes and push to origin? " should_push
|
|
59
|
+
|
|
60
|
+
if [ "$should_push" != "y" ]; then
|
|
61
|
+
echo "Aborting"
|
|
62
|
+
exit 1
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
if [ -n "$(git status --porcelain)" ]; then
|
|
66
|
+
git commit -m "Update for $tag" -a
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
git push
|
|
70
|
+
|
|
71
|
+
gh release create --target "$(git branch --show-current)" -t "$version" -n "$notes" "$tag"
|
|
72
|
+
|
|
73
|
+
git push --tags
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -4,7 +4,7 @@ build-backend = "maturin"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "maxminddb-rust"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.2.0"
|
|
8
8
|
description = "Rust-based Python binding for MaxMind DB - high-performance alternative to maxminddb"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [
|
|
@@ -36,6 +36,9 @@ keywords = ["maxmind", "geoip", "geolocation", "ip-address", "mmdb"]
|
|
|
36
36
|
Homepage = "https://github.com/oschwald/maxminddb-rust-python"
|
|
37
37
|
Repository = "https://github.com/oschwald/maxminddb-rust-python"
|
|
38
38
|
"Bug Tracker" = "https://github.com/oschwald/maxminddb-rust-python/issues"
|
|
39
|
+
Changelog = "https://github.com/oschwald/maxminddb-rust-python/blob/main/CHANGELOG.md"
|
|
40
|
+
"Migration Guide" = "https://github.com/oschwald/maxminddb-rust-python/blob/main/MIGRATION.md"
|
|
41
|
+
Contributing = "https://github.com/oschwald/maxminddb-rust-python/blob/main/CONTRIBUTING.md"
|
|
39
42
|
|
|
40
43
|
[project.optional-dependencies]
|
|
41
44
|
test = ["pytest>=8.3.5"]
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
use ::maxminddb as maxminddb_crate;
|
|
2
|
-
use maxminddb_crate::{MaxMindDbError, Reader as MaxMindReader, Within,
|
|
2
|
+
use maxminddb_crate::{MaxMindDbError, Reader as MaxMindReader, Within, WithinOptions};
|
|
3
3
|
use memmap2::Mmap;
|
|
4
4
|
use pyo3::{
|
|
5
5
|
conversion::IntoPyObjectExt,
|
|
@@ -253,8 +253,14 @@ impl ReaderSource {
|
|
|
253
253
|
ip: IpAddr,
|
|
254
254
|
) -> Result<Option<PyDecodedValue>, maxminddb_crate::MaxMindDbError> {
|
|
255
255
|
match self {
|
|
256
|
-
ReaderSource::Mmap(reader) =>
|
|
257
|
-
|
|
256
|
+
ReaderSource::Mmap(reader) => {
|
|
257
|
+
let result = reader.lookup(ip)?;
|
|
258
|
+
result.decode()
|
|
259
|
+
}
|
|
260
|
+
ReaderSource::Memory(reader) => {
|
|
261
|
+
let result = reader.lookup(ip)?;
|
|
262
|
+
result.decode()
|
|
263
|
+
}
|
|
258
264
|
}
|
|
259
265
|
}
|
|
260
266
|
|
|
@@ -264,8 +270,20 @@ impl ReaderSource {
|
|
|
264
270
|
ip: IpAddr,
|
|
265
271
|
) -> Result<(Option<PyDecodedValue>, usize), maxminddb_crate::MaxMindDbError> {
|
|
266
272
|
match self {
|
|
267
|
-
ReaderSource::Mmap(reader) =>
|
|
268
|
-
|
|
273
|
+
ReaderSource::Mmap(reader) => {
|
|
274
|
+
let result = reader.lookup(ip)?;
|
|
275
|
+
let network = result.network()?;
|
|
276
|
+
let prefix_len = convert_prefix_len(ip, network);
|
|
277
|
+
let data = result.decode()?;
|
|
278
|
+
Ok((data, prefix_len))
|
|
279
|
+
}
|
|
280
|
+
ReaderSource::Memory(reader) => {
|
|
281
|
+
let result = reader.lookup(ip)?;
|
|
282
|
+
let network = result.network()?;
|
|
283
|
+
let prefix_len = convert_prefix_len(ip, network);
|
|
284
|
+
let data = result.decode()?;
|
|
285
|
+
Ok((data, prefix_len))
|
|
286
|
+
}
|
|
269
287
|
}
|
|
270
288
|
}
|
|
271
289
|
|
|
@@ -278,6 +296,22 @@ impl ReaderSource {
|
|
|
278
296
|
}
|
|
279
297
|
}
|
|
280
298
|
|
|
299
|
+
/// Convert prefix length from database network to the perspective of the queried IP.
|
|
300
|
+
/// When an IPv4 address is looked up in an IPv6 database, the network is returned
|
|
301
|
+
/// in IPv6 terms. We need to convert it back to IPv4 terms for the user.
|
|
302
|
+
#[inline]
|
|
303
|
+
fn convert_prefix_len(queried_ip: IpAddr, network: ipnetwork::IpNetwork) -> usize {
|
|
304
|
+
let prefix = network.prefix() as usize;
|
|
305
|
+
match (queried_ip, network) {
|
|
306
|
+
// IPv4 query, IPv6 result: convert from IPv6 prefix to IPv4 prefix
|
|
307
|
+
// IPv4-mapped IPv6 addresses have a 96-bit prefix (::ffff:0:0/96)
|
|
308
|
+
// So the IPv4-relevant part starts at bit 96
|
|
309
|
+
(IpAddr::V4(_), ipnetwork::IpNetwork::V6(_)) => prefix.saturating_sub(96),
|
|
310
|
+
// Same address family: use prefix as-is
|
|
311
|
+
_ => prefix,
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
281
315
|
/// Metadata about the MaxMind DB database
|
|
282
316
|
#[pyclass(module = "maxminddb_rust.extension")]
|
|
283
317
|
struct Metadata {
|
|
@@ -449,7 +483,7 @@ impl Reader {
|
|
|
449
483
|
match lookup_result {
|
|
450
484
|
Ok(Some(data)) => Ok(data.into_py()),
|
|
451
485
|
Ok(None) => Ok(py.None()),
|
|
452
|
-
Err(MaxMindDbError::InvalidDatabase
|
|
486
|
+
Err(MaxMindDbError::InvalidDatabase { .. } | MaxMindDbError::Decoding { .. }) => {
|
|
453
487
|
Err(InvalidDatabaseError::new_err(ERR_BAD_DATA))
|
|
454
488
|
}
|
|
455
489
|
Err(err) => Err(PyValueError::new_err(format!("Database error: {err}"))),
|
|
@@ -504,7 +538,7 @@ impl Reader {
|
|
|
504
538
|
Ok((py_obj, prefix_len))
|
|
505
539
|
}
|
|
506
540
|
Ok((None, prefix_len)) => Ok((py.None(), prefix_len)),
|
|
507
|
-
Err(MaxMindDbError::InvalidDatabase
|
|
541
|
+
Err(MaxMindDbError::InvalidDatabase { .. } | MaxMindDbError::Decoding { .. }) => {
|
|
508
542
|
Err(InvalidDatabaseError::new_err(ERR_BAD_DATA))
|
|
509
543
|
}
|
|
510
544
|
Err(err) => Err(PyValueError::new_err(format!("Database error: {err}"))),
|
|
@@ -565,7 +599,7 @@ impl Reader {
|
|
|
565
599
|
match result {
|
|
566
600
|
Ok(Some(data)) => objects.push(data.into_py()),
|
|
567
601
|
Ok(None) => objects.push(py.None()),
|
|
568
|
-
Err(MaxMindDbError::InvalidDatabase
|
|
602
|
+
Err(MaxMindDbError::InvalidDatabase { .. } | MaxMindDbError::Decoding { .. }) => {
|
|
569
603
|
return Err(InvalidDatabaseError::new_err(ERR_BAD_DATA));
|
|
570
604
|
}
|
|
571
605
|
Err(err) => {
|
|
@@ -786,15 +820,21 @@ impl ReaderIterator {
|
|
|
786
820
|
let network_obj = class.call1((network_str,))?;
|
|
787
821
|
|
|
788
822
|
// Record is already materialized as a Python object
|
|
789
|
-
let data_obj = next_item.
|
|
823
|
+
let data_obj = next_item.data.into_py();
|
|
790
824
|
|
|
791
825
|
Ok(Some((network_obj.unbind(), data_obj)))
|
|
792
826
|
}
|
|
793
827
|
}
|
|
794
828
|
|
|
795
829
|
enum ReaderWithin {
|
|
796
|
-
Mmap(Within<'static,
|
|
797
|
-
Memory(Within<'static,
|
|
830
|
+
Mmap(Within<'static, Mmap>),
|
|
831
|
+
Memory(Within<'static, Vec<u8>>),
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
/// Result from the within iterator, containing network and decoded data
|
|
835
|
+
struct WithinResult {
|
|
836
|
+
ip_net: ipnetwork::IpNetwork,
|
|
837
|
+
data: PyDecodedValue,
|
|
798
838
|
}
|
|
799
839
|
|
|
800
840
|
impl ReaderWithin {
|
|
@@ -802,36 +842,55 @@ impl ReaderWithin {
|
|
|
802
842
|
reader: &Arc<ReaderSource>,
|
|
803
843
|
network: ipnetwork::IpNetwork,
|
|
804
844
|
) -> Result<Self, maxminddb_crate::MaxMindDbError> {
|
|
845
|
+
let options = WithinOptions::default();
|
|
805
846
|
match reader.as_ref() {
|
|
806
847
|
ReaderSource::Mmap(inner) => {
|
|
807
|
-
let iter = inner.within
|
|
848
|
+
let iter = inner.within(network, options)?;
|
|
808
849
|
// SAFETY: the iterator holds a reference into `inner`. We store an Arc guard
|
|
809
850
|
// alongside it so the reader outlives the transmuted iterator.
|
|
810
851
|
Ok(Self::Mmap(unsafe {
|
|
811
|
-
transmute::<Within<'_,
|
|
812
|
-
iter,
|
|
813
|
-
)
|
|
852
|
+
transmute::<Within<'_, Mmap>, Within<'_, Mmap>>(iter)
|
|
814
853
|
}))
|
|
815
854
|
}
|
|
816
855
|
ReaderSource::Memory(inner) => {
|
|
817
|
-
let iter = inner.within
|
|
856
|
+
let iter = inner.within(network, options)?;
|
|
818
857
|
// SAFETY: same as above, the Arc guard in `ReaderIterator` keeps the reader alive.
|
|
819
858
|
Ok(Self::Memory(unsafe {
|
|
820
|
-
transmute::<
|
|
821
|
-
Within<'_, PyDecodedValue, Vec<u8>>,
|
|
822
|
-
Within<'_, PyDecodedValue, Vec<u8>>,
|
|
823
|
-
>(iter)
|
|
859
|
+
transmute::<Within<'_, Vec<u8>>, Within<'_, Vec<u8>>>(iter)
|
|
824
860
|
}))
|
|
825
861
|
}
|
|
826
862
|
}
|
|
827
863
|
}
|
|
828
864
|
|
|
829
|
-
fn next(
|
|
830
|
-
|
|
831
|
-
|
|
865
|
+
fn next(&mut self) -> Option<Result<WithinResult, maxminddb_crate::MaxMindDbError>> {
|
|
866
|
+
fn process_lookup<S: AsRef<[u8]>>(
|
|
867
|
+
lookup_result: maxminddb_crate::LookupResult<'_, S>,
|
|
868
|
+
) -> Result<WithinResult, MaxMindDbError> {
|
|
869
|
+
let network = lookup_result.network()?;
|
|
870
|
+
let ip_net =
|
|
871
|
+
ipnetwork::IpNetwork::new(network.network(), network.prefix()).map_err(|e| {
|
|
872
|
+
MaxMindDbError::InvalidDatabase {
|
|
873
|
+
message: format!("Invalid network from database: {}", e),
|
|
874
|
+
offset: None,
|
|
875
|
+
}
|
|
876
|
+
})?;
|
|
877
|
+
let data: Option<PyDecodedValue> = lookup_result.decode()?;
|
|
878
|
+
let data = data.ok_or_else(|| MaxMindDbError::InvalidDatabase {
|
|
879
|
+
message: "No data in database record".to_string(),
|
|
880
|
+
offset: None,
|
|
881
|
+
})?;
|
|
882
|
+
Ok(WithinResult { ip_net, data })
|
|
883
|
+
}
|
|
884
|
+
|
|
832
885
|
match self {
|
|
833
|
-
ReaderWithin::Mmap(iter) =>
|
|
834
|
-
|
|
886
|
+
ReaderWithin::Mmap(iter) => {
|
|
887
|
+
let result = iter.next()?;
|
|
888
|
+
Some(result.and_then(process_lookup))
|
|
889
|
+
}
|
|
890
|
+
ReaderWithin::Memory(iter) => {
|
|
891
|
+
let result = iter.next()?;
|
|
892
|
+
Some(result.and_then(process_lookup))
|
|
893
|
+
}
|
|
835
894
|
}
|
|
836
895
|
}
|
|
837
896
|
}
|
|
@@ -380,10 +380,10 @@ class BaseTestReader(unittest.TestCase):
|
|
|
380
380
|
def test_nondatabase(self) -> None:
|
|
381
381
|
with self.assertRaisesRegex(
|
|
382
382
|
InvalidDatabaseError,
|
|
383
|
-
r"Error opening database file \(README.
|
|
383
|
+
r"Error opening database file \(README.md\). "
|
|
384
384
|
r"Is this a valid MaxMind DB file\?",
|
|
385
385
|
):
|
|
386
|
-
open_database("README.
|
|
386
|
+
open_database("README.md", self.mode)
|
|
387
387
|
|
|
388
388
|
# This is from https://github.com/maxmind/MaxMind-DB-Reader-python/issues/58
|
|
389
389
|
def test_database_with_invalid_utf8_key(self) -> None:
|
|
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
|
|
File without changes
|