fastjsonpatch 0.1.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.
- fastjsonpatch-0.1.0/.github/workflows/CI.yml +157 -0
- fastjsonpatch-0.1.0/.gitignore +7 -0
- fastjsonpatch-0.1.0/CHANGELOG.md +11 -0
- fastjsonpatch-0.1.0/Cargo.lock +211 -0
- fastjsonpatch-0.1.0/Cargo.toml +20 -0
- fastjsonpatch-0.1.0/LICENSE +15 -0
- fastjsonpatch-0.1.0/MAINTAINING.md +86 -0
- fastjsonpatch-0.1.0/PKG-INFO +200 -0
- fastjsonpatch-0.1.0/README.md +172 -0
- fastjsonpatch-0.1.0/THIRD_PARTY_LICENSES.md +258 -0
- fastjsonpatch-0.1.0/bench/compare.py +72 -0
- fastjsonpatch-0.1.0/pyproject.toml +40 -0
- fastjsonpatch-0.1.0/python/fastjsonpatch/__init__.py +1020 -0
- fastjsonpatch-0.1.0/scripts/test_linux_matrix.sh +44 -0
- fastjsonpatch-0.1.0/scripts/third_party_licenses.py +63 -0
- fastjsonpatch-0.1.0/src/lib.rs +966 -0
- fastjsonpatch-0.1.0/tests/rfc6902/LICENSE-APACHE-2.0 +176 -0
- fastjsonpatch-0.1.0/tests/rfc6902/README.md +6 -0
- fastjsonpatch-0.1.0/tests/rfc6902/spec_tests.json +233 -0
- fastjsonpatch-0.1.0/tests/rfc6902/test_rfc6902.py +40 -0
- fastjsonpatch-0.1.0/tests/rfc6902/tests.json +500 -0
- fastjsonpatch-0.1.0/tests/test_parity.py +283 -0
- fastjsonpatch-0.1.0/tests/upstream/test_upstream.py +1359 -0
- fastjsonpatch-0.1.0/tests/upstream/tests.js +398 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Tests on every OS / Python, builds wheels for every platform, publishes on tags.
|
|
2
|
+
#
|
|
3
|
+
# - push / pull request: test matrix + wheel builds
|
|
4
|
+
# - manual run with target=testpypi: also publish to TestPyPI
|
|
5
|
+
# - tag v*: also publish to PyPI (the tag must equal the version in pyproject.toml)
|
|
6
|
+
#
|
|
7
|
+
# Publishing uses PyPI trusted publishing (no token): register this repository and
|
|
8
|
+
# workflow on pypi.org / test.pypi.org under the environments "pypi" / "testpypi".
|
|
9
|
+
name: CI
|
|
10
|
+
|
|
11
|
+
on:
|
|
12
|
+
push:
|
|
13
|
+
branches: [main]
|
|
14
|
+
tags: ["v*"]
|
|
15
|
+
pull_request:
|
|
16
|
+
workflow_dispatch:
|
|
17
|
+
inputs:
|
|
18
|
+
target:
|
|
19
|
+
description: "Publish to"
|
|
20
|
+
type: choice
|
|
21
|
+
options: [none, testpypi]
|
|
22
|
+
default: none
|
|
23
|
+
|
|
24
|
+
permissions:
|
|
25
|
+
contents: read
|
|
26
|
+
|
|
27
|
+
jobs:
|
|
28
|
+
test:
|
|
29
|
+
name: test ${{ matrix.os }} py${{ matrix.python }}
|
|
30
|
+
runs-on: ${{ matrix.os }}
|
|
31
|
+
strategy:
|
|
32
|
+
fail-fast: false
|
|
33
|
+
matrix:
|
|
34
|
+
os: [ubuntu-latest, ubuntu-24.04-arm, macos-latest, macos-15-intel, windows-latest]
|
|
35
|
+
python: ["3.12", "3.13", "3.14"]
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v4
|
|
38
|
+
- uses: actions/setup-python@v5
|
|
39
|
+
with:
|
|
40
|
+
python-version: ${{ matrix.python }}
|
|
41
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
42
|
+
- name: Build and install the wheel
|
|
43
|
+
shell: bash
|
|
44
|
+
run: |
|
|
45
|
+
python -m pip install --upgrade pip maturin
|
|
46
|
+
maturin build --release --out dist
|
|
47
|
+
python -m pip install --only-binary fastjsonpatch --find-links dist "fastjsonpatch[test]"
|
|
48
|
+
- name: Tests (parity with jsonpatch, upstream suite, RFC 6902 suite)
|
|
49
|
+
shell: bash
|
|
50
|
+
run: |
|
|
51
|
+
mkdir -p results
|
|
52
|
+
python -m pytest -q -p no:cacheprovider tests 2>&1 | tee pytest.log
|
|
53
|
+
tail -1 pytest.log > results/tests.txt
|
|
54
|
+
- name: Speed vs jsonpatch
|
|
55
|
+
shell: bash
|
|
56
|
+
run: |
|
|
57
|
+
python bench/compare.py > results/compare.json
|
|
58
|
+
python -c "import json, sys; r = json.load(open('results/compare.json')); r['tests'] = open('results/tests.txt').read().strip(); r['runner'] = sys.argv[1]; json.dump(r, open('results/compare.json', 'w'))" "${{ matrix.os }}"
|
|
59
|
+
- uses: actions/upload-artifact@v4
|
|
60
|
+
with:
|
|
61
|
+
name: results-${{ matrix.os }}-${{ matrix.python }}
|
|
62
|
+
path: results/compare.json
|
|
63
|
+
|
|
64
|
+
report:
|
|
65
|
+
name: matrix report
|
|
66
|
+
needs: test
|
|
67
|
+
if: always()
|
|
68
|
+
runs-on: ubuntu-latest
|
|
69
|
+
steps:
|
|
70
|
+
- uses: actions/download-artifact@v4
|
|
71
|
+
with:
|
|
72
|
+
pattern: results-*
|
|
73
|
+
path: results
|
|
74
|
+
- name: Write the comparison table to the job summary
|
|
75
|
+
run: |
|
|
76
|
+
python - <<'EOF' >> "$GITHUB_STEP_SUMMARY"
|
|
77
|
+
import glob, json
|
|
78
|
+
rows = [json.load(open(f)) for f in sorted(glob.glob("results/*/compare.json"))]
|
|
79
|
+
cases = list(rows[0]["results"]) if rows else []
|
|
80
|
+
print("| runner | OS / arch | Python | tests | " + " | ".join(cases) + " |")
|
|
81
|
+
print("|---|---|---|---|" + "---|" * len(cases))
|
|
82
|
+
for r in rows:
|
|
83
|
+
cells = [f"{r['results'][c]['jsonpatch_ms']:.1f} → {r['results'][c]['fastjsonpatch_ms']:.1f} ms "
|
|
84
|
+
f"(**{r['results'][c]['speedup']}x**)" for c in cases]
|
|
85
|
+
print(f"| {r['runner']} | {r['os']} {r['machine']} | {r['python']} | {r['tests']} | " + " | ".join(cells) + " |")
|
|
86
|
+
EOF
|
|
87
|
+
|
|
88
|
+
wheels:
|
|
89
|
+
name: wheel ${{ matrix.platform.name }}
|
|
90
|
+
runs-on: ${{ matrix.platform.runner }}
|
|
91
|
+
strategy:
|
|
92
|
+
fail-fast: false
|
|
93
|
+
matrix:
|
|
94
|
+
platform:
|
|
95
|
+
- { name: linux-x86_64, runner: ubuntu-latest, target: x86_64, manylinux: "2014" }
|
|
96
|
+
- { name: linux-aarch64, runner: ubuntu-24.04-arm, target: aarch64, manylinux: "2014" }
|
|
97
|
+
- { name: musllinux-x86_64, runner: ubuntu-latest, target: x86_64, manylinux: musllinux_1_2 }
|
|
98
|
+
- { name: musllinux-aarch64, runner: ubuntu-24.04-arm, target: aarch64, manylinux: musllinux_1_2 }
|
|
99
|
+
- { name: macos-arm64, runner: macos-latest, target: aarch64 }
|
|
100
|
+
- { name: macos-x86_64, runner: macos-15-intel, target: x86_64 }
|
|
101
|
+
- { name: windows-x64, runner: windows-latest, target: x64 }
|
|
102
|
+
steps:
|
|
103
|
+
- uses: actions/checkout@v4
|
|
104
|
+
- uses: actions/setup-python@v5
|
|
105
|
+
with:
|
|
106
|
+
python-version: "3.12"
|
|
107
|
+
- uses: PyO3/maturin-action@v1
|
|
108
|
+
with:
|
|
109
|
+
target: ${{ matrix.platform.target }}
|
|
110
|
+
manylinux: ${{ matrix.platform.manylinux || 'auto' }}
|
|
111
|
+
args: --release --out dist
|
|
112
|
+
- uses: actions/upload-artifact@v4
|
|
113
|
+
with:
|
|
114
|
+
name: wheel-${{ matrix.platform.name }}
|
|
115
|
+
path: dist
|
|
116
|
+
|
|
117
|
+
sdist:
|
|
118
|
+
runs-on: ubuntu-latest
|
|
119
|
+
steps:
|
|
120
|
+
- uses: actions/checkout@v4
|
|
121
|
+
- uses: PyO3/maturin-action@v1
|
|
122
|
+
with:
|
|
123
|
+
command: sdist
|
|
124
|
+
args: --out dist
|
|
125
|
+
- uses: actions/upload-artifact@v4
|
|
126
|
+
with:
|
|
127
|
+
name: sdist
|
|
128
|
+
path: dist
|
|
129
|
+
|
|
130
|
+
publish:
|
|
131
|
+
name: publish to ${{ startsWith(github.ref, 'refs/tags/v') && 'PyPI' || 'TestPyPI' }}
|
|
132
|
+
needs: [test, wheels, sdist]
|
|
133
|
+
if: startsWith(github.ref, 'refs/tags/v') || inputs.target == 'testpypi'
|
|
134
|
+
runs-on: ubuntu-latest
|
|
135
|
+
environment: ${{ startsWith(github.ref, 'refs/tags/v') && 'pypi' || 'testpypi' }}
|
|
136
|
+
permissions:
|
|
137
|
+
id-token: write # trusted publishing
|
|
138
|
+
steps:
|
|
139
|
+
- uses: actions/checkout@v4
|
|
140
|
+
- name: Tag matches the package version
|
|
141
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
142
|
+
run: |
|
|
143
|
+
version=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")
|
|
144
|
+
test "v$version" = "${GITHUB_REF_NAME}" || { echo "tag ${GITHUB_REF_NAME} != version $version"; exit 1; }
|
|
145
|
+
- uses: actions/download-artifact@v4
|
|
146
|
+
with:
|
|
147
|
+
pattern: wheel-*
|
|
148
|
+
path: dist
|
|
149
|
+
merge-multiple: true
|
|
150
|
+
- uses: actions/download-artifact@v4
|
|
151
|
+
with:
|
|
152
|
+
name: sdist
|
|
153
|
+
path: dist
|
|
154
|
+
- run: ls -la dist
|
|
155
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
156
|
+
with:
|
|
157
|
+
repository-url: ${{ startsWith(github.ref, 'refs/tags/v') && 'https://upload.pypi.org/legacy/' || 'https://test.pypi.org/legacy/' }}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 (2026-10-11)
|
|
4
|
+
|
|
5
|
+
First release. Behaves like jsonpatch 1.34 with `make_patch`, `apply`/`apply_patch`
|
|
6
|
+
and patch validation in Rust:
|
|
7
|
+
|
|
8
|
+
- `make_patch` 9-57x faster, `apply` 6-27x faster (see README).
|
|
9
|
+
- Standalone: depends only on `jsonpointer`.
|
|
10
|
+
- Wheels for Linux (glibc and musl, x86_64 and aarch64), macOS (arm64, x86_64) and
|
|
11
|
+
Windows (x64); one abi3 wheel per platform covers Python 3.12+.
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# This file is automatically @generated by Cargo.
|
|
2
|
+
# It is not intended for manual editing.
|
|
3
|
+
version = 4
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "ahash"
|
|
7
|
+
version = "0.8.12"
|
|
8
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
9
|
+
checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"cfg-if",
|
|
12
|
+
"getrandom",
|
|
13
|
+
"once_cell",
|
|
14
|
+
"version_check",
|
|
15
|
+
"zerocopy",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[[package]]
|
|
19
|
+
name = "cfg-if"
|
|
20
|
+
version = "1.0.5"
|
|
21
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
22
|
+
checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
|
|
23
|
+
|
|
24
|
+
[[package]]
|
|
25
|
+
name = "fastjsonpatch"
|
|
26
|
+
version = "0.1.0"
|
|
27
|
+
dependencies = [
|
|
28
|
+
"ahash",
|
|
29
|
+
"pyo3",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[[package]]
|
|
33
|
+
name = "getrandom"
|
|
34
|
+
version = "0.3.4"
|
|
35
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
36
|
+
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
|
37
|
+
dependencies = [
|
|
38
|
+
"cfg-if",
|
|
39
|
+
"libc",
|
|
40
|
+
"r-efi",
|
|
41
|
+
"wasip2",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[[package]]
|
|
45
|
+
name = "heck"
|
|
46
|
+
version = "0.5.0"
|
|
47
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
48
|
+
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
|
49
|
+
|
|
50
|
+
[[package]]
|
|
51
|
+
name = "libc"
|
|
52
|
+
version = "0.2.190"
|
|
53
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
54
|
+
checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78"
|
|
55
|
+
|
|
56
|
+
[[package]]
|
|
57
|
+
name = "once_cell"
|
|
58
|
+
version = "1.21.4"
|
|
59
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
60
|
+
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
|
61
|
+
|
|
62
|
+
[[package]]
|
|
63
|
+
name = "portable-atomic"
|
|
64
|
+
version = "1.15.0"
|
|
65
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
66
|
+
checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
|
|
67
|
+
|
|
68
|
+
[[package]]
|
|
69
|
+
name = "proc-macro2"
|
|
70
|
+
version = "1.0.107"
|
|
71
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
72
|
+
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
|
73
|
+
dependencies = [
|
|
74
|
+
"unicode-ident",
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
[[package]]
|
|
78
|
+
name = "pyo3"
|
|
79
|
+
version = "0.29.3"
|
|
80
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
81
|
+
checksum = "700d18fa267b73b9b521fd7e13580e2f446916f176cacee1ab63fcc8191f1655"
|
|
82
|
+
dependencies = [
|
|
83
|
+
"libc",
|
|
84
|
+
"once_cell",
|
|
85
|
+
"portable-atomic",
|
|
86
|
+
"pyo3-build-config",
|
|
87
|
+
"pyo3-ffi",
|
|
88
|
+
"pyo3-macros",
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
[[package]]
|
|
92
|
+
name = "pyo3-build-config"
|
|
93
|
+
version = "0.29.3"
|
|
94
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
95
|
+
checksum = "7b3fc0c4d08f6bb10e71fe39dfb9e2f59c6eb6854e22ec8092f50c69a4499adb"
|
|
96
|
+
dependencies = [
|
|
97
|
+
"target-lexicon",
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
[[package]]
|
|
101
|
+
name = "pyo3-ffi"
|
|
102
|
+
version = "0.29.3"
|
|
103
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
104
|
+
checksum = "dfc0b8e19df29aad7086cf977bb0c2a2f143e30567eb113e9cf72b62ca698330"
|
|
105
|
+
dependencies = [
|
|
106
|
+
"libc",
|
|
107
|
+
"pyo3-build-config",
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
[[package]]
|
|
111
|
+
name = "pyo3-macros"
|
|
112
|
+
version = "0.29.3"
|
|
113
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
114
|
+
checksum = "6100e8a4b5eba53afaa5ed078364851a0b2499c553a44c31026b929049b49dc6"
|
|
115
|
+
dependencies = [
|
|
116
|
+
"proc-macro2",
|
|
117
|
+
"pyo3-macros-backend",
|
|
118
|
+
"quote",
|
|
119
|
+
"syn",
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
[[package]]
|
|
123
|
+
name = "pyo3-macros-backend"
|
|
124
|
+
version = "0.29.3"
|
|
125
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
126
|
+
checksum = "6143877a16e82b5a727b7127ff4cd86858a24a28d745d72f43e6f227c7b1bdb3"
|
|
127
|
+
dependencies = [
|
|
128
|
+
"heck",
|
|
129
|
+
"proc-macro2",
|
|
130
|
+
"quote",
|
|
131
|
+
"syn",
|
|
132
|
+
]
|
|
133
|
+
|
|
134
|
+
[[package]]
|
|
135
|
+
name = "quote"
|
|
136
|
+
version = "1.0.47"
|
|
137
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
138
|
+
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
|
139
|
+
dependencies = [
|
|
140
|
+
"proc-macro2",
|
|
141
|
+
]
|
|
142
|
+
|
|
143
|
+
[[package]]
|
|
144
|
+
name = "r-efi"
|
|
145
|
+
version = "5.3.0"
|
|
146
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
147
|
+
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
|
148
|
+
|
|
149
|
+
[[package]]
|
|
150
|
+
name = "syn"
|
|
151
|
+
version = "2.0.119"
|
|
152
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
153
|
+
checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
|
|
154
|
+
dependencies = [
|
|
155
|
+
"proc-macro2",
|
|
156
|
+
"quote",
|
|
157
|
+
"unicode-ident",
|
|
158
|
+
]
|
|
159
|
+
|
|
160
|
+
[[package]]
|
|
161
|
+
name = "target-lexicon"
|
|
162
|
+
version = "0.13.5"
|
|
163
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
164
|
+
checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
|
165
|
+
|
|
166
|
+
[[package]]
|
|
167
|
+
name = "unicode-ident"
|
|
168
|
+
version = "1.0.26"
|
|
169
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
170
|
+
checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954"
|
|
171
|
+
|
|
172
|
+
[[package]]
|
|
173
|
+
name = "version_check"
|
|
174
|
+
version = "0.9.5"
|
|
175
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
176
|
+
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
|
177
|
+
|
|
178
|
+
[[package]]
|
|
179
|
+
name = "wasip2"
|
|
180
|
+
version = "1.0.4+wasi-0.2.12"
|
|
181
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
182
|
+
checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487"
|
|
183
|
+
dependencies = [
|
|
184
|
+
"wit-bindgen",
|
|
185
|
+
]
|
|
186
|
+
|
|
187
|
+
[[package]]
|
|
188
|
+
name = "wit-bindgen"
|
|
189
|
+
version = "0.57.1"
|
|
190
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
191
|
+
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
|
|
192
|
+
|
|
193
|
+
[[package]]
|
|
194
|
+
name = "zerocopy"
|
|
195
|
+
version = "0.8.62"
|
|
196
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
197
|
+
checksum = "86502bf56ac7c77571a32e2647bb2a15894565e981fb2a48d7bde2d91c965a9d"
|
|
198
|
+
dependencies = [
|
|
199
|
+
"zerocopy-derive",
|
|
200
|
+
]
|
|
201
|
+
|
|
202
|
+
[[package]]
|
|
203
|
+
name = "zerocopy-derive"
|
|
204
|
+
version = "0.8.62"
|
|
205
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
206
|
+
checksum = "5457206954b06561e2608c7e19cf58b1926586d999c246eebe4502f7e2039d1a"
|
|
207
|
+
dependencies = [
|
|
208
|
+
"proc-macro2",
|
|
209
|
+
"quote",
|
|
210
|
+
"syn",
|
|
211
|
+
]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "fastjsonpatch"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
edition = "2024"
|
|
5
|
+
description = "Rust core of the fastjsonpatch Python package"
|
|
6
|
+
license = "BSD-3-Clause"
|
|
7
|
+
publish = false
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
|
|
10
|
+
[dependencies]
|
|
11
|
+
ahash = "0.8.12"
|
|
12
|
+
pyo3 = { version = "0.29.3", features = ["extension-module", "abi3-py312"] }
|
|
13
|
+
|
|
14
|
+
[lib]
|
|
15
|
+
name = "_core"
|
|
16
|
+
crate-type = ["cdylib"]
|
|
17
|
+
|
|
18
|
+
[profile.release]
|
|
19
|
+
lto = "fat"
|
|
20
|
+
codegen-units = 1
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, the fastjsonpatch authors
|
|
4
|
+
Copyright (c) 2011 Stefan Kögl <stefan@skoegl.net> (jsonpatch, whose diff algorithm
|
|
5
|
+
src/lib.rs ports)
|
|
6
|
+
|
|
7
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
12
|
+
|
|
13
|
+
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
|
14
|
+
|
|
15
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Maintaining fastjsonpatch
|
|
2
|
+
|
|
3
|
+
## What the package is
|
|
4
|
+
|
|
5
|
+
- `python/fastjsonpatch/__init__.py`: jsonpatch 1.34's module (BSD, notice kept), with
|
|
6
|
+
`JsonPatch.__init__`, `from_diff` and `apply` routed to the Rust core when they can
|
|
7
|
+
be reproduced exactly. Everything else is jsonpatch's code, unchanged.
|
|
8
|
+
- `src/lib.rs`: the Rust core (PyO3). `diff` ports `DiffBuilder`; `apply` runs
|
|
9
|
+
operations on plain dicts/lists and hands anything unusual back to the Python
|
|
10
|
+
operation classes before mutating; `deepcopy` replaces `copy.deepcopy` for JSON.
|
|
11
|
+
- Runtime dependency: `jsonpointer` only. `jsonpatch` is a test dependency: it is the
|
|
12
|
+
reference the parity tests compare against.
|
|
13
|
+
|
|
14
|
+
**The rule:** fastjsonpatch must return the same patches, documents and exceptions as
|
|
15
|
+
jsonpatch 1.34. A behaviour difference is a bug, unless it is listed in the README.
|
|
16
|
+
|
|
17
|
+
## Tests
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
maturin develop --release
|
|
21
|
+
pip install "jsonpatch==1.34" pytest
|
|
22
|
+
pytest tests # ~1570 tests, a few seconds
|
|
23
|
+
python bench/compare.py # speed vs jsonpatch
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
- `tests/test_parity.py`: random documents, mutations and operations (valid and
|
|
27
|
+
invalid), compared with jsonpatch by `repr` and by exception type and message.
|
|
28
|
+
- `tests/upstream/`: jsonpatch's own test suite and doctests, run against us.
|
|
29
|
+
- `tests/rfc6902/`: the json-patch-tests conformance suite (Apache-2.0).
|
|
30
|
+
- `scripts/test_linux_matrix.sh`: installs the built wheels in clean Docker images
|
|
31
|
+
(Debian/Alpine, Python 3.12-3.14) and runs everything there.
|
|
32
|
+
|
|
33
|
+
CI runs the tests and the speed comparison on Linux x86_64/arm64, macOS arm64/x86_64
|
|
34
|
+
and Windows for Python 3.12, 3.13 and 3.14; the run's summary page has the table.
|
|
35
|
+
|
|
36
|
+
## Versions
|
|
37
|
+
|
|
38
|
+
[Semantic versioning](https://semver.org): `MAJOR.MINOR.PATCH`.
|
|
39
|
+
|
|
40
|
+
| change | bump |
|
|
41
|
+
|---|---|
|
|
42
|
+
| bug fix, speed-up, dependency update, same behaviour | PATCH (0.1.0 → 0.1.1) |
|
|
43
|
+
| new feature, existing behaviour unchanged (e.g. an `optimize=` option) | MINOR (0.1 → 0.2) |
|
|
44
|
+
| existing behaviour changes, Python version dropped | MAJOR (after 1.0) |
|
|
45
|
+
|
|
46
|
+
While on 0.x the API may still change between minor versions. Go to 1.0 once the
|
|
47
|
+
package has had real-world use without behaviour bugs.
|
|
48
|
+
|
|
49
|
+
The version lives only in `pyproject.toml` (`[project] version`);
|
|
50
|
+
`fastjsonpatch.__version__` reads it from the installed package. `Cargo.toml` is not
|
|
51
|
+
published and can stay at 0.1.0.
|
|
52
|
+
|
|
53
|
+
## Releasing
|
|
54
|
+
|
|
55
|
+
1. Update the version in `pyproject.toml` and `CHANGELOG.md`; merge to `main` with green CI.
|
|
56
|
+
2. Optional dry run: Actions → CI → "Run workflow" with target `testpypi`, then
|
|
57
|
+
`pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ fastjsonpatch`.
|
|
58
|
+
A version number can be uploaded to TestPyPI only once as well, so use a dev
|
|
59
|
+
version (e.g. `0.1.1.dev1`) for dry runs.
|
|
60
|
+
3. `git tag v0.1.1 && git push origin v0.1.1`. CI checks that the tag equals the
|
|
61
|
+
version, builds every wheel and the sdist, and publishes to PyPI.
|
|
62
|
+
|
|
63
|
+
A version uploaded to PyPI can be yanked (hidden from new installs) but its number can
|
|
64
|
+
never be reused. Fix mistakes with a new PATCH release.
|
|
65
|
+
|
|
66
|
+
## Routine upkeep
|
|
67
|
+
|
|
68
|
+
- **New jsonpatch release:** install it, run the parity tests against it, port any
|
|
69
|
+
behaviour changes (both the Python module and `src/lib.rs`), bump the test pin
|
|
70
|
+
`jsonpatch==X` in `pyproject.toml`, and update `__jsonpatch_version__`.
|
|
71
|
+
- **New Python version:** the wheels use the stable ABI (abi3, Python ≥ 3.12), so they
|
|
72
|
+
install on new Pythons without a rebuild. Add the version to the CI test matrix.
|
|
73
|
+
- **Dropping a Python version:** change `requires-python` and the `abi3-py3XX`
|
|
74
|
+
feature in `Cargo.toml` together, in a MINOR (0.x) or MAJOR release.
|
|
75
|
+
- **Rust dependencies (PyO3, ahash):** `cargo update`, run the tests, then
|
|
76
|
+
`python scripts/third_party_licenses.py` to refresh `THIRD_PARTY_LICENSES.md`.
|
|
77
|
+
- **Bug reports:** reproduce with jsonpatch first. If jsonpatch behaves the same,
|
|
78
|
+
it is not our bug; if not, add the case to `tests/test_parity.py` before fixing.
|
|
79
|
+
|
|
80
|
+
## Licenses
|
|
81
|
+
|
|
82
|
+
- Package: BSD-3-Clause (`LICENSE`), keeping jsonpatch's copyright notice because
|
|
83
|
+
the Python module and the diff algorithm come from it.
|
|
84
|
+
- Wheels include `THIRD_PARTY_LICENSES.md` for the Rust crates compiled into the
|
|
85
|
+
extension (all MIT/Apache-2.0 dual licensed).
|
|
86
|
+
- `tests/rfc6902/` data: Apache-2.0, text in that folder; ships in the sdist only.
|