⚡ Sangsakala Proxy 🏠 Home
Skip to content

Raise ValueError for None in Stmt lists to match CPython validator - #7670

Merged
youknowone merged 1 commit into
RustPython:mainfrom
changjoon-park:fix-stmt-none-disallowed
Apr 24, 2026
Merged

youknowone merged 1 commit into
RustPython:mainfrom
changjoon-park:fix-stmt-none-disallowed

Conversation

@changjoon-park

@changjoon-park changjoon-park commented Apr 24, 2026 •

Copy link
Copy Markdown
Contributor

Sibling fix to #7656 (which handled Vec<Expr>). The same catch-all TypeError(\"expected some sort of stmt, but got {}\") in Stmt::ast_from_object silently swallowed None, so compile() on an AST with None in a statement-list field (ClassDef.body, Try.body, For.body, etc.) raised TypeError where CPython raises ValueError(\"None disallowed in statement list\").

Fix

One check in Stmt::ast_from_object (crates/vm/src/stdlib/_ast/statement.rs) before the catch-all, matching the Expr-side shape from #7656:

} else if _vm.is_none(&_object) {
    return Err(_vm.new_value_error(\"None disallowed in statement list\"));
}

Option<Stmt> positions are unaffected — node.rs Option<T>::ast_from_object short-circuits None earlier.

Verification

CPython 3.13.4 baseline message:

$ python3 -c \"import ast; compile(ast.Module([ast.ClassDef('X', [], [], [None], [], [])], []), '<t>', 'exec')\"
ValueError: None disallowed in statement list

After the fix, RustPython raises the byte-identical message for ClassDef, For, While, Try, and FunctionDef body positions.

Full test.test_ast.test_ast suite (227 tests):

Ran 227 tests in 18.951s
OK (skipped=10, expected failures=38)

0 failures, 0 unexpected successes. One less expected failure than upstream/main (was 39), corresponding to test_classdef unmasked.

Unmasks

  • ASTValidatorTests.test_classdef (was @unittest.expectedFailure; body=[None] sub-case now passes)

Part of the skip-test inventory in #7611.

Summary by CodeRabbit

  • Bug Fixes
    • Improved error handling for invalid statement list inputs, providing a more specific error message when None values are encountered instead of generic type errors.

Sibling fix to RustPython#7656 (which handled Vec<Expr>). The same catch-all
TypeError ("expected some sort of stmt, but got {}") in
Stmt::ast_from_object silently swallowed None, so compile() on an
AST with None in a statement-list field (ClassDef.body, Try.body,
For.body, etc.) raised TypeError where CPython raises
ValueError("None disallowed in statement list").

Add an is_none check before the catch-all, matching the Expr-side
shape introduced in RustPython#7656. Option<Stmt> positions are unaffected —
they short-circuit None earlier in node.rs.

Unmasks test_classdef (body=[None] sub-case). Full
test.test_ast.test_ast run: 227 tests, 0 unexpected successes, 38
expected failures (was 39).
@coderabbitai

coderabbitai Bot commented Apr 24, 2026 •

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 502bbe97-f6a4-4c7c-8958-9912b5e56805

📥 Commits

Reviewing files that changed from the base of the PR and between dc0c814 and 64cb2fd.

⛔ Files ignored due to path filters (1)
  • Lib/test/test_ast/test_ast.py is excluded by !Lib/**
📒 Files selected for processing (1)
  • crates/vm/src/stdlib/_ast/statement.rs

📝 Walkthrough

Walkthrough

The PR enhances the ast_from_object function for ast::Stmt to explicitly validate and reject None values in statement lists. When None is encountered during statement-list conversion, it now raises a specific ValueError with message "None disallowed in statement list" rather than producing a generic type error.

Changes

Cohort / File(s) Summary
AST Statement Validation
crates/vm/src/stdlib/_ast/statement.rs
Enhanced ast_from_object with an explicit is_none check that raises a specific error for None values in statement lists, improving error clarity and validation specificity.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~5 minutes

Possibly related PRs

Suggested reviewers

  • ShaharNaveh

Poem

🐰 A little check, so swift and clean,
"No None!" our statement guard does deem,
With error crisp and message bright,
The AST lists stand firm and right! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: raising a ValueError for None in statement lists to match CPython's behavior.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

Copy link
Copy Markdown
Contributor

📦 Library Dependencies

The following Lib/ modules were modified. Here are their dependencies:

[x] lib: cpython/Lib/ast.py
[x] lib: cpython/Lib/_ast_unparse.py
[x] test: cpython/Lib/test/test_unparse.py
[ ] test: cpython/Lib/test/test_type_comments.py (TODO: 15)

dependencies:

  • ast

dependent tests: (136 tests)

  • ast: test_ast test_builtin test_compile test_compiler_codegen test_dis test_fstring test_future_stmt test_site test_ssl test_type_comments test_ucn test_unparse
    • annotationlib: test_annotationlib test_functools test_inspect test_reprlib test_type_annotations test_type_params test_typing
      • dataclasses: test__colorize test_copy test_ctypes test_enum test_genericalias test_patma test_pprint test_pydoc test_regrtest test_zoneinfo
      • inspect: test_abc test_argparse test_asyncgen test_buffer test_code test_collections test_coroutines test_decimal test_generators test_grammar test_monitoring test_ntpath test_operator test_posixpath test_signal test_sqlite3 test_traceback test_types test_unittest test_yield_from test_zipimport
    • dbm.dumb: test_dbm_dumb
    • inspect:
      • bdb: test_bdb
      • cmd: test_cmd
      • importlib.metadata: test_importlib
      • pkgutil: test_pkgutil test_runpy
      • rlcompleter: test_rlcompleter
      • trace: test_trace
      • xmlrpc.server: test_docxmlrpc test_xmlrpc
    • pyclbr: test_pyclbr
    • traceback: test_asyncio test_code_module test_contextlib test_contextlib_async test_dictcomps test_exceptions test_http_cookiejar test_importlib test_iter test_listcomps test_pyexpat test_setcomps test_socket test_subprocess test_sys test_threadedtempfile test_threading test_unittest test_with
      • concurrent.futures.process: test_compileall test_concurrent_futures
      • http.cookiejar: test_urllib2
      • logging: test_asyncio test_hashlib test_logging test_support test_urllib2net
      • multiprocessing: test_asyncio test_concurrent_futures test_fcntl test_memoryview test_multiprocessing_main_handling test_re
      • py_compile: test_cmd_line_script test_importlib test_modulefinder test_py_compile
      • socketserver: test_imaplib test_socketserver test_wsgiref
      • threading: test_android test_asyncio test_bz2 test_concurrent_futures test_ctypes test_email test_fork1 test_frame test_ftplib test_gc test_httplib test_httpservers test_importlib test_io test_itertools test_largefile test_linecache test_opcache test_pathlib test_poll test_poplib test_queue test_robotparser test_sched test_smtplib test_super test_syslog test_termios test_threading_local test_time test_urllib2_localnet test_weakref test_winreg test_zstd
      • timeit: test_timeit

Legend:

  • [+] path exists in CPython
  • [x] up-to-date, [ ] outdated

@youknowone youknowone left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

👍

@youknowone
youknowone merged commit 0913563 into RustPython:main Apr 24, 2026
21 checks passed
@changjoon-park
changjoon-park deleted the fix-stmt-none-disallowed branch April 27, 2026 13:24
youknowone pushed a commit that referenced this pull request Sep 16, 2026
…7670)

Sibling fix to #7656 (which handled Vec<Expr>). The same catch-all
TypeError ("expected some sort of stmt, but got {}") in
Stmt::ast_from_object silently swallowed None, so compile() on an
AST with None in a statement-list field (ClassDef.body, Try.body,
For.body, etc.) raised TypeError where CPython raises
ValueError("None disallowed in statement list").

Add an is_none check before the catch-all, matching the Expr-side
shape introduced in #7656. Option<Stmt> positions are unaffected —
they short-circuit None earlier in node.rs.

Unmasks test_classdef (body=[None] sub-case). Full
test.test_ast.test_ast run: 227 tests, 0 unexpected successes, 38
expected failures (was 39).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants