Skip to content

feat: modernize parser bindings and release workflow#6

Merged
digizeph merged 7 commits into
mainfrom
feat/parser-py-modernize-api-ci
Jun 9, 2026
Merged

feat: modernize parser bindings and release workflow#6
digizeph merged 7 commits into
mainfrom
feat/parser-py-modernize-api-ci

Conversation

@digizeph

@digizeph digizeph commented Jun 9, 2026

Copy link
Copy Markdown
Member

Summary

  • Update bgpkit-parser to 0.17.0 and PyO3 to 0.28 with abi3-py39 wheels
  • Add RouteParser, projected tuple iteration, filter helpers, utility methods, benchmarks, and API tests
  • Replace manual release flow with maturin-action wheel builds and PyPI publishing

Validation

  • cargo fmt
  • cargo clippy -- -D warnings
  • cargo bench --no-run
  • maturin develop --release
  • pytest tests/test_api.py
  • python tests/benchmark.py cache/benchmarks/updates.20260601.0000.gz

Notes

  • Requires PYPI_API_TOKEN secret before publishing releases
  • Manual release workflow runs are build-only unless publish=true

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Modernizes the pybgpkit-parser Rust/PyO3 bindings and packaging/release workflow, while expanding the Python API (route-level parsing, projected tuple iteration, filter helpers) and adding benchmark/test scaffolding.

Changes:

  • Upgraded core dependencies (bgpkit-parser 0.17.0, PyO3 0.28 with abi3-py39) and expanded the Python API surface in src/lib.rs.
  • Added Python API tests/benchmarks and Rust Criterion benchmarks to validate behavior and measure overhead.
  • Reworked CI/release workflows to build ABI3 wheels + sdist via maturin-action and publish to PyPI / create GitHub Releases.

Reviewed changes

