Skip to content

Commit f37ea32

Browse files
committed
release: abi3 wheels for py3.9+
1 parent 0092b62 commit f37ea32

File tree

6 files changed

+20
-46
lines changed

6 files changed

+20
-46
lines changed

.cargo/config.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[target.aarch64-apple-darwin]
2+
rustflags = ["-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup"]
3+
4+
[target.x86_64-apple-darwin]
5+
rustflags = ["-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup"]
6+

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "agentjson"
3-
version = "0.1.1"
3+
version = "0.1.2"
44
edition = "2021"
55
license = "MIT OR Apache-2.0"
66
description = "Probabilistic JSON repair library powered by Rust"
@@ -14,5 +14,5 @@ crate-type = ["cdylib"]
1414
path = "rust-pyo3/src/lib.rs"
1515

1616
[dependencies]
17-
pyo3 = { version = "0.23", features = ["extension-module"] }
17+
pyo3 = { version = "0.23", features = ["extension-module", "abi3-py39"] }
1818
json_prob_parser = { package = "agentjson-core", path = "rust" }

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ uv add agentjson
5656
# or: python -m pip install agentjson
5757
```
5858

59+
Note: `agentjson` ships **abi3** wheels (Python **3.9+**) so the same wheel works across CPython versions (e.g. 3.11, 3.12).
60+
5961
### Build from source (development)
6062

6163
#### 1) Install Rust toolchain

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "maturin"
44

55
[project]
66
name = "agentjson"
7-
version = "0.1.1"
7+
version = "0.1.2"
88
description = "Probabilistic JSON repair library powered by Rust - fixes broken JSON from LLMs"
99
readme = "README.md"
1010
requires-python = ">=3.9"

rust-pyo3/src/lib.rs

Lines changed: 8 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use pyo3::prelude::*;
2-
use pyo3::buffer::PyBuffer;
3-
use pyo3::types::{PyByteArray, PyBytes, PyDict, PyList};
2+
use pyo3::types::{PyBytes, PyDict, PyList};
43
use pyo3::IntoPyObjectExt;
4+
use std::borrow::Cow;
55

66
use json_prob_parser::beam;
77
use json_prob_parser::json::JsonValue;
@@ -36,57 +36,23 @@ fn json_to_py(py: Python<'_>, v: &JsonValue) -> PyObject {
3636

3737
#[pyfunction]
3838
fn strict_loads_py(py: Python<'_>, input: &Bound<'_, PyAny>) -> PyResult<PyObject> {
39-
let parsed = if let Ok(s) = input.extract::<&str>() {
40-
strict::strict_parse(s)
41-
.map_err(|e| pyo3::exceptions::PyValueError::new_err((e.message, e.pos)))?
42-
} else if let Ok(b) = input.downcast::<PyBytes>() {
43-
let s = std::str::from_utf8(b.as_bytes()).map_err(|_| {
39+
let parsed = if let Ok(s) = input.extract::<Cow<str>>() {
40+
strict::strict_parse(s.as_ref())
41+
} else if let Ok(b) = input.extract::<Cow<[u8]>>() {
42+
let s = std::str::from_utf8(b.as_ref()).map_err(|_| {
4443
pyo3::exceptions::PyValueError::new_err((
4544
"str is not valid UTF-8: surrogates not allowed".to_string(),
4645
0_usize,
4746
))
4847
})?;
4948
strict::strict_parse(s)
50-
.map_err(|e| pyo3::exceptions::PyValueError::new_err((e.message, e.pos)))?
51-
} else if let Ok(ba) = input.downcast::<PyByteArray>() {
52-
let parsed = {
53-
// SAFETY: We do not call back into Python while using this slice.
54-
let bytes = unsafe { ba.as_bytes() };
55-
let s = std::str::from_utf8(bytes).map_err(|_| {
56-
pyo3::exceptions::PyValueError::new_err((
57-
"str is not valid UTF-8: surrogates not allowed".to_string(),
58-
0_usize,
59-
))
60-
})?;
61-
strict::strict_parse(s)
62-
};
63-
parsed.map_err(|e| pyo3::exceptions::PyValueError::new_err((e.message, e.pos)))?
64-
} else if let Ok(buf) = PyBuffer::<u8>::get(input) {
65-
let parsed = {
66-
let cells = buf.as_slice(py).ok_or_else(|| {
67-
pyo3::exceptions::PyValueError::new_err((
68-
"input buffer must be C-contiguous".to_string(),
69-
0_usize,
70-
))
71-
})?;
72-
73-
// ReadOnlyCell<u8> is repr(transparent) over UnsafeCell<u8>, so this is safe.
74-
let bytes = unsafe { std::slice::from_raw_parts(cells.as_ptr() as *const u8, cells.len()) };
75-
let s = std::str::from_utf8(bytes).map_err(|_| {
76-
pyo3::exceptions::PyValueError::new_err((
77-
"str is not valid UTF-8: surrogates not allowed".to_string(),
78-
0_usize,
79-
))
80-
})?;
81-
strict::strict_parse(s)
82-
};
83-
parsed.map_err(|e| pyo3::exceptions::PyValueError::new_err((e.message, e.pos)))?
8449
} else {
8550
return Err(pyo3::exceptions::PyValueError::new_err((
8651
"input must be bytes, bytearray, memoryview, or str".to_string(),
8752
0_usize,
8853
)));
89-
};
54+
}
55+
.map_err(|e| pyo3::exceptions::PyValueError::new_err((e.message, e.pos)))?;
9056

9157
Ok(json_to_py(py, &parsed))
9258
}

0 commit comments

Comments
 (0)