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.
Files changed (36) hide show
  1. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/.githooks/pre-commit +0 -0
  2. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/.github/workflows/codeql.yml +4 -4
  3. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/.github/workflows/lint.yml +6 -6
  4. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/.github/workflows/release.yml +2 -2
  5. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/.github/workflows/test.yml +2 -2
  6. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/.github/workflows/zizmor.yml +2 -2
  7. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/CHANGELOG.md +8 -0
  8. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/Cargo.lock +3 -3
  9. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/Cargo.toml +2 -2
  10. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/PKG-INFO +13 -10
  11. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/README.md +9 -9
  12. maxminddb_rust-0.2.0/dev-bin/release.sh +73 -0
  13. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/examples/basic_usage.py +0 -0
  14. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/examples/batch_processing.py +0 -0
  15. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/examples/benchmark.py +0 -0
  16. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/examples/benchmark_batch.py +0 -0
  17. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/examples/context_manager.py +0 -0
  18. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/examples/iterator_demo.py +0 -0
  19. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/pyproject.toml +4 -1
  20. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/src/lib.rs +84 -25
  21. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/tests/maxmind/reader_test.py +2 -2
  22. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/uv.lock +1 -1
  23. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/.github/dependabot.yml +0 -0
  24. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/.gitignore +0 -0
  25. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/.gitmodules +0 -0
  26. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/CONTRIBUTING.md +0 -0
  27. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/LICENSE +0 -0
  28. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/MIGRATION.md +0 -0
  29. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/benchmark_comprehensive.py +0 -0
  30. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/maxminddb_rust.pyi +0 -0
  31. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/precious.toml +0 -0
  32. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/py.typed +0 -0
  33. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/tests/__init__.py +0 -0
  34. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/tests/maxmind/README.md +0 -0
  35. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/tests/maxmind/UPSTREAM_LICENSE +0 -0
  36. {maxminddb_rust-0.1.0 → maxminddb_rust-0.2.0}/tests/maxmind/__init__.py +0 -0
@@ -21,7 +21,7 @@ jobs:
21
21
 
22
22
  steps:
23
23
  - name: Checkout repository
24
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
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@6d653acede28d24f02e3cd41383119e8b1b35921 # master
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@v3
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@v3
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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
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@6d653acede28d24f02e3cd41383119e8b1b35921 # master
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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
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@6d653acede28d24f02e3cd41383119e8b1b35921 # master
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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
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@6d653acede28d24f02e3cd41383119e8b1b35921 # master
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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
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@e673c3917a1aef3c65c972347ed84ccd013ecda4 # v0.2.0
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.26.0"
62
+ version = "0.27.0"
63
63
  source = "registry+https://github.com/rust-lang/crates.io-index"
64
- checksum = "2a197e44322788858682406c74b0b59bf8d9b4954fe1f224d9a25147f1880bba"
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.1.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.1.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.26.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.1.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
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "maxminddb-rust"
7
- version = "0.1.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, WithinItem};
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) => reader.lookup(ip),
257
- ReaderSource::Memory(reader) => reader.lookup(ip),
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) => reader.lookup_prefix(ip),
268
- ReaderSource::Memory(reader) => reader.lookup_prefix(ip),
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(_) | MaxMindDbError::Decoding(_)) => {
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(_) | MaxMindDbError::Decoding(_)) => {
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(_) | MaxMindDbError::Decoding(_)) => {
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.info.into_py();
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, PyDecodedValue, Mmap>),
797
- Memory(Within<'static, PyDecodedValue, Vec<u8>>),
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::<PyDecodedValue>(network)?;
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<'_, PyDecodedValue, Mmap>, Within<'_, PyDecodedValue, Mmap>>(
812
- iter,
813
- )
852
+ transmute::<Within<'_, Mmap>, Within<'_, Mmap>>(iter)
814
853
  }))
815
854
  }
816
855
  ReaderSource::Memory(inner) => {
817
- let iter = inner.within::<PyDecodedValue>(network)?;
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
- &mut self,
831
- ) -> Option<Result<WithinItem<PyDecodedValue>, maxminddb_crate::MaxMindDbError>> {
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) => iter.next(),
834
- ReaderWithin::Memory(iter) => iter.next(),
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.rst\). "
383
+ r"Error opening database file \(README.md\). "
384
384
  r"Is this a valid MaxMind DB file\?",
385
385
  ):
386
- open_database("README.rst", self.mode)
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:
@@ -55,7 +55,7 @@ wheels = [
55
55
 
56
56
  [[package]]
57
57
  name = "maxminddb-rust"
58
- version = "0.1.0"
58
+ version = "0.2.0"
59
59
  source = { editable = "." }
60
60
 
61
61
  [package.optional-dependencies]
File without changes
File without changes