Copilot reviewed 13 out of 14 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
UPDATE_DESIGN.md Documents the intended one-PR upgrade plan and design decisions.
src/lib.rs Major API expansion (RouteParser/RouteElem, projected tuple iterators, Filter helpers, batch iteration) and PyO3 0.28 adjustments.
Cargo.toml Dependency bumps + Criterion bench configuration.
pyproject.toml Adds PEP 621 project metadata and dev extras.
README.md Documents new Filter API, projected iteration, utilities, and RouteParser.
CHANGELOG.md Adds 0.7.0 release notes draft.
BUILD.md Updates build/publish instructions for the new CI-driven release flow.
benches/parse_bench.rs Adds Criterion benchmarks for native elem/route iteration.
tests/test_api.py Adds API tests (with opt-in network smoke tests).
tests/benchmark.py Adds a manual Python-side benchmark script.
AGENTS.md Adds contributor knowledge base / conventions.
.github/workflows/rust.yaml Adds a Python API test job to CI.
.github/workflows/release.yml New release pipeline: checks, wheel/sdist builds, PyPI upload, GH release.
.gitignore Ignores Python bytecode / __pycache__.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pyproject.toml
Comment on lines +8 to +12
description = "Python binding for bgpkit-parser"
readme = "README.md"
requires-python = ">=3.9"
license = "MIT"
classifiers = [
Comment on lines 7 to +10
push:
tags:
- v[0-9]+.*
- "v*"
workflow_dispatch:
Comment thread src/lib.rs Outdated
Comment on lines +582 to +597
unsafe impl Send for Parser {}
unsafe impl Sync for Parser {}
unsafe impl Send for BatchIterator {}
unsafe impl Sync for BatchIterator {}
unsafe impl Send for RouteParser {}
unsafe impl Sync for RouteParser {}
unsafe impl Send for RouteBatchIterator {}
unsafe impl Sync for RouteBatchIterator {}
unsafe impl Send for TupleIterator {}
unsafe impl Sync for TupleIterator {}
unsafe impl Send for TupleBatchIterator {}
unsafe impl Sync for TupleBatchIterator {}
unsafe impl Send for RouteTupleIterator {}
unsafe impl Sync for RouteTupleIterator {}
unsafe impl Send for RouteTupleBatchIterator {}
unsafe impl Sync for RouteTupleBatchIterator {}
Comment thread src/lib.rs
Comment on lines +748 to +756
fn __next__(mut slf: PyRefMut<Self>, py: Python) -> PyResult<Option<Py<PyTuple>>> {
let fields = slf.fields.clone();
let Some(elem_iter) = slf.elem_iter.as_mut() else {
return Ok(None);
};
elem_iter
.next()
.map(|elem| elem_to_tuple(py, elem, &fields))
.transpose()
Comment thread src/lib.rs Outdated
Comment on lines +767 to +786
let fields = slf.fields.clone();
let batch_size = slf.batch_size;
let Some(elem_iter) = slf.elem_iter.as_mut() else {
return Ok(None);
};

let elems = py.detach(|| {
elem_iter
.by_ref()
.take(batch_size)
.collect::<Vec<BgpElem>>()
});
if elems.is_empty() {
slf.elem_iter = None;
return Ok(None);
}

elems
.into_iter()
.map(|elem| elem_to_tuple(py, elem, &fields))
Comment thread src/lib.rs
Comment on lines +913 to +921
fn __next__(mut slf: PyRefMut<Self>, py: Python) -> PyResult<Option<Py<PyTuple>>> {
let fields = slf.fields.clone();
let Some(route_iter) = slf.route_iter.as_mut() else {
return Ok(None);
};
route_iter
.next()
.map(|route| route_to_tuple(py, route, &fields))
.transpose()
Comment thread src/lib.rs Outdated
Comment on lines +932 to +953
let fields = slf.fields.clone();
let batch_size = slf.batch_size;
let Some(route_iter) = slf.route_iter.as_mut() else {
return Ok(None);
};

let routes = py.detach(|| {
route_iter
.by_ref()
.take(batch_size)
.collect::<Vec<BgpRouteElem>>()
});
if routes.is_empty() {
slf.route_iter = None;
return Ok(None);
}

routes
.into_iter()
.map(|route| route_to_tuple(py, route, &fields))
.collect::<PyResult<Vec<_>>>()
.map(Some)
Comment thread .github/workflows/rust.yaml Outdated
Comment on lines +22 to +34
python-api:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install test tools
run: python -m pip install --upgrade pip maturin pytest pytest-benchmark
- name: Build extension in-place
run: maturin develop
- name: Run Python API tests
run: pytest tests/test_api.py
Comment thread AGENTS.md Outdated
Comment on lines +80 to +83
- `bgpkit-parser` crate version bump is the primary release trigger (see CHANGELOG for version history)
- Release workflow: `rust.yaml` runs Rust + Python API checks on PR/push; `release.yml` builds ABI3 wheels and publishes on `v*` tag push
- Supports Python 3.9+ via ABI3 wheels
- No Python tests in-repo; examples in `examples/` serve as smoke tests

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 14 changed files in this pull request and generated 7 comments.

Comment thread src/lib.rs
Comment on lines +370 to +391
#[staticmethod]
pub fn get_psv_header() -> String {
[
"type",
"timestamp",
"peer_ip",
"peer_asn",
"prefix",
"as_path",
"origin_asns",
"origin",
"next_hop",
"local_pref",
"med",
"communities",
"atomic",
"aggr_asn",
"aggr_ip",
"only_to_customer",
]
.join("|")
}
Comment thread src/lib.rs
Comment on lines +393 to +412
pub fn to_psv(&self) -> String {
format!(
"{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}",
self.elem_type,
self.timestamp,
self.peer_ip,
self.peer_asn,
self.prefix,
option_to_string(&self.as_path),
option_vec_to_string(&self.origin_asns),
option_to_string(&self.origin),
option_to_string(&self.next_hop),
option_to_string(&self.local_pref),
option_to_string(&self.med),
option_vec_to_string(&self.communities),
option_to_string(&self.atomic),
option_to_string(&self.aggr_asn),
option_to_string(&self.aggr_ip),
option_to_string(&self.only_to_customer),
)
Comment thread .github/workflows/rust.yaml Outdated
Comment on lines +35 to +38
- name: Run Python API tests
run: pytest tests/test_api.py
env:
PYBGPKIT_RUN_NETWORK_TESTS: "1"
Comment on lines 8 to +11
push:
tags:
- v[0-9]+.*
- "v[0-9]*.[0-9]*.[0-9]*"
workflow_dispatch:
Comment thread AGENTS.md
Comment on lines +3 to +6
## OVERVIEW

Python binding for `bgpkit-parser` (Rust MRT/BGP parser). Exposes a single `Parser` class and `Elem` dataclass via PyO3, built with maturin.

Comment thread AGENTS.md
Comment on lines +39 to +43
- Rust fmt/clippy enforced in CI (`cargo fmt --check`, `cargo clippy -- -D warnings`)
- `PyValueError` used for filter errors propagated to Python
- `unsafe impl Send + Sync for Parser` — required because `ElemIterator<Box<dyn Send + Read>>` is not auto-Send
- `#[pyo3(name = "__str__")]` used for JSON string representation of `Elem`
- `atomic` field returns `"AG"`/`"NAG"` strings (not bool)
Comment thread UPDATE_DESIGN.md Outdated
Comment on lines +79 to +84
### 9. `unsafe impl Send/Sync` for `Parser`

**Decision:** Keep and verify after the `bgpkit-parser` bump.

**Rationale:** The `ElemIterator` type may have changed in v0.17.0. If `BgpkitParser::into_iter()` no longer returns `Send`, we switch to a different approach (e.g., `into_elem_iter()` or `into_fallible_elem_iter()`).

@digizeph digizeph merged commit f38981e into main Jun 9, 2026
2 checks passed
@digizeph digizeph deleted the feat/parser-py-modernize-api-ci branch June 9, 2026 02:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants