diff --git a/.github/workflows/debug.yaml b/.github/workflows/debug.yaml index 68cdfb1e..c04ac046 100644 --- a/.github/workflows/debug.yaml +++ b/.github/workflows/debug.yaml @@ -8,7 +8,7 @@ jobs: fail-fast: false matrix: rust: [ - { version: "1.60" }, # MSRV + { version: "1.65" }, # MSRV { version: "nightly-2023-08-30" }, ] python: [ @@ -28,7 +28,7 @@ jobs: python-version: '${{ matrix.python.version }}' - run: python -m pip install --user --upgrade pip "maturin>=1,<2" wheel - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: build run: | diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index a4155ff2..e9b6dc63 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -10,7 +10,7 @@ jobs: - run: curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain=stable --profile=default -y - run: pip install -U autoflake isort black ruff mypy types-python-dateutil types-pytz types-simplejson types-ujson - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: cargo fmt - run: ./script/lint diff --git a/.github/workflows/linux.yaml b/.github/workflows/linux.yaml index b851c372..2a594258 100644 --- a/.github/workflows/linux.yaml +++ b/.github/workflows/linux.yaml @@ -7,12 +7,12 @@ jobs: strategy: fail-fast: false env: - RUST_TOOLCHAIN: "1.60" # MSRV + RUST_TOOLCHAIN: "1.65" # MSRV steps: - run: curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain $RUST_TOOLCHAIN -y - run: rustup default $RUST_TOOLCHAIN - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: python3 -m pip install --user --upgrade pip "maturin>=1,<2" wheel @@ -73,10 +73,9 @@ jobs: - run: yum install -y clang lld - run: curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain nightly-2023-08-30 --profile minimal -y - run: rustup component add rust-src --toolchain nightly-2023-08-30-x86_64-unknown-linux-gnu - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: build-std - if: matrix.target.arch != 'aarch64' run: | mkdir .cargo cp ci/config.toml .cargo/config.toml @@ -128,10 +127,9 @@ jobs: arch: x86_64 platform: linux/amd64 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: build-std - if: matrix.target.arch != 'aarch64' run: | mkdir .cargo cp ci/config.toml .cargo/config.toml @@ -153,7 +151,7 @@ jobs: - name: Set up QEMU if: matrix.platform.arch != 'x86_64' - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 with: image: tonistiigi/binfmt:qemu-v7.0.0 platforms: ${{ matrix.platform.platform }} @@ -216,10 +214,9 @@ jobs: }, ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: build-std - if: matrix.target.arch != 'aarch64' run: | mkdir .cargo cp ci/config.toml .cargo/config.toml diff --git a/Cargo.lock b/Cargo.lock index f8ec5823..3d35dd4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,9 +24,9 @@ dependencies = [ [[package]] name = "associative-cache" -version = "1.0.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46016233fc1bb55c23b856fe556b7db6ccd05119a0a392e04f0b3b7c79058f16" +checksum = "b993cd767a2bc7307dd87622311ca22c44329cc7a21366206bfa0896827b2bad" [[package]] name = "autocfg" @@ -45,11 +45,11 @@ dependencies = [ [[package]] name = "bytecount" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c" +checksum = "ad152d03a2c813c80bb94fedbf3a3f02b28f793e39e7c214c8a0bcc196343de7" dependencies = [ - "packed_simd_2", + "packed_simd", ] [[package]] @@ -78,9 +78,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.30" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defd4e7873dbddba6c7c91e199c7fcb946abc4a6a4ac3195400bcfb01b5de877" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ "num-traits", ] @@ -126,21 +126,15 @@ checksum = "9028f49264629065d057f340a86acb84867925865f73bbf8d47b4d149a7e88b8" [[package]] name = "libc" -version = "0.2.147" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" - -[[package]] -name = "libm" -version = "0.1.4" +version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" [[package]] name = "libm" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "no-panic" @@ -155,12 +149,12 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", - "libm 0.2.7", + "libm", ] [[package]] @@ -205,21 +199,11 @@ dependencies = [ "num-traits", ] -[[package]] -name = "packed_simd_2" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282" -dependencies = [ - "cfg-if", - "libm 0.1.4", -] - [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] @@ -290,9 +274,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.105" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" dependencies = [ "itoa", "ryu", @@ -307,9 +291,9 @@ checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" [[package]] name = "smallvec" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" [[package]] name = "static_assertions" @@ -319,9 +303,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "syn" -version = "2.0.31" +version = "2.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" dependencies = [ "proc-macro2", "quote", @@ -336,9 +320,9 @@ checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "version_check" diff --git a/Cargo.toml b/Cargo.toml index 8ca77f73..fc2b932d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ authors = ["ijl "] description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" edition = "2021" resolver = "2" -rust-version = "1.60" +rust-version = "1.65" license = "Apache-2.0 OR MIT" repository = "https://github.com/ijl/orjson" homepage = "https://github.com/ijl/orjson" @@ -50,9 +50,9 @@ yyjson = [] [dependencies] ahash = { version = "0.8", default_features = false } arrayvec = { version = "0.7", default_features = false, features = ["std", "serde"] } -associative-cache = { version = "1", default_features = false } +associative-cache = { version = "2", default_features = false } beef = { version = "0.5", default_features = false, features = ["impl_serde"] } -bytecount = { version = "^0.6.3", default_features = false, features = ["runtime-dispatch-simd"] } +bytecount = { version = "^0.6.4", default_features = false, features = ["runtime-dispatch-simd"] } chrono = { version = "^0.4.24", default_features = false } compact_str = { version = "0.7", default_features = false, features = ["serde"] } encoding_rs = { version = "0.8", default_features = false } diff --git a/README.md b/README.md index cec9fc18..3f964ac0 100644 --- a/README.md +++ b/README.md @@ -1183,7 +1183,7 @@ Probably not. ## Packaging -To package orjson requires at least [Rust](https://www.rust-lang.org/) 1.60 +To package orjson requires at least [Rust](https://www.rust-lang.org/) 1.65 and the [maturin](https://github.com/PyO3/maturin) build tool. The recommended build command is: @@ -1195,7 +1195,7 @@ It benefits from also having a C build environment to compile a faster deserialization backend. See this project's `manylinux_2_28` builds for an example using clang and LTO. -The project's own CI tests against `nightly-2023-08-30` and stable 1.60. It +The project's own CI tests against `nightly-2023-08-30` and stable 1.65. It is prudent to pin the nightly version because that channel can introduce breaking changes. diff --git a/ci/azure-pipelines.yml b/ci/azure-pipelines.yml index 306b88d7..94d91432 100644 --- a/ci/azure-pipelines.yml +++ b/ci/azure-pipelines.yml @@ -12,7 +12,7 @@ jobs: steps: - task: UsePythonVersion@0 inputs: - versionSpec: '3.12.0-rc.1' + versionSpec: '3.12.0' addToPath: true allowUnstable: true - checkout: self @@ -79,13 +79,13 @@ jobs: pool: vmImage: windows-2022 variables: - interpreter: C:\hostedtoolcache\windows\Python\3.12.0-rc.1\x64\python.exe + interpreter: C:\hostedtoolcache\windows\Python\3.12.0\x64\python.exe rustup: https://win.rustup.rs/x86_64 target: x86_64-pc-windows-msvc steps: - task: UsePythonVersion@0 inputs: - versionSpec: '3.12.0-rc.1' + versionSpec: '3.12.0' addToPath: true allowUnstable: true architecture: 'x64' @@ -160,13 +160,13 @@ jobs: pool: vmImage: windows-2022 variables: - interpreter: C:\hostedtoolcache\windows\Python\3.12.0-rc.1\x86\python.exe + interpreter: C:\hostedtoolcache\windows\Python\3.12.0\x86\python.exe rustup: https://win.rustup.rs/x86 target: i686-pc-windows-msvc steps: - task: UsePythonVersion@0 inputs: - versionSpec: '3.12.0-rc.1' + versionSpec: '3.12.0' addToPath: true allowUnstable: true architecture: 'x86' diff --git a/pyproject.toml b/pyproject.toml index aa3e11cf..276703ed 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,6 +16,7 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python", "Programming Language :: Rust", diff --git a/src/util.rs b/src/util.rs index 44884eeb..3c17ddad 100644 --- a/src/util.rs +++ b/src/util.rs @@ -168,7 +168,7 @@ macro_rules! str_hash { #[cfg(Py_3_13)] macro_rules! pydict_contains { ($obj1:expr, $obj2:expr) => { - unsafe { pyo3_ffi::PyDict_Contains((*$obj1).tp_dict, $obj2) == 1 } + unsafe { pyo3_ffi::PyDict_Contains(pyo3_ffi::PyType_GetDict($obj1), $obj2) == 1 } }; } diff --git a/test/test_circular.py b/test/test_circular.py index 993a768d..89ec6ae1 100644 --- a/test/test_circular.py +++ b/test/test_circular.py @@ -15,6 +15,24 @@ def test_circular_dict(self): with pytest.raises(orjson.JSONEncodeError): orjson.dumps(obj) + def test_circular_dict_sort_keys(self): + """ + dumps() circular reference dict OPT_SORT_KEYS + """ + obj = {} # type: ignore + obj["obj"] = obj + with pytest.raises(orjson.JSONEncodeError): + orjson.dumps(obj, option=orjson.OPT_SORT_KEYS) + + def test_circular_dict_non_str_keys(self): + """ + dumps() circular reference dict OPT_NON_STR_KEYS + """ + obj = {} # type: ignore + obj["obj"] = obj + with pytest.raises(orjson.JSONEncodeError): + orjson.dumps(obj, option=orjson.OPT_NON_STR_KEYS) + def test_circular_list(self): """ dumps() circular reference list @@ -32,3 +50,21 @@ def test_circular_nested(self): obj["list"] = [{"obj": obj}] with pytest.raises(orjson.JSONEncodeError): orjson.dumps(obj) + + def test_circular_nested_sort_keys(self): + """ + dumps() circular reference nested dict, list OPT_SORT_KEYS + """ + obj = {} # type: ignore + obj["list"] = [{"obj": obj}] + with pytest.raises(orjson.JSONEncodeError): + orjson.dumps(obj, option=orjson.OPT_SORT_KEYS) + + def test_circular_nested_non_str_keys(self): + """ + dumps() circular reference nested dict, list OPT_NON_STR_KEYS + """ + obj = {} # type: ignore + obj["list"] = [{"obj": obj}] + with pytest.raises(orjson.JSONEncodeError): + orjson.dumps(obj, option=orjson.OPT_NON_STR_KEYS)