test_builtin.py test_compile unit test fix (#5251)

* compile accepts memoryview now

* Update test_compile to what it is in CPython3.12

* compile optimize flag

* added undocumented flags to flag validator
This commit is contained in:
Jonathan Rotter
2024-04-23 00:07:02 -05:00
committed by GitHub
parent 2bd8ff0b6c
commit 3313fdeb32
3 changed files with 81 additions and 13 deletions

View File

@@ -327,7 +327,7 @@ class BuiltinTest(unittest.TestCase):
def test_cmp(self):
self.assertTrue(not hasattr(builtins, "cmp"))
# TODO: RUSTPYTHON
# TODO: RUSTPYTHON optval=2 does not remove docstrings
@unittest.expectedFailure
def test_compile(self):
compile('print(1)\n', '', 'exec')
@@ -340,11 +340,10 @@ class BuiltinTest(unittest.TestCase):
self.assertRaises(TypeError, compile)
self.assertRaises(ValueError, compile, 'print(42)\n', '<string>', 'badmode')
self.assertRaises(ValueError, compile, 'print(42)\n', '<string>', 'single', 0xff)
self.assertRaises(ValueError, compile, chr(0), 'f', 'exec')
self.assertRaises(TypeError, compile, 'pass', '?', 'exec',
mode='eval', source='0', filename='tmp')
compile('print("\xe5")\n', '', 'exec')
self.assertRaises(ValueError, compile, chr(0), 'f', 'exec')
self.assertRaises(SyntaxError, compile, chr(0), 'f', 'exec')
self.assertRaises(ValueError, compile, str('a = 1'), 'f', 'bad')
# test the optimize argument

View File

@@ -341,8 +341,13 @@ pub(crate) fn compile(
object: PyObjectRef,
filename: &str,
mode: crate::compiler::Mode,
optimize: Option<u8>,
) -> PyResult {
let opts = vm.compile_opts();
let mut opts = vm.compile_opts();
if let Some(optimize) = optimize {
opts.optimize = optimize;
}
let ast = Node::ast_from_object(vm, object)?;
let code = codegen::compile::compile_top(&ast, filename.to_owned(), mode, opts)
.map_err(|err| (CompileError::from(err), None).to_pyexception(vm))?; // FIXME source
@@ -354,6 +359,43 @@ pub(crate) use _ast::NodeAst;
// Used by builtins::compile()
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;
// __future__ flags - sync with Lib/__future__.py
// TODO: These flags aren't being used in rust code
// CO_FUTURE_ANNOTATIONS does make a difference in the codegen,
// so it should be used in compile().
// see compiler/codegen/src/compile.rs
const CO_NESTED: i32 = 0x0010;
const CO_GENERATOR_ALLOWED: i32 = 0;
const CO_FUTURE_DIVISION: i32 = 0x20000;
const CO_FUTURE_ABSOLUTE_IMPORT: i32 = 0x40000;
const CO_FUTURE_WITH_STATEMENT: i32 = 0x80000;
const CO_FUTURE_PRINT_FUNCTION: i32 = 0x100000;
const CO_FUTURE_UNICODE_LITERALS: i32 = 0x200000;
const CO_FUTURE_BARRY_AS_BDFL: i32 = 0x400000;
const CO_FUTURE_GENERATOR_STOP: i32 = 0x800000;
const CO_FUTURE_ANNOTATIONS: i32 = 0x1000000;
// Used by builtins::compile() - the summary of all flags
pub const PY_COMPILE_FLAGS_MASK: i32 = PY_COMPILE_FLAG_AST_ONLY
| PY_CF_DONT_IMPLY_DEDENT
| PY_CF_ALLOW_INCOMPLETE_INPUT
| CO_NESTED
| CO_GENERATOR_ALLOWED
| CO_FUTURE_DIVISION
| CO_FUTURE_ABSOLUTE_IMPORT
| CO_FUTURE_WITH_STATEMENT
| CO_FUTURE_PRINT_FUNCTION
| CO_FUTURE_UNICODE_LITERALS
| CO_FUTURE_BARRY_AS_BDFL
| CO_FUTURE_GENERATOR_STOP
| CO_FUTURE_ANNOTATIONS;
pub fn make_module(vm: &VirtualMachine) -> PyRef<PyModule> {
let module = _ast::make_module(vm);
gen::extend_module_nodes(vm, &module);

View File

@@ -121,6 +121,15 @@ mod builtins {
let mode_str = args.mode.as_str();
let optimize: i32 = args.optimize.map_or(Ok(-1), |v| v.try_to_primitive(vm))?;
let optimize: u8 = if optimize == -1 {
vm.state.settings.optimize
} else {
optimize.try_into().map_err(|_| {
vm.new_value_error("compile() optimize value invalid".to_owned())
})?
};
if args
.source
.fast_isinstance(&ast::NodeAst::make_class(&vm.ctx))
@@ -134,7 +143,13 @@ mod builtins {
let mode = mode_str
.parse::<crate::compiler::Mode>()
.map_err(|err| vm.new_value_error(err.to_string()))?;
return ast::compile(vm, args.source, args.filename.as_str(), mode);
return ast::compile(
vm,
args.source,
args.filename.as_str(),
mode,
Some(optimize),
);
}
}
@@ -146,20 +161,23 @@ mod builtins {
}
#[cfg(feature = "rustpython-parser")]
{
use crate::{builtins::PyBytesRef, convert::ToPyException};
use crate::convert::ToPyException;
use num_traits::Zero;
use rustpython_parser as parser;
let source = Either::<PyStrRef, PyBytesRef>::try_from_object(vm, args.source)?;
let source = ArgStrOrBytesLike::try_from_object(vm, args.source)?;
let source = source.borrow_bytes();
// TODO: compiler::compile should probably get bytes
let source = match &source {
Either::A(string) => string.as_str(),
Either::B(bytes) => std::str::from_utf8(bytes)
.map_err(|e| vm.new_unicode_decode_error(e.to_string()))?,
};
let source = std::str::from_utf8(&source)
.map_err(|e| vm.new_unicode_decode_error(e.to_string()))?;
let flags = args.flags.map_or(Ok(0), |v| v.try_to_primitive(vm))?;
if !(flags & !ast::PY_COMPILE_FLAGS_MASK).is_zero() {
return Err(vm.new_value_error("compile() unrecognized flags".to_owned()));
}
if (flags & ast::PY_COMPILE_FLAG_AST_ONLY).is_zero() {
#[cfg(not(feature = "rustpython-compiler"))]
{
@@ -170,8 +188,17 @@ mod builtins {
let mode = mode_str
.parse::<crate::compiler::Mode>()
.map_err(|err| vm.new_value_error(err.to_string()))?;
let mut opts = vm.compile_opts();
opts.optimize = optimize;
let code = vm
.compile(source, mode, args.filename.as_str().to_owned())
.compile_with_opts(
source,
mode,
args.filename.as_str().to_owned(),
opts,
)
.map_err(|err| (err, Some(source)).to_pyexception(vm))?;
Ok(code.into())
}