Compare commits

...

19 Commits

Author SHA1 Message Date
Ashwin Naren
c968fe0fd9 remove macos skips 2025-06-15 17:36:13 +09:00
Ashwin Naren
125f14190a Remove unnecessary uv runin README (#5792)
* Update README.md

Remove unnecessary `uv run`

* uv comment

---------

Co-authored-by: Jeong YunWon <jeong@youknowone.org>
2025-06-15 16:10:27 +09:00
Jeong YunWon
a6dd2d805b Skip test_local_unknown_cert to avoid CI failure 2025-06-15 16:04:37 +09:00
Jeong YunWon
6723bf30a7 Fix deque module name for test_repr 2025-06-15 16:04:37 +09:00
Jeong YunWon
2c61a12bed Apply coderabbit reviews 2025-06-15 16:03:46 +09:00
Jeong YunWon
f560b4cbfb Fix nightly clippy warnings 2025-06-15 16:03:46 +09:00
dependabot[bot]
4e094eaa55 Bump webpack-dev-server from 5.2.0 to 5.2.1 in /wasm/demo (#5801)
Bumps [webpack-dev-server](https://github.com/webpack/webpack-dev-server) from 5.2.0 to 5.2.1.
- [Release notes](https://github.com/webpack/webpack-dev-server/releases)
- [Changelog](https://github.com/webpack/webpack-dev-server/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-dev-server/compare/v5.2.0...v5.2.1)

---
updated-dependencies:
- dependency-name: webpack-dev-server
  dependency-version: 5.2.1
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-06 23:17:32 +09:00
Jeong, YunWon
2e368baf2a Fix Nightly clippy (#5798) 2025-06-06 22:00:07 +09:00
Aneesh Durg
323ea3b96b Support incomplete parsing (#5764)
* continue accepting REPL input for multiline strings

* Match cpython behavior for all multi-line statements (execute when complete)

* Emit _IncompleteInputError when compiling with incomplete flag

* Refine when _IncompleteInputError is emitted

* Support multiline strings emitting _IncompleteInputError

* lint

* Undo accidental change to PyTabError

* match -> if let

* Fix test_baseexception and test_codeop

* fix spelling

* fix exception name

* Skip pickle test of _IncompleteInputError

* Use py3.15's codeop implementation

* Update Lib/test/test_baseexception.py

---------

Co-authored-by: Jeong, YunWon <69878+youknowone@users.noreply.github.com>
2025-06-05 14:41:56 +09:00
Noa
e27d03179f Remove getrandom 0.2 from dependencies 2025-05-21 12:12:14 +09:00
Jeong YunWon
81a9002ef2 Rename Dockerfile 2025-05-20 11:10:13 +09:00
Noa
18521290bf Update dependencies 2025-05-19 14:41:24 +09:00
Noa
5e682e3f17 Merge pull request #5788 from coolreader18/fix-prec
Fix panic with high precision
2025-05-16 20:28:25 -05:00
Noa
163296d306 Fix test_memoryio 2025-05-16 15:20:10 -05:00
Noa
1ae98ee177 Fix panic with high precision 2025-05-16 14:17:25 -05:00
Noa
2c02e2776b Fix warnings for rust 1.87 2025-05-16 18:52:14 +09:00
Ashwin Naren
72dc4954ad dev container update 2025-05-16 18:25:08 +09:00
Rex Ledesma
b696e56c5f chore: rely on the default inclusions for ruff 2025-05-15 19:15:51 +09:00
dependabot[bot]
d11d5c65e6 Bump streetsidesoftware/cspell-action in the github-actions group
Bumps the github-actions group with 1 update: [streetsidesoftware/cspell-action](https://github.com/streetsidesoftware/cspell-action).


Updates `streetsidesoftware/cspell-action` from 6 to 7
- [Release notes](https://github.com/streetsidesoftware/cspell-action/releases)
- [Changelog](https://github.com/streetsidesoftware/cspell-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/streetsidesoftware/cspell-action/compare/v6...v7)

---
updated-dependencies:
- dependency-name: streetsidesoftware/cspell-action
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-13 04:08:12 +09:00
57 changed files with 597 additions and 374 deletions

6
.devcontainer/Dockerfile Normal file
View File

@@ -0,0 +1,6 @@
FROM mcr.microsoft.com/vscode/devcontainers/rust:1-bullseye
# Install clang
RUN apt-get update \
&& apt-get install -y clang \
&& rm -rf /var/lib/apt/lists/*

View File

@@ -1,4 +1,25 @@
{
"image": "mcr.microsoft.com/devcontainers/base:jammy",
"onCreateCommand": "curl https://sh.rustup.rs -sSf | sh -s -- -y"
}
"name": "Rust",
"build": {
"dockerfile": "Dockerfile"
},
"runArgs": ["--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined"],
"customizations": {
"vscode": {
"settings": {
"lldb.executable": "/usr/bin/lldb",
// VS Code don't watch files under ./target
"files.watcherExclude": {
"**/target/**": true
},
"extensions": [
"rust-lang.rust-analyzer",
"tamasfe.even-better-toml",
"vadimcn.vscode-lldb",
"mutantdino.resourcemonitor"
]
}
}
},
"remoteUser": "vscode"
}

View File

@@ -32,11 +32,6 @@ env:
test_pathlib
test_posixpath
test_venv
# configparser: https://github.com/RustPython/RustPython/issues/4995#issuecomment-1582397417
# socketserver: seems related to configparser crash.
MACOS_SKIPS: >-
test_configparser
test_socketserver
# PLATFORM_INDEPENDENT_TESTS are tests that do not depend on the underlying OS. They are currently
# only run on Linux to speed up the CI.
PLATFORM_INDEPENDENT_TESTS: >-
@@ -284,7 +279,7 @@ jobs:
run: target/release/rustpython -m test -j 1 -u all --slowest --fail-env-changed -v -x ${{ env.PLATFORM_INDEPENDENT_TESTS }}
- if: runner.os == 'macOS'
name: run cpython platform-dependent tests (MacOS)
run: target/release/rustpython -m test -j 1 --slowest --fail-env-changed -v -x ${{ env.PLATFORM_INDEPENDENT_TESTS }} ${{ env.MACOS_SKIPS }}
run: target/release/rustpython -m test -j 1 --slowest --fail-env-changed -v -x ${{ env.PLATFORM_INDEPENDENT_TESTS }}
- if: runner.os == 'Windows'
name: run cpython platform-dependent tests (windows partial - fixme)
run:
@@ -340,7 +335,7 @@ jobs:
- name: install extra dictionaries
run: npm install @cspell/dict-en_us @cspell/dict-cpp @cspell/dict-python @cspell/dict-rust @cspell/dict-win32 @cspell/dict-shell
- name: spell checker
uses: streetsidesoftware/cspell-action@v6
uses: streetsidesoftware/cspell-action@v7
with:
files: '**/*.rs'
incremental_files_only: true

272
Cargo.lock generated
View File

@@ -16,15 +16,15 @@ checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
[[package]]
name = "ahash"
version = "0.8.11"
version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
dependencies = [
"cfg-if",
"getrandom 0.2.15",
"getrandom 0.3.2",
"once_cell",
"version_check",
"zerocopy 0.7.35",
"zerocopy",
]
[[package]]
@@ -115,9 +115,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.97"
version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
[[package]]
name = "approx"
@@ -178,7 +178,7 @@ dependencies = [
"regex",
"rustc-hash",
"shlex",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@@ -213,9 +213,9 @@ dependencies = [
[[package]]
name = "bstr"
version = "1.11.3"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0"
checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4"
dependencies = [
"memchr",
"regex-automata",
@@ -233,9 +233,9 @@ dependencies = [
[[package]]
name = "bytemuck"
version = "1.22.0"
version = "1.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540"
checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c"
[[package]]
name = "bzip2"
@@ -283,9 +283,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.2.18"
version = "1.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c"
checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0"
dependencies = [
"shlex",
]
@@ -313,9 +313,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "chrono"
version = "0.4.40"
version = "0.4.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
dependencies = [
"android-tzdata",
"iana-time-zone",
@@ -365,18 +365,18 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.36"
version = "4.5.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04"
checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.5.36"
version = "4.5.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5"
checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120"
dependencies = [
"anstyle",
"clap_lex",
@@ -850,9 +850,9 @@ dependencies = [
[[package]]
name = "error-code"
version = "3.3.1"
version = "3.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f"
checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59"
[[package]]
name = "exitcode"
@@ -963,9 +963,9 @@ dependencies = [
[[package]]
name = "gethostname"
version = "1.0.1"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed7131e57abbde63513e0e6636f76668a1ca9798dcae2df4e283cae9ee83859e"
checksum = "fc257fdb4038301ce4b9cd1b3b51704509692bb3ff716a410cbd07925d9dae55"
dependencies = [
"rustix",
"windows-targets 0.52.6",
@@ -982,15 +982,13 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.15"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
dependencies = [
"cfg-if",
"js-sys",
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
"wasm-bindgen",
]
[[package]]
@@ -1026,9 +1024,9 @@ checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
[[package]]
name = "half"
version = "2.5.0"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7db2ff139bba50379da6aa0766b52fdcb62cb5b263009b09ed58ba604e14bbd1"
checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9"
dependencies = [
"cfg-if",
"crunchy",
@@ -1036,9 +1034,9 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.15.2"
version = "0.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
dependencies = [
"foldhash",
]
@@ -1057,9 +1055,9 @@ checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
[[package]]
name = "hermit-abi"
version = "0.5.0"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e"
checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08"
[[package]]
name = "hex"
@@ -1124,14 +1122,12 @@ checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
[[package]]
name = "insta"
version = "1.42.2"
version = "1.43.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50259abbaa67d11d2bcafc7ba1d094ed7a0c70e3ce893f0d0997f73558cb3084"
checksum = "154934ea70c58054b556dd430b99a98c2a7ff5309ac9891597e339b5c28f4371"
dependencies = [
"console",
"linked-hash-map",
"once_cell",
"pin-project",
"similar",
]
@@ -1144,7 +1140,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@@ -1153,7 +1149,7 @@ version = "0.4.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9"
dependencies = [
"hermit-abi 0.5.0",
"hermit-abi 0.5.1",
"libc",
"windows-sys 0.59.0",
]
@@ -1199,9 +1195,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "jiff"
version = "0.2.5"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c102670231191d07d37a35af3eb77f1f0dbf7a71be51a962dcd57ea607be7260"
checksum = "f02000660d30638906021176af16b17498bd0d12813dbfe7b276d8bc7f3c0806"
dependencies = [
"jiff-static",
"log",
@@ -1212,13 +1208,13 @@ dependencies = [
[[package]]
name = "jiff-static"
version = "0.2.5"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cdde31a9d349f1b1f51a0b3714a5940ac022976f4b49485fc04be052b183b4c"
checksum = "f3c30758ddd7188629c6713fc45d1188af4f44c90582311d0c8d8c9907f60c48"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@@ -1300,15 +1296,15 @@ checksum = "0864a00c8d019e36216b69c2c4ce50b83b7bd966add3cf5ba554ec44f8bebcf5"
[[package]]
name = "libc"
version = "0.2.171"
version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]]
name = "libffi"
version = "4.0.0"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a9434b6fc77375fb624698d5f8c49d7e80b10d59eb1219afda27d1f824d4074"
checksum = "ebfd30a67b482a08116e753d0656cb626548cf4242543e5cc005be7639d99838"
dependencies = [
"libc",
"libffi-sys",
@@ -1316,9 +1312,9 @@ dependencies = [
[[package]]
name = "libffi-sys"
version = "3.2.0"
version = "3.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ead36a2496acfc8edd6cc32352110e9478ac5b9b5f5b9856ebd3d28019addb84"
checksum = "f003aa318c9f0ee69eb0ada7c78f5c9d2fedd2ceb274173b5c7ff475eee584a3"
dependencies = [
"cc",
]
@@ -1335,9 +1331,9 @@ dependencies = [
[[package]]
name = "libm"
version = "0.2.11"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa"
checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
[[package]]
name = "libredox"
@@ -1369,17 +1365,11 @@ dependencies = [
"zlib-rs",
]
[[package]]
name = "linked-hash-map"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]]
name = "linux-raw-sys"
version = "0.9.3"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
[[package]]
name = "lock_api"
@@ -1537,9 +1527,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniz_oxide"
version = "0.8.7"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430"
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
dependencies = [
"adler2",
]
@@ -1639,7 +1629,7 @@ checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@@ -1677,7 +1667,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@@ -1688,18 +1678,18 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
[[package]]
name = "openssl-src"
version = "300.4.2+3.4.1"
version = "300.5.0+3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "168ce4e058f975fe43e89d9ccf78ca668601887ae736090aacc23ae353c298e2"
checksum = "e8ce546f549326b0e6052b649198487d91320875da901e7bd11a06d1ee3f9c2f"
dependencies = [
"cc",
]
[[package]]
name = "openssl-sys"
version = "0.9.107"
version = "0.9.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07"
checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847"
dependencies = [
"cc",
"libc",
@@ -1742,7 +1732,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [
"cfg-if",
"libc",
"redox_syscall 0.5.11",
"redox_syscall 0.5.12",
"smallvec",
"windows-targets 0.52.6",
]
@@ -1791,26 +1781,6 @@ dependencies = [
"siphasher",
]
[[package]]
name = "pin-project"
version = "1.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
]
[[package]]
name = "pkg-config"
version = "0.3.32"
@@ -1853,7 +1823,7 @@ checksum = "52a40bc70c2c58040d2d8b167ba9a5ff59fc9dab7ad44771cfde3dcfde7a09c6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@@ -1877,7 +1847,7 @@ version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
dependencies = [
"zerocopy 0.8.24",
"zerocopy",
]
[[package]]
@@ -1887,14 +1857,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6"
dependencies = [
"proc-macro2",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
name = "proc-macro2"
version = "1.0.94"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
@@ -1910,9 +1880,9 @@ dependencies = [
[[package]]
name = "pyo3"
version = "0.24.1"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17da310086b068fbdcefbba30aeb3721d5bb9af8db4987d6735b2183ca567229"
checksum = "e5203598f366b11a02b13aa20cab591229ff0a89fd121a308a5df751d5fc9219"
dependencies = [
"cfg-if",
"indoc",
@@ -1928,9 +1898,9 @@ dependencies = [
[[package]]
name = "pyo3-build-config"
version = "0.24.1"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e27165889bd793000a098bb966adc4300c312497ea25cf7a690a9f0ac5aa5fc1"
checksum = "99636d423fa2ca130fa5acde3059308006d46f98caac629418e53f7ebb1e9999"
dependencies = [
"once_cell",
"target-lexicon",
@@ -1938,9 +1908,9 @@ dependencies = [
[[package]]
name = "pyo3-ffi"
version = "0.24.1"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05280526e1dbf6b420062f3ef228b78c0c54ba94e157f5cb724a609d0f2faabc"
checksum = "78f9cf92ba9c409279bc3305b5409d90db2d2c22392d443a87df3a1adad59e33"
dependencies = [
"libc",
"pyo3-build-config",
@@ -1948,27 +1918,27 @@ dependencies = [
[[package]]
name = "pyo3-macros"
version = "0.24.1"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c3ce5686aa4d3f63359a5100c62a127c9f15e8398e5fdeb5deef1fed5cd5f44"
checksum = "0b999cb1a6ce21f9a6b147dcf1be9ffedf02e0043aec74dc390f3007047cecd9"
dependencies = [
"proc-macro2",
"pyo3-macros-backend",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
name = "pyo3-macros-backend"
version = "0.24.1"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4cf6faa0cbfb0ed08e89beb8103ae9724eb4750e3a78084ba4017cbe94f3855"
checksum = "822ece1c7e1012745607d5cf0bcb2874769f0f7cb34c4cde03b9358eb9ef911a"
dependencies = [
"heck",
"proc-macro2",
"pyo3-build-config",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@@ -2017,13 +1987,12 @@ dependencies = [
[[package]]
name = "rand"
version = "0.9.0"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
dependencies = [
"rand_chacha 0.9.0",
"rand_core 0.9.3",
"zerocopy 0.8.24",
]
[[package]]
@@ -2052,7 +2021,7 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom 0.2.15",
"getrandom 0.2.16",
]
[[package]]
@@ -2092,9 +2061,9 @@ checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]]
name = "redox_syscall"
version = "0.5.11"
version = "0.5.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3"
checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af"
dependencies = [
"bitflags 2.9.0",
]
@@ -2105,7 +2074,7 @@ version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
dependencies = [
"getrandom 0.2.15",
"getrandom 0.2.16",
"libredox",
"thiserror 1.0.69",
]
@@ -2183,7 +2152,7 @@ dependencies = [
"pmutil",
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@@ -2255,9 +2224,9 @@ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
[[package]]
name = "rustix"
version = "1.0.5"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf"
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
dependencies = [
"bitflags 2.9.0",
"errno",
@@ -2346,7 +2315,7 @@ dependencies = [
name = "rustpython-compiler"
version = "0.4.0"
dependencies = [
"rand 0.9.0",
"rand 0.9.1",
"ruff_python_ast",
"ruff_python_parser",
"ruff_source_file",
@@ -2386,7 +2355,7 @@ dependencies = [
"proc-macro2",
"rustpython-compiler",
"rustpython-derive-impl",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@@ -2399,7 +2368,7 @@ dependencies = [
"quote",
"rustpython-compiler-core",
"rustpython-doc",
"syn 2.0.100",
"syn 2.0.101",
"syn-ext",
"textwrap",
]
@@ -2435,7 +2404,7 @@ dependencies = [
"is-macro",
"lexical-parse-float",
"num-traits",
"rand 0.9.0",
"rand 0.9.1",
"rustpython-wtf8",
"unic-ucd-category",
]
@@ -2631,7 +2600,6 @@ name = "rustpython_wasm"
version = "0.4.0"
dependencies = [
"console_error_panic_hook",
"getrandom 0.2.15",
"js-sys",
"ruff_python_parser",
"rustpython-common",
@@ -2732,7 +2700,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@@ -2760,9 +2728,9 @@ dependencies = [
[[package]]
name = "sha2"
version = "0.10.8"
version = "0.10.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [
"cfg-if",
"cpufeatures",
@@ -2849,7 +2817,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustversion",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@@ -2871,9 +2839,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.100"
version = "2.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
dependencies = [
"proc-macro2",
"quote",
@@ -2888,7 +2856,7 @@ checksum = "b126de4ef6c2a628a68609dd00733766c3b015894698a438ebdf374933fc31d1"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@@ -2968,7 +2936,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@@ -2979,7 +2947,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@@ -3320,7 +3288,7 @@ dependencies = [
"log",
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
"wasm-bindgen-shared",
]
@@ -3355,7 +3323,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -3480,7 +3448,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@@ -3491,7 +3459,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@@ -3693,9 +3661,9 @@ dependencies = [
[[package]]
name = "xml-rs"
version = "0.8.25"
version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4"
checksum = "a62ce76d9b56901b19a74f19431b0d8b3bc7ca4ad685a746dfd78ca8f4fc6bda"
[[package]]
name = "xz2"
@@ -3708,42 +3676,22 @@ dependencies = [
[[package]]
name = "zerocopy"
version = "0.7.35"
version = "0.8.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb"
dependencies = [
"zerocopy-derive 0.7.35",
]
[[package]]
name = "zerocopy"
version = "0.8.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879"
dependencies = [
"zerocopy-derive 0.8.24",
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.35"
version = "0.8.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]

10
Lib/codeop.py vendored
View File

@@ -65,14 +65,10 @@ def _maybe_compile(compiler, source, filename, symbol):
try:
compiler(source + "\n", filename, symbol)
return None
except _IncompleteInputError as e:
return None
except SyntaxError as e:
# XXX: RustPython; support multiline definitions in REPL
# See also: https://github.com/RustPython/RustPython/pull/5743
strerr = str(e)
if source.endswith(":") and "expected an indented block" in strerr:
return None
elif "incomplete input" in str(e):
return None
pass
# fallthrough
return compiler(source, filename, symbol, incomplete_input=False)

View File

@@ -83,6 +83,8 @@ class ExceptionClassTests(unittest.TestCase):
exc_set = set(e for e in exc_set if not e.startswith('_'))
# RUSTPYTHON specific
exc_set.discard("JitError")
# TODO: RUSTPYTHON; this will be officially introduced in Python 3.15
exc_set.discard("IncompleteInputError")
self.assertEqual(len(exc_set), 0, "%s not accounted for" % exc_set)
interface_tests = ("length", "args", "str", "repr")

View File

@@ -2088,8 +2088,6 @@ class TestDocString(unittest.TestCase):
self.assertDocStrEqual(C.__doc__, "C(x:List[int]=<factory>)")
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_docstring_deque_field(self):
@dataclass
class C:
@@ -2097,8 +2095,6 @@ class TestDocString(unittest.TestCase):
self.assertDocStrEqual(C.__doc__, "C(x:collections.deque)")
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_docstring_deque_field_with_default_factory(self):
@dataclass
class C:

View File

@@ -1,3 +1,4 @@
import sys
import errno
from http import client, HTTPStatus
import io
@@ -1781,6 +1782,7 @@ class HTTPSTest(TestCase):
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.skipIf(sys.platform == 'darwin', 'Occasionally success on macOS')
def test_local_unknown_cert(self):
# The custom cert isn't known to the default trust bundle
import ssl

View File

@@ -664,6 +664,9 @@ class CompatPickleTests(unittest.TestCase):
BaseExceptionGroup,
ExceptionGroup):
continue
# TODO: RUSTPYTHON: fix name mapping for _IncompleteInputError
if exc is _IncompleteInputError:
continue
if exc is not OSError and issubclass(exc, OSError):
self.assertEqual(reverse_mapping('builtins', name),
('exceptions', 'OSError'))

View File

@@ -82,8 +82,6 @@ class ReprTests(unittest.TestCase):
expected = repr(t3)[:-2] + "+++)"
eq(r3.repr(t3), expected)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_container(self):
from array import array
from collections import deque

View File

@@ -226,7 +226,7 @@ To enhance CPython compatibility, try to increase unittest coverage by checking
Another approach is to checkout the source code: builtin functions and object
methods are often the simplest and easiest way to contribute.
You can also simply run `uv run python -I whats_left.py` to assist in finding any unimplemented
You can also simply run `python -I whats_left.py` to assist in finding any unimplemented
method.
## Compiling to WebAssembly

View File

@@ -151,7 +151,7 @@ pub fn compile_program(
let mut compiler = Compiler::new(opts, source_code, "<module>".to_owned());
compiler.compile_program(ast, symbol_table)?;
let code = compiler.pop_code_object();
trace!("Compilation completed: {:?}", code);
trace!("Compilation completed: {code:?}");
Ok(code)
}
@@ -166,7 +166,7 @@ pub fn compile_program_single(
let mut compiler = Compiler::new(opts, source_code, "<module>".to_owned());
compiler.compile_program_single(&ast.body, symbol_table)?;
let code = compiler.pop_code_object();
trace!("Compilation completed: {:?}", code);
trace!("Compilation completed: {code:?}");
Ok(code)
}
@@ -180,7 +180,7 @@ pub fn compile_block_expression(
let mut compiler = Compiler::new(opts, source_code, "<module>".to_owned());
compiler.compile_block_expr(&ast.body, symbol_table)?;
let code = compiler.pop_code_object();
trace!("Compilation completed: {:?}", code);
trace!("Compilation completed: {code:?}");
Ok(code)
}
@@ -233,7 +233,7 @@ fn eprint_location(zelf: &Compiler<'_>) {
fn unwrap_internal<T>(zelf: &Compiler<'_>, r: InternalResult<T>) -> T {
if let Err(ref r_err) = r {
eprintln!("=== CODEGEN PANIC INFO ===");
eprintln!("This IS an internal error: {}", r_err);
eprintln!("This IS an internal error: {r_err}");
eprint_location(zelf);
eprintln!("=== END PANIC INFO ===");
}
@@ -671,7 +671,7 @@ impl Compiler<'_> {
fn compile_statement(&mut self, statement: &Stmt) -> CompileResult<()> {
use ruff_python_ast::*;
trace!("Compiling {:?}", statement);
trace!("Compiling {statement:?}");
self.set_source_range(statement.range());
match &statement {
@@ -1907,7 +1907,7 @@ impl Compiler<'_> {
fn compile_error_forbidden_name(&mut self, name: &str) -> CodegenError {
// TODO: make into error (fine for now since it realistically errors out earlier)
panic!("Failing due to forbidden name {:?}", name);
panic!("Failing due to forbidden name {name:?}");
}
/// Ensures that `pc.fail_pop` has at least `n + 1` entries.
@@ -3209,7 +3209,7 @@ impl Compiler<'_> {
fn compile_expression(&mut self, expression: &Expr) -> CompileResult<()> {
use ruff_python_ast::*;
trace!("Compiling {:?}", expression);
trace!("Compiling {expression:?}");
let range = expression.range();
self.set_source_range(range);
@@ -4432,7 +4432,7 @@ pub fn ruff_int_to_bigint(int: &Int) -> Result<BigInt, CodegenErrorType> {
fn parse_big_integer(int: &Int) -> Result<BigInt, CodegenErrorType> {
// TODO: Improve ruff API
// Can we avoid this copy?
let s = format!("{}", int);
let s = format!("{int}");
let mut s = s.as_str();
// See: https://peps.python.org/pep-0515/#literal-grammar
let radix = match s.get(0..2) {

View File

@@ -1388,12 +1388,12 @@ impl Instruction {
let value = ctx.get_constant(idx.get(arg) as usize);
match value.borrow_constant() {
BorrowedConstant::Code { code } if expand_code_objects => {
write!(f, "{:pad$}({:?}):", op, code)?;
write!(f, "{op:pad$}({code:?}):")?;
code.display_inner(f, true, level + 1)?;
Ok(())
}
c => {
write!(f, "{:pad$}(", op)?;
write!(f, "{op:pad$}(")?;
c.fmt_display(f)?;
write!(f, ")")
}

View File

@@ -55,6 +55,7 @@ pub fn format_fixed(precision: usize, magnitude: f64, case: Case, alternate_form
match magnitude {
magnitude if magnitude.is_finite() => {
let point = decimal_point_or_empty(precision, alternate_form);
let precision = std::cmp::min(precision, u16::MAX as usize);
format!("{magnitude:.precision$}{point}")
}
magnitude if magnitude.is_nan() => format_nan(case),

View File

@@ -25,6 +25,7 @@ pub enum CompileErrorType {
pub struct ParseError {
#[source]
pub error: parser::ParseErrorType,
pub raw_location: ruff_text_size::TextRange,
pub location: SourceLocation,
pub source_path: String,
}
@@ -48,6 +49,7 @@ impl CompileError {
let location = source_code.source_location(error.location.start());
Self::Parse(ParseError {
error: error.error,
raw_location: error.location,
location,
source_path: source_code.path.to_owned(),
})

View File

@@ -1,4 +1,4 @@
""" This script can be used to test the equivalence in parsing between
"""This script can be used to test the equivalence in parsing between
rustpython and cpython.
Usage example:
@@ -8,76 +8,80 @@ $ cargo run crawl_sourcecode.py crawl_sourcecode.py > rustpython.txt
$ diff cpython.txt rustpython.txt
"""
import ast
import sys
import symtable
import dis
filename = sys.argv[1]
print('Crawling file:', filename)
print("Crawling file:", filename)
with open(filename, 'r') as f:
with open(filename, "r") as f:
source = f.read()
t = ast.parse(source)
print(t)
shift = 3
def print_node(node, indent=0):
indents = ' ' * indent
indents = " " * indent
if isinstance(node, ast.AST):
lineno = 'row={}'.format(node.lineno) if hasattr(node, 'lineno') else ''
lineno = "row={}".format(node.lineno) if hasattr(node, "lineno") else ""
print(indents, "NODE", node.__class__.__name__, lineno)
for field in node._fields:
print(indents,'-', field)
print(indents, "-", field)
f = getattr(node, field)
if isinstance(f, list):
for f2 in f:
print_node(f2, indent=indent+shift)
print_node(f2, indent=indent + shift)
else:
print_node(f, indent=indent+shift)
print_node(f, indent=indent + shift)
else:
print(indents, 'OBJ', node)
print(indents, "OBJ", node)
print_node(t)
# print(ast.dump(t))
flag_names = [
'is_referenced',
'is_assigned',
'is_global',
'is_local',
'is_parameter',
'is_free',
"is_referenced",
"is_assigned",
"is_global",
"is_local",
"is_parameter",
"is_free",
]
def print_table(table, indent=0):
indents = ' ' * indent
print(indents, 'table:', table.get_name())
print(indents, ' ', 'name:', table.get_name())
print(indents, ' ', 'type:', table.get_type())
print(indents, ' ', 'line:', table.get_lineno())
print(indents, ' ', 'identifiers:', table.get_identifiers())
print(indents, ' ', 'Syms:')
indents = " " * indent
print(indents, "table:", table.get_name())
print(indents, " ", "name:", table.get_name())
print(indents, " ", "type:", table.get_type())
print(indents, " ", "line:", table.get_lineno())
print(indents, " ", "identifiers:", table.get_identifiers())
print(indents, " ", "Syms:")
for sym in table.get_symbols():
flags = []
for flag_name in flag_names:
func = getattr(sym, flag_name)
if func():
flags.append(flag_name)
print(indents, ' sym:', sym.get_name(), 'flags:', ' '.join(flags))
print(indents, " sym:", sym.get_name(), "flags:", " ".join(flags))
if table.has_children():
print(indents, ' ', 'Child tables:')
print(indents, " ", "Child tables:")
for child in table.get_children():
print_table(child, indent=indent+shift)
print_table(child, indent=indent + shift)
table = symtable.symtable(source, 'a', 'exec')
table = symtable.symtable(source, "a", "exec")
print_table(table)
print()
print('======== dis.dis ========')
print("======== dis.dis ========")
print()
co = compile(source, filename, 'exec')
co = compile(source, filename, "exec")
dis.dis(co)

View File

@@ -1,13 +1,12 @@
def foo(x):
def bar(z):
return z + x
return bar
f = foo(9)
g = foo(10)
print(f(2))
print(g(2))

View File

@@ -1165,8 +1165,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
// ----- Merge: Return the final result.
self.builder.switch_to_block(merge_block);
let final_val = self.builder.block_params(merge_block)[0];
final_val
self.builder.block_params(merge_block)[0]
}
fn compile_ipow(&mut self, a: Value, b: Value) -> Value {

View File

@@ -15,7 +15,13 @@ pub enum JitCompileError {
#[error("bad bytecode")]
BadBytecode,
#[error("error while compiling to machine code: {0}")]
CraneliftError(#[from] ModuleError),
CraneliftError(Box<ModuleError>),
}
impl From<ModuleError> for JitCompileError {
fn from(err: ModuleError) -> Self {
Self::CraneliftError(Box::new(err))
}
}
#[derive(Debug, thiserror::Error, Eq, PartialEq)]

View File

@@ -78,7 +78,7 @@ impl StackMachine {
pub fn run(&mut self, code: CodeObject) {
let mut oparg_state = OpArgState::default();
code.instructions.iter().try_for_each(|&word| {
let _ = code.instructions.iter().try_for_each(|&word| {
let (instruction, arg) = oparg_state.get(word);
self.process_instruction(instruction, arg, &code.constants, &code.names)
});

View File

@@ -1,11 +1,4 @@
include = [
"examples/**/*.py",
"extra_tests/**/*.py",
"wasm/**/*.py",
]
exclude = [
".*",
"Lib",
"vm/Lib",
"benches",

View File

@@ -3,18 +3,21 @@ import subprocess
TARGET = "extra_tests/snippets"
def run_llvm_cov(file_path: str):
""" Run cargo llvm-cov on a file. """
"""Run cargo llvm-cov on a file."""
if file_path.endswith(".py"):
command = ["cargo", "llvm-cov", "--no-report", "run", "--", file_path]
subprocess.call(command)
def iterate_files(folder: str):
""" Iterate over all files in a folder. """
"""Iterate over all files in a folder."""
for root, _, files in os.walk(folder):
for file in files:
file_path = os.path.join(root, file)
run_llvm_cov(file_path)
if __name__ == "__main__":
iterate_files(TARGET)
iterate_files(TARGET)

View File

@@ -10,21 +10,26 @@ How to use:
4. Ensure that there are no unexpected successes in the test.
5. Actually fix the test.
"""
import argparse
import ast
import itertools
import platform
from pathlib import Path
def parse_args():
parser = argparse.ArgumentParser(description="Fix test.")
parser.add_argument("--path", type=Path, help="Path to test file")
parser.add_argument("--force", action="store_true", help="Force modification")
parser.add_argument("--platform", action="store_true", help="Platform specific failure")
parser.add_argument(
"--platform", action="store_true", help="Platform specific failure"
)
args = parser.parse_args()
return args
class Test:
name: str = ""
path: str = ""
@@ -33,6 +38,7 @@ class Test:
def __str__(self):
return f"Test(name={self.name}, path={self.path}, result={self.result})"
class TestResult:
tests_result: str = ""
tests = []
@@ -52,7 +58,11 @@ def parse_results(result):
in_test_results = True
elif line.startswith("-----------"):
in_test_results = False
if in_test_results and not line.startswith("tests") and not line.startswith("["):
if (
in_test_results
and not line.startswith("tests")
and not line.startswith("[")
):
line = line.split(" ")
if line != [] and len(line) > 3:
test = Test()
@@ -67,9 +77,11 @@ def parse_results(result):
test_results.tests_result = res
return test_results
def path_to_test(path) -> list[str]:
return path.split(".")[2:]
def modify_test(file: str, test: list[str], for_platform: bool = False) -> str:
a = ast.parse(file)
lines = file.splitlines()
@@ -84,6 +96,7 @@ def modify_test(file: str, test: list[str], for_platform: bool = False) -> str:
break
return "\n".join(lines)
def modify_test_v2(file: str, test: list[str], for_platform: bool = False) -> str:
a = ast.parse(file)
lines = file.splitlines()
@@ -101,8 +114,13 @@ def modify_test_v2(file: str, test: list[str], for_platform: bool = False) -> st
if fn.name == test[-1]:
assert not for_platform
indent = " " * fn.col_offset
lines.insert(fn.lineno - 1, indent + fixture)
lines.insert(fn.lineno - 1, indent + "# TODO: RUSTPYTHON")
lines.insert(
fn.lineno - 1, indent + fixture
)
lines.insert(
fn.lineno - 1,
indent + "# TODO: RUSTPYTHON",
)
break
case ast.FunctionDef():
if n.name == test[0] and len(test) == 1:
@@ -115,11 +133,17 @@ def modify_test_v2(file: str, test: list[str], for_platform: bool = False) -> st
exit()
return "\n".join(lines)
def run_test(test_name):
print(f"Running test: {test_name}")
rustpython_location = "./target/release/rustpython"
import subprocess
result = subprocess.run([rustpython_location, "-m", "test", "-v", test_name], capture_output=True, text=True)
result = subprocess.run(
[rustpython_location, "-m", "test", "-v", test_name],
capture_output=True,
text=True,
)
return parse_results(result)

View File

@@ -197,12 +197,12 @@ fn run_rustpython(vm: &VirtualMachine, run_mode: RunMode) -> PyResult<()> {
}
let res = match run_mode {
RunMode::Command(command) => {
debug!("Running command {}", command);
debug!("Running command {command}");
vm.run_code_string(scope.clone(), &command, "<stdin>".to_owned())
.map(drop)
}
RunMode::Module(module) => {
debug!("Running module {}", module);
debug!("Running module {module}");
vm.run_module(&module)
}
RunMode::InstallPip(installer) => install_pip(installer, scope.clone(), vm),

View File

@@ -1,7 +1,8 @@
mod helper;
use rustpython_compiler::{
CompileError, ParseError, parser::LexicalErrorType, parser::ParseErrorType,
CompileError, ParseError, parser::FStringErrorType, parser::LexicalErrorType,
parser::ParseErrorType,
};
use rustpython_vm::{
AsObject, PyResult, VirtualMachine,
@@ -14,7 +15,8 @@ use rustpython_vm::{
enum ShellExecResult {
Ok,
PyErr(PyBaseExceptionRef),
Continue,
ContinueBlock,
ContinueLine,
}
fn shell_exec(
@@ -22,11 +24,17 @@ fn shell_exec(
source: &str,
scope: Scope,
empty_line_given: bool,
continuing: bool,
continuing_block: bool,
) -> ShellExecResult {
// compiling expects only UNIX style line endings, and will replace windows line endings
// internally. Since we might need to analyze the source to determine if an error could be
// resolved by future input, we need the location from the error to match the source code that
// was actually compiled.
#[cfg(windows)]
let source = &source.replace("\r\n", "\n");
match vm.compile(source, compiler::Mode::Single, "<stdin>".to_owned()) {
Ok(code) => {
if empty_line_given || !continuing {
if empty_line_given || !continuing_block {
// We want to execute the full code
match vm.run_code_obj(code, scope) {
Ok(_val) => ShellExecResult::Ok,
@@ -40,8 +48,32 @@ fn shell_exec(
Err(CompileError::Parse(ParseError {
error: ParseErrorType::Lexical(LexicalErrorType::Eof),
..
})) => ShellExecResult::Continue,
})) => ShellExecResult::ContinueLine,
Err(CompileError::Parse(ParseError {
error:
ParseErrorType::Lexical(LexicalErrorType::FStringError(
FStringErrorType::UnterminatedTripleQuotedString,
)),
..
})) => ShellExecResult::ContinueLine,
Err(err) => {
// Check if the error is from an unclosed triple quoted string (which should always
// continue)
if let CompileError::Parse(ParseError {
error: ParseErrorType::Lexical(LexicalErrorType::UnclosedStringError),
raw_location,
..
}) = err
{
let loc = raw_location.start().to_usize();
let mut iter = source.chars();
if let Some(quote) = iter.nth(loc) {
if iter.next() == Some(quote) && iter.next() == Some(quote) {
return ShellExecResult::ContinueLine;
}
}
};
// bad_error == true if we are handling an error that should be thrown even if we are continuing
// if its an indentation error, set to true if we are continuing and the error is on column 0,
// since indentations errors on columns other than 0 should be ignored.
@@ -50,10 +82,12 @@ fn shell_exec(
let bad_error = match err {
CompileError::Parse(ref p) => {
match &p.error {
ParseErrorType::Lexical(LexicalErrorType::IndentationError) => continuing, // && p.location.is_some()
ParseErrorType::Lexical(LexicalErrorType::IndentationError) => {
continuing_block
} // && p.location.is_some()
ParseErrorType::OtherError(msg) => {
if msg.starts_with("Expected an indented block") {
continuing
continuing_block
} else {
true
}
@@ -68,7 +102,7 @@ fn shell_exec(
if empty_line_given || bad_error {
ShellExecResult::PyErr(vm.new_syntax_error(&err, Some(source)))
} else {
ShellExecResult::Continue
ShellExecResult::ContinueBlock
}
}
}
@@ -93,10 +127,19 @@ pub fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> {
println!("No previous history.");
}
let mut continuing = false;
// We might either be waiting to know if a block is complete, or waiting to know if a multiline
// statement is complete. In the former case, we need to ensure that we read one extra new line
// to know that the block is complete. In the latter, we can execute as soon as the statement is
// valid.
let mut continuing_block = false;
let mut continuing_line = false;
loop {
let prompt_name = if continuing { "ps2" } else { "ps1" };
let prompt_name = if continuing_block || continuing_line {
"ps2"
} else {
"ps1"
};
let prompt = vm
.sys_module
.get_attr(prompt_name, vm)
@@ -105,9 +148,12 @@ pub fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> {
Ok(ref s) => s.as_str(),
Err(_) => "",
};
continuing_line = false;
let result = match repl.readline(prompt) {
ReadlineResult::Line(line) => {
debug!("You entered {:?}", line);
#[cfg(debug_assertions)]
debug!("You entered {line:?}");
repl.add_history_entry(line.trim_end()).unwrap();
@@ -120,39 +166,44 @@ pub fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> {
}
full_input.push('\n');
match shell_exec(vm, &full_input, scope.clone(), empty_line_given, continuing) {
match shell_exec(
vm,
&full_input,
scope.clone(),
empty_line_given,
continuing_block,
) {
ShellExecResult::Ok => {
if continuing {
if continuing_block {
if empty_line_given {
// We should be exiting continue mode
continuing = false;
// We should exit continue mode since the block successfully executed
continuing_block = false;
full_input.clear();
Ok(())
} else {
// We should stay in continue mode
continuing = true;
Ok(())
}
} else {
// We aren't in continue mode so proceed normally
continuing = false;
full_input.clear();
Ok(())
}
Ok(())
}
ShellExecResult::Continue => {
continuing = true;
// Continue, but don't change the mode
ShellExecResult::ContinueLine => {
continuing_line = true;
Ok(())
}
ShellExecResult::ContinueBlock => {
continuing_block = true;
Ok(())
}
ShellExecResult::PyErr(err) => {
continuing = false;
continuing_block = false;
full_input.clear();
Err(err)
}
}
}
ReadlineResult::Interrupt => {
continuing = false;
continuing_block = false;
full_input.clear();
let keyboard_interrupt =
vm.new_exception_empty(vm.ctx.exceptions.keyboard_interrupt.to_owned());

View File

@@ -756,8 +756,7 @@ impl ToPyException for Base64DecodeError {
InvalidLastSymbol(_, PAD) => "Excess data after padding".to_owned(),
InvalidLastSymbol(length, _) => {
format!(
"Invalid base64-encoded string: number of data characters {} cannot be 1 more than a multiple of 4",
length
"Invalid base64-encoded string: number of data characters {length} cannot be 1 more than a multiple of 4"
)
}
// TODO: clean up errors

View File

@@ -346,13 +346,9 @@ mod _csv {
if !rest.args.is_empty() {
let arg_len = rest.args.len();
if arg_len != 1 {
return Err(vm.new_type_error(
format!(
"field_size_limit() takes at most 1 argument ({} given)",
arg_len
)
.to_string(),
));
return Err(vm.new_type_error(format!(
"field_size_limit() takes at most 1 argument ({arg_len} given)"
)));
}
let Ok(new_size) = rest.args.first().unwrap().try_int(vm) else {
return Err(vm.new_type_error("limit must be an integer".to_string()));
@@ -701,7 +697,7 @@ mod _csv {
if let Some(dialect) = g.get(name) {
Ok(self.update_py_dialect(*dialect))
} else {
Err(new_csv_error(vm, format!("{} is not registered.", name)))
Err(new_csv_error(vm, format!("{name} is not registered.")))
}
// TODO
// Maybe need to update the obj from HashMap

View File

@@ -363,7 +363,7 @@ impl FormatSpec {
// Loop over all opcodes:
for code in &self.codes {
buffer = &mut buffer[code.pre_padding..];
debug!("code: {:?}", code);
debug!("code: {code:?}");
match code.code {
FormatType::Str => {
let (buf, rest) = buffer.split_at_mut(code.repeat);
@@ -407,7 +407,7 @@ impl FormatSpec {
let mut items = Vec::with_capacity(self.arg_count);
for code in &self.codes {
data = &data[code.pre_padding..];
debug!("unpack code: {:?}", code);
debug!("unpack code: {code:?}");
match code.code {
FormatType::Pad => {
data = &data[code.repeat..];

View File

@@ -66,10 +66,9 @@ impl PyObjectRef {
warnings::warn(
vm.ctx.exceptions.deprecation_warning,
format!(
"__complex__ returned non-complex (type {}). \
"__complex__ returned non-complex (type {ret_class}). \
The ability to return an instance of a strict subclass of complex \
is deprecated, and may be removed in a future version of Python.",
ret_class
is deprecated, and may be removed in a future version of Python."
),
1,
vm,

View File

@@ -53,14 +53,12 @@ impl Constructor for PyBaseObject {
0 => {}
1 => {
return Err(vm.new_type_error(format!(
"class {} without an implementation for abstract method '{}'",
name, methods
"class {name} without an implementation for abstract method '{methods}'"
)));
}
2.. => {
return Err(vm.new_type_error(format!(
"class {} without an implementation for abstract methods '{}'",
name, methods
"class {name} without an implementation for abstract methods '{methods}'"
)));
}
// TODO: remove `allow` when redox build doesn't complain about it

View File

@@ -132,8 +132,7 @@ impl PyProperty {
let func_args_len = func_args.args.len();
let (_owner, name): (PyObjectRef, PyObjectRef) = func_args.bind(vm).map_err(|_e| {
vm.new_type_error(format!(
"__set_name__() takes 2 positional arguments but {} were given",
func_args_len
"__set_name__() takes 2 positional arguments but {func_args_len} were given"
))
})?;

View File

@@ -1,3 +1,4 @@
// cspell:ignore cmeth
/*! Python `super` class.
See also [CPython source code.](https://github.com/python/cpython/blob/50b48572d9a90c5bb36e2bef6179548ea927a35a/Objects/typeobject.c#L7663)
@@ -125,8 +126,8 @@ impl Initializer for PySuper {
(typ, obj)
};
let mut inner = PySuperInner::new(typ, obj, vm)?;
std::mem::swap(&mut inner, &mut zelf.inner.write());
let inner = PySuperInner::new(typ, obj, vm)?;
*zelf.inner.write() = inner;
Ok(())
}

View File

@@ -419,7 +419,7 @@ impl StandardEncoding {
match encoding {
"be" => Some(Self::Utf32Be),
"le" => Some(Self::Utf32Le),
_ => return None,
_ => None,
}
} else {
None
@@ -1116,7 +1116,7 @@ fn replace_errors(err: PyObjectRef, vm: &VirtualMachine) -> PyResult<(PyObjectRe
let replace = replacement_char.repeat(range.end - range.start);
Ok((replace.to_pyobject(vm), range.end))
} else {
return Err(bad_err_type(err, vm));
Err(bad_err_type(err, vm))
}
}

View File

@@ -49,3 +49,10 @@ impl crate::convert::ToPyException for (CompileError, Option<&str>) {
vm.new_syntax_error(&self.0, self.1)
}
}
#[cfg(any(feature = "parser", feature = "codegen"))]
impl crate::convert::ToPyException for (CompileError, Option<&str>, bool) {
fn to_pyexception(&self, vm: &crate::VirtualMachine) -> crate::builtins::PyBaseExceptionRef {
vm.new_syntax_error_maybe_incomplete(&self.0, self.1, self.2)
}
}

View File

@@ -3,7 +3,7 @@ use crate::{PyResult, VirtualMachine, compiler, scope::Scope};
pub fn eval(vm: &VirtualMachine, source: &str, scope: Scope, source_path: &str) -> PyResult {
match vm.compile(source, compiler::Mode::Eval, source_path.to_owned()) {
Ok(bytecode) => {
debug!("Code object: {:?}", bytecode);
debug!("Code object: {bytecode:?}");
vm.run_code_obj(bytecode, scope)
}
Err(err) => Err(vm.new_syntax_error(&err, Some(source))),

View File

@@ -206,7 +206,7 @@ impl VirtualMachine {
lineno
)?;
} else if let Some(filename) = maybe_filename {
filename_suffix = format!(" ({})", filename);
filename_suffix = format!(" ({filename})");
}
if let Some(text) = maybe_text {
@@ -215,7 +215,7 @@ impl VirtualMachine {
let l_text = r_text.trim_start_matches([' ', '\n', '\x0c']); // \x0c is \f
let spaces = (r_text.len() - l_text.len()) as isize;
writeln!(output, " {}", l_text)?;
writeln!(output, " {l_text}")?;
let maybe_offset: Option<isize> =
getattr("offset").and_then(|obj| obj.try_to_value::<isize>(vm).ok());
@@ -495,6 +495,7 @@ pub struct ExceptionZoo {
pub not_implemented_error: &'static Py<PyType>,
pub recursion_error: &'static Py<PyType>,
pub syntax_error: &'static Py<PyType>,
pub incomplete_input_error: &'static Py<PyType>,
pub indentation_error: &'static Py<PyType>,
pub tab_error: &'static Py<PyType>,
pub system_error: &'static Py<PyType>,
@@ -743,6 +744,7 @@ impl ExceptionZoo {
let recursion_error = PyRecursionError::init_builtin_type();
let syntax_error = PySyntaxError::init_builtin_type();
let incomplete_input_error = PyIncompleteInputError::init_builtin_type();
let indentation_error = PyIndentationError::init_builtin_type();
let tab_error = PyTabError::init_builtin_type();
@@ -817,6 +819,7 @@ impl ExceptionZoo {
not_implemented_error,
recursion_error,
syntax_error,
incomplete_input_error,
indentation_error,
tab_error,
system_error,
@@ -965,6 +968,7 @@ impl ExceptionZoo {
"end_offset" => ctx.none(),
"text" => ctx.none(),
});
extend_exception!(PyIncompleteInputError, ctx, excs.incomplete_input_error);
extend_exception!(PyIndentationError, ctx, excs.indentation_error);
extend_exception!(PyTabError, ctx, excs.tab_error);
@@ -1611,7 +1615,7 @@ pub(super) mod types {
format!("{} ({}, line {})", msg, basename(filename.as_str()), lineno)
}
(Some(lineno), None) => {
format!("{} (line {})", msg, lineno)
format!("{msg} (line {lineno})")
}
(None, Some(filename)) => {
format!("{} ({})", msg, basename(filename.as_str()))
@@ -1623,6 +1627,28 @@ pub(super) mod types {
}
}
#[pyexception(
name = "_IncompleteInputError",
base = "PySyntaxError",
ctx = "incomplete_input_error"
)]
#[derive(Debug)]
pub struct PyIncompleteInputError {}
#[pyexception]
impl PyIncompleteInputError {
#[pyslot]
#[pymethod(name = "__init__")]
pub(crate) fn slot_init(
zelf: PyObjectRef,
_args: FuncArgs,
vm: &VirtualMachine,
) -> PyResult<()> {
zelf.set_attr("name", vm.ctx.new_str("SyntaxError"), vm)?;
Ok(())
}
}
#[pyexception(name, base = "PySyntaxError", ctx = "indentation_error", impl)]
#[derive(Debug)]
pub struct PyIndentationError {}

View File

@@ -1667,7 +1667,8 @@ impl ExecutingFrame<'_> {
.topmost_exception()
.ok_or_else(|| vm.new_runtime_error("No active exception to reraise".to_owned()))?,
};
debug!("Exception raised: {:?} with cause: {:?}", exception, cause);
#[cfg(debug_assertions)]
debug!("Exception raised: {exception:?} with cause: {cause:?}");
if let Some(cause) = cause {
exception.set_cause(cause);
}

View File

@@ -51,8 +51,7 @@ impl PyObject {
Err(err) => return err,
};
vm.new_value_error(format!(
"invalid literal for int() with base {}: {}",
base, repr,
"invalid literal for int() with base {base}: {repr}",
))
})?;
Ok(PyInt::from(i).into_ref(&vm.ctx))
@@ -475,10 +474,9 @@ impl PyNumber<'_> {
warnings::warn(
vm.ctx.exceptions.deprecation_warning,
format!(
"__int__ returned non-int (type {}). \
"__int__ returned non-int (type {ret_class}). \
The ability to return an instance of a strict subclass of int \
is deprecated, and may be removed in a future version of Python.",
ret_class
is deprecated, and may be removed in a future version of Python."
),
1,
vm,
@@ -509,10 +507,9 @@ impl PyNumber<'_> {
warnings::warn(
vm.ctx.exceptions.deprecation_warning,
format!(
"__index__ returned non-int (type {}). \
"__index__ returned non-int (type {ret_class}). \
The ability to return an instance of a strict subclass of int \
is deprecated, and may be removed in a future version of Python.",
ret_class
is deprecated, and may be removed in a future version of Python."
),
1,
vm,
@@ -543,10 +540,9 @@ impl PyNumber<'_> {
warnings::warn(
vm.ctx.exceptions.deprecation_warning,
format!(
"__float__ returned non-float (type {}). \
"__float__ returned non-float (type {ret_class}). \
The ability to return an instance of a strict subclass of float \
is deprecated, and may be removed in a future version of Python.",
ret_class
is deprecated, and may be removed in a future version of Python."
),
1,
vm,

View File

@@ -245,6 +245,7 @@ pub(crate) fn parse(
let top = parser::parse(source, mode.into())
.map_err(|parse_error| ParseError {
error: parse_error.error,
raw_location: parse_error.location,
location: text_range_to_source_range(&source_code, parse_error.location)
.start
.to_source_location(),
@@ -295,8 +296,8 @@ pub const PY_COMPILE_FLAG_AST_ONLY: i32 = 0x0400;
// The following flags match the values from Include/cpython/compile.h
// Caveat emptor: These flags are undocumented on purpose and depending
// on their effect outside the standard library is **unsupported**.
const PY_CF_DONT_IMPLY_DEDENT: i32 = 0x200;
const PY_CF_ALLOW_INCOMPLETE_INPUT: i32 = 0x4000;
pub const PY_CF_DONT_IMPLY_DEDENT: i32 = 0x200;
pub const PY_CF_ALLOW_INCOMPLETE_INPUT: i32 = 0x4000;
// __future__ flags - sync with Lib/__future__.py
// TODO: These flags aren't being used in rust code

View File

@@ -186,6 +186,8 @@ mod builtins {
return Err(vm.new_value_error("compile() unrecognized flags".to_owned()));
}
let allow_incomplete = !(flags & ast::PY_CF_ALLOW_INCOMPLETE_INPUT).is_zero();
if (flags & ast::PY_COMPILE_FLAG_AST_ONLY).is_zero() {
#[cfg(not(feature = "compiler"))]
{
@@ -207,14 +209,17 @@ mod builtins {
args.filename.to_string_lossy().into_owned(),
opts,
)
.map_err(|err| (err, Some(source)).to_pyexception(vm))?;
.map_err(|err| {
(err, Some(source), allow_incomplete).to_pyexception(vm)
})?;
Ok(code.into())
}
} else {
let mode = mode_str
.parse::<parser::Mode>()
.map_err(|err| vm.new_value_error(err.to_string()))?;
ast::parse(vm, source, mode).map_err(|e| (e, Some(source)).to_pyexception(vm))
ast::parse(vm, source, mode)
.map_err(|e| (e, Some(source), allow_incomplete).to_pyexception(vm))
}
}
}
@@ -1056,6 +1061,7 @@ pub fn init_module(vm: &VirtualMachine, module: &Py<PyModule>) {
"NotImplementedError" => ctx.exceptions.not_implemented_error.to_owned(),
"RecursionError" => ctx.exceptions.recursion_error.to_owned(),
"SyntaxError" => ctx.exceptions.syntax_error.to_owned(),
"_IncompleteInputError" => ctx.exceptions.incomplete_input_error.to_owned(),
"IndentationError" => ctx.exceptions.indentation_error.to_owned(),
"TabError" => ctx.exceptions.tab_error.to_owned(),
"SystemError" => ctx.exceptions.system_error.to_owned(),

View File

@@ -27,7 +27,7 @@ mod _collections {
use std::collections::VecDeque;
#[pyattr]
#[pyclass(name = "deque", unhashable = true)]
#[pyclass(module = "collections", name = "deque", unhashable = true)]
#[derive(Debug, Default, PyPayload)]
struct PyDeque {
deque: PyRwLock<VecDeque<PyObjectRef>>,

View File

@@ -251,7 +251,7 @@ impl PyCSimple {
#[pyclassmethod]
fn repeat(cls: PyTypeRef, n: isize, vm: &VirtualMachine) -> PyResult {
if n < 0 {
return Err(vm.new_value_error(format!("Array length must be >= 0, not {}", n)));
return Err(vm.new_value_error(format!("Array length must be >= 0, not {n}")));
}
Ok(PyCArrayType {
inner: PyCArray {

View File

@@ -13,6 +13,7 @@ use libffi::middle::{Arg, Cif, CodePtr, Type};
use libloading::Symbol;
use num_traits::ToPrimitive;
use rustpython_common::lock::PyRwLock;
use std::ffi::CString;
use std::fmt::Debug;
// https://github.com/python/cpython/blob/4f8bb3947cfbc20f970ff9d9531e1132a9e95396/Modules/_ctypes/callproc.c#L15
@@ -77,10 +78,11 @@ impl Function {
}
})
.collect::<PyResult<Vec<Type>>>()?;
let terminated = format!("{}\0", function);
let c_function_name = CString::new(function)
.map_err(|_| vm.new_value_error("Function name contains null bytes".to_string()))?;
let pointer: Symbol<'_, FP> = unsafe {
library
.get(terminated.as_bytes())
.get(c_function_name.as_bytes())
.map_err(|err| err.to_string())
.map_err(|err| vm.new_attribute_error(err))?
};

View File

@@ -53,7 +53,7 @@ impl GetAttr for PyCStructure {
let data = zelf.data.read();
match data.get(&name) {
Some(value) => Ok(value.clone()),
None => Err(vm.new_attribute_error(format!("No attribute named {}", name))),
None => Err(vm.new_attribute_error(format!("No attribute named {name}"))),
}
}
}

View File

@@ -259,6 +259,9 @@ mod _io {
}
fn write(&mut self, data: &[u8]) -> Option<u64> {
if data.is_empty() {
return Some(0);
}
let length = data.len();
self.cursor.write_all(data).ok()?;
Some(length as u64)
@@ -1172,7 +1175,7 @@ mod _io {
vm.call_method(self.raw.as_ref().unwrap(), "readinto", (mem_obj.clone(),));
mem_obj.release();
std::mem::swap(v, &mut read_buf.take());
*v = read_buf.take();
res?
}

View File

@@ -1989,7 +1989,7 @@ pub mod module {
let pathname = vm.ctx.new_dict();
for variant in PathconfVar::iter() {
// get the name of variant as a string to use as the dictionary key
let key = vm.ctx.new_str(format!("{:?}", variant));
let key = vm.ctx.new_str(format!("{variant:?}"));
// get the enum from the string and convert it to an integer for the dictionary value
let value = vm.ctx.new_int(variant as u8);
pathname
@@ -2185,7 +2185,7 @@ pub mod module {
let names = vm.ctx.new_dict();
for variant in SysconfVar::iter() {
// get the name of variant as a string to use as the dictionary key
let key = vm.ctx.new_str(format!("{:?}", variant));
let key = vm.ctx.new_str(format!("{variant:?}"));
// get the enum from the string and convert it to an integer for the dictionary value
let value = vm.ctx.new_int(variant as u8);
names

View File

@@ -317,9 +317,9 @@ mod sys {
let mut source = String::new();
handle
.read_to_string(&mut source)
.map_err(|e| vm.new_os_error(format!("Error reading from stdin: {}", e)))?;
.map_err(|e| vm.new_os_error(format!("Error reading from stdin: {e}")))?;
vm.compile(&source, crate::compiler::Mode::Single, "<stdin>".to_owned())
.map_err(|e| vm.new_os_error(format!("Error running stdin: {}", e)))?;
.map_err(|e| vm.new_os_error(format!("Error running stdin: {e}")))?;
Ok(())
}
@@ -723,7 +723,7 @@ mod sys {
vm.state.int_max_str_digits.store(maxdigits);
Ok(())
} else {
let error = format!("maxdigits must be 0 or larger than {:?}", threshold);
let error = format!("maxdigits must be 0 or larger than {threshold:?}");
Err(vm.new_value_error(error))
}
}

View File

@@ -49,7 +49,7 @@ impl VirtualMachine {
self.run_code_string(scope, &source, path.to_owned())?;
}
Err(err) => {
error!("Failed reading file '{}': {}", path, err);
error!("Failed reading file '{path}': {err}");
// TODO: Need to change to ExitCode or Termination
std::process::exit(1);
}

View File

@@ -320,10 +320,11 @@ impl VirtualMachine {
}
#[cfg(any(feature = "parser", feature = "compiler"))]
pub fn new_syntax_error(
pub fn new_syntax_error_maybe_incomplete(
&self,
error: &crate::compiler::CompileError,
source: Option<&str>,
allow_incomplete: bool,
) -> PyBaseExceptionRef {
use crate::source::SourceLocation;
@@ -343,12 +344,102 @@ impl VirtualMachine {
..
}) => self.ctx.exceptions.indentation_error,
#[cfg(feature = "parser")]
crate::compiler::CompileError::Parse(rustpython_compiler::ParseError {
error:
ruff_python_parser::ParseErrorType::Lexical(
ruff_python_parser::LexicalErrorType::Eof,
),
..
}) => {
if allow_incomplete {
self.ctx.exceptions.incomplete_input_error
} else {
self.ctx.exceptions.syntax_error
}
}
#[cfg(feature = "parser")]
crate::compiler::CompileError::Parse(rustpython_compiler::ParseError {
error:
ruff_python_parser::ParseErrorType::Lexical(
ruff_python_parser::LexicalErrorType::FStringError(
ruff_python_parser::FStringErrorType::UnterminatedTripleQuotedString,
),
),
..
}) => {
if allow_incomplete {
self.ctx.exceptions.incomplete_input_error
} else {
self.ctx.exceptions.syntax_error
}
}
#[cfg(feature = "parser")]
crate::compiler::CompileError::Parse(rustpython_compiler::ParseError {
error:
ruff_python_parser::ParseErrorType::Lexical(
ruff_python_parser::LexicalErrorType::UnclosedStringError,
),
raw_location,
..
}) => {
if allow_incomplete {
let mut is_incomplete = false;
if let Some(source) = source {
let loc = raw_location.start().to_usize();
let mut iter = source.chars();
if let Some(quote) = iter.nth(loc) {
if iter.next() == Some(quote) && iter.next() == Some(quote) {
is_incomplete = true;
}
}
}
if is_incomplete {
self.ctx.exceptions.incomplete_input_error
} else {
self.ctx.exceptions.syntax_error
}
} else {
self.ctx.exceptions.syntax_error
}
}
#[cfg(feature = "parser")]
crate::compiler::CompileError::Parse(rustpython_compiler::ParseError {
error: ruff_python_parser::ParseErrorType::OtherError(s),
raw_location,
..
}) => {
if s.starts_with("Expected an indented block after") {
self.ctx.exceptions.indentation_error
if allow_incomplete {
// Check that all chars in the error are whitespace, if so, the source is
// incomplete. Otherwise, we've found code that might violates
// indentation rules.
let mut is_incomplete = true;
if let Some(source) = source {
let start = raw_location.start().to_usize();
let end = raw_location.end().to_usize();
let mut iter = source.chars();
iter.nth(start);
for _ in start..end {
if let Some(c) = iter.next() {
if !c.is_ascii_whitespace() {
is_incomplete = false;
}
} else {
break;
}
}
}
if is_incomplete {
self.ctx.exceptions.incomplete_input_error
} else {
self.ctx.exceptions.indentation_error
}
} else {
self.ctx.exceptions.indentation_error
}
} else {
self.ctx.exceptions.syntax_error
}
@@ -410,6 +501,15 @@ impl VirtualMachine {
syntax_error
}
#[cfg(any(feature = "parser", feature = "compiler"))]
pub fn new_syntax_error(
&self,
error: &crate::compiler::CompileError,
source: Option<&str>,
) -> PyBaseExceptionRef {
self.new_syntax_error_maybe_incomplete(error, source, false)
}
pub fn new_import_error(&self, msg: String, name: PyStrRef) -> PyBaseExceptionRef {
let import_error = self.ctx.exceptions.import_error.to_owned();
let exc = self.new_exception_msg(import_error, msg);

View File

@@ -10,6 +10,7 @@ del m
assert re._constants.MAGIC == sre_engine_magic
class CompiledPattern:
@classmethod
def compile(cls, pattern, flags=0):
@@ -21,40 +22,50 @@ class CompiledPattern:
self.flags = re.RegexFlag(flags | p.state.flags)
return self
for k, v in re.RegexFlag.__members__.items():
setattr(CompiledPattern, k, v)
class EscapeRustStr:
hardcoded = {
ord('\r'): '\\r',
ord('\t'): '\\t',
ord('\r'): '\\r',
ord('\n'): '\\n',
ord('\\'): '\\\\',
ord('\''): '\\\'',
ord('\"'): '\\\"',
ord("\r"): "\\r",
ord("\t"): "\\t",
ord("\r"): "\\r",
ord("\n"): "\\n",
ord("\\"): "\\\\",
ord("'"): "\\'",
ord('"'): '\\"',
}
@classmethod
def __class_getitem__(cls, ch):
if (rpl := cls.hardcoded.get(ch)) is not None:
return rpl
if ch in range(0x20, 0x7f):
if ch in range(0x20, 0x7F):
return ch
return f"\\u{{{ch:x}}}"
def rust_str(s):
return '"' + s.translate(EscapeRustStr) + '"'
# matches `// pattern {varname} = re.compile(...)`
pattern_pattern = re.compile(r"^((\s*)\/\/\s*pattern\s+(\w+)\s+=\s+(.+?))$(?:.+?END GENERATED)?", re.M | re.S)
pattern_pattern = re.compile(
r"^((\s*)\/\/\s*pattern\s+(\w+)\s+=\s+(.+?))$(?:.+?END GENERATED)?", re.M | re.S
)
def replace_compiled(m):
line, indent, varname, pattern = m.groups()
pattern = eval(pattern, {"re": CompiledPattern})
pattern = f"Pattern {{ pattern: {rust_str(pattern.pattern)}, code: &{json.dumps(pattern.code)} }}"
return f'''{line}
return f"""{line}
{indent}// START GENERATED by generate_tests.py
{indent}#[rustfmt::skip] let {varname} = {pattern};
{indent}// END GENERATED'''
{indent}// END GENERATED"""
with os.scandir("tests") as t, os.scandir("benches") as b:
for f in chain(t, b):

View File

@@ -24,7 +24,7 @@
"serve": "^14.2.4",
"webpack": "^5.97.1",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.2.0"
"webpack-dev-server": "^5.2.1"
}
},
"node_modules/@codemirror/autocomplete": {
@@ -5360,15 +5360,16 @@
}
},
"node_modules/webpack-dev-server": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.0.tgz",
"integrity": "sha512-90SqqYXA2SK36KcT6o1bvwvZfJFcmoamqeJY7+boioffX9g9C0wjjJRGUrQIuh43pb0ttX7+ssavmj/WN2RHtA==",
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.1.tgz",
"integrity": "sha512-ml/0HIj9NLpVKOMq+SuBPLHcmbG+TGIjXRHsYfZwocUBIqEvws8NnS/V9AFQ5FKP+tgn5adwVwRrTEpGL33QFQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/bonjour": "^3.5.13",
"@types/connect-history-api-fallback": "^1.5.4",
"@types/express": "^4.17.21",
"@types/express-serve-static-core": "^4.17.21",
"@types/serve-index": "^1.9.4",
"@types/serve-static": "^1.15.5",
"@types/sockjs": "^0.3.36",
@@ -5416,6 +5417,19 @@
}
}
},
"node_modules/webpack-dev-server/node_modules/@types/express-serve-static-core": {
"version": "4.19.6",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz",
"integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*",
"@types/qs": "*",
"@types/range-parser": "*",
"@types/send": "*"
}
},
"node_modules/webpack-merge": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz",

View File

@@ -19,7 +19,7 @@
"serve": "^14.2.4",
"webpack": "^5.97.1",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.2.0"
"webpack-dev-server": "^5.2.1"
},
"scripts": {
"dev": "webpack serve",

View File

@@ -28,9 +28,6 @@ ruff_python_parser = { workspace = true }
serde = { workspace = true }
wasm-bindgen = { workspace = true }
# remove once getrandom 0.2 is no longer otherwise in the dependency tree
getrandom = { version = "0.2", features = ["js"] }
console_error_panic_hook = "0.1"
js-sys = "0.3"
serde-wasm-bindgen = "0.3.1"

View File

@@ -7,8 +7,7 @@ edition = "2021"
crate-type = ["cdylib"]
[dependencies]
getrandom = { version = "0.2.12", features = ["custom"] }
getrandom_03 = { package = "getrandom", version = "0.3" }
getrandom = "0.3"
rustpython-vm = { path = "../../vm", default-features = false, features = ["compiler"] }
[workspace]

View File

@@ -1,4 +1,4 @@
use rustpython_vm::{eval, Interpreter};
use rustpython_vm::{Interpreter, eval};
pub unsafe extern "C" fn eval(s: *const u8, l: usize) -> u32 {
let src = std::slice::from_raw_parts(s, l);
@@ -9,16 +9,10 @@ pub unsafe extern "C" fn eval(s: *const u8, l: usize) -> u32 {
})
}
fn getrandom_always_fail(_buf: &mut [u8]) -> Result<(), getrandom::Error> {
Err(getrandom::Error::UNSUPPORTED)
}
getrandom::register_custom_getrandom!(getrandom_always_fail);
#[unsafe(no_mangle)]
unsafe extern "Rust" fn __getrandom_v03_custom(
_dest: *mut u8,
_len: usize,
) -> Result<(), getrandom_03::Error> {
Err(getrandom_03::Error::UNSUPPORTED)
) -> Result<(), getrandom::Error> {
Err(getrandom::Error::UNSUPPORTED)
}

View File

@@ -39,7 +39,10 @@ implementation = platform.python_implementation()
if implementation != "CPython":
sys.exit(f"whats_left.py must be run under CPython, got {implementation} instead")
if sys.version_info[:2] < (3, 13):
sys.exit(f"whats_left.py must be run under CPython 3.13 or newer, got {implementation} {sys.version} instead")
sys.exit(
f"whats_left.py must be run under CPython 3.13 or newer, got {implementation} {sys.version} instead. If you have uv, try `uv run python -I whats_left.py` to select a proper Python interpreter easier."
)
def parse_args():
parser = argparse.ArgumentParser(description="Process some integers.")
@@ -73,8 +76,16 @@ args = parse_args()
# CPython specific modules (mostly consisting of templates/tests)
CPYTHON_SPECIFIC_MODS = {
'xxmodule', 'xxsubtype', 'xxlimited', '_xxtestfuzz',
'_testbuffer', '_testcapi', '_testimportmultiple', '_testinternalcapi', '_testmultiphase', '_testlimitedcapi'
"xxmodule",
"xxsubtype",
"xxlimited",
"_xxtestfuzz",
"_testbuffer",
"_testcapi",
"_testimportmultiple",
"_testinternalcapi",
"_testmultiphase",
"_testlimitedcapi",
}
IGNORED_MODULES = {"this", "antigravity"} | CPYTHON_SPECIFIC_MODS
@@ -291,7 +302,7 @@ output = """\
output += gen_methods()
output += f"""
cpymods = {gen_modules()!r}
libdir = {os.path.abspath("Lib/").encode('utf8')!r}
libdir = {os.path.abspath("Lib/").encode("utf8")!r}
"""
@@ -310,6 +321,8 @@ for fn in REUSED:
expected_methods = {}
cpymods = {}
libdir = ""
# This function holds the source code that will be run under RustPython
def compare():
import inspect
@@ -376,7 +389,9 @@ def compare():
if rustpymod is None:
result["not_implemented"][modname] = None
elif isinstance(rustpymod, Exception):
result["failed_to_import"][modname] = rustpymod.__class__.__name__ + str(rustpymod)
result["failed_to_import"][modname] = rustpymod.__class__.__name__ + str(
rustpymod
)
else:
implemented_items = sorted(set(cpymod) & set(rustpymod))
mod_missing_items = set(cpymod) - set(rustpymod)
@@ -418,13 +433,23 @@ def remove_one_indent(s):
compare_src = inspect.getsourcelines(compare)[0][1:]
output += "".join(remove_one_indent(line) for line in compare_src)
with open(GENERATED_FILE, "w", encoding='utf-8') as f:
with open(GENERATED_FILE, "w", encoding="utf-8") as f:
f.write(output + "\n")
subprocess.run(["cargo", "build", "--release", f"--features={args.features}"], check=True)
subprocess.run(
["cargo", "build", "--release", f"--features={args.features}"], check=True
)
result = subprocess.run(
["cargo", "run", "--release", f"--features={args.features}", "-q", "--", GENERATED_FILE],
[
"cargo",
"run",
"--release",
f"--features={args.features}",
"-q",
"--",
GENERATED_FILE,
],
env={**os.environ.copy(), "RUSTPYTHONPATH": "Lib"},
text=True,
capture_output=True,
@@ -475,7 +500,7 @@ if args.signature:
if args.doc:
print("\n# mismatching `__doc__`s (warnings)")
for modname, mismatched in result["mismatched_doc_items"].items():
for (item, rustpy_doc, cpython_doc) in mismatched:
for item, rustpy_doc, cpython_doc in mismatched:
print(f"{item} {repr(rustpy_doc)} != {repr(cpython_doc)}")

View File

@@ -676,7 +676,7 @@ impl fmt::Debug for Wtf8 {
write_str_escaped(formatter, unsafe {
str::from_utf8_unchecked(&self.bytes[pos..surrogate_pos])
})?;
write!(formatter, "\\u{{{:x}}}", surrogate)?;
write!(formatter, "\\u{{{surrogate:x}}}")?;
pos = surrogate_pos + 3;
}
write_str_escaped(formatter, unsafe {