From 733d544802c2ed9c6eea551a039a644fb9aae990 Mon Sep 17 00:00:00 2001 From: snowapril Date: Sat, 6 Nov 2021 16:12:11 +0900 Subject: [PATCH 1/6] Wrap `ItemFn` and #[pyattr] with `static_cell!` When we have to add #[pyattr] with function, that function must be called only once when module is imported. In previous, we did it with add static_cell for each function or skip it(undesired). I thought these static_cell stmt for all of each function in modules are quite duplicated. Thus, I add wrapping code when the given item is `ItemFn` and have `#[pyattr]`. Signed-off-by: snowapril --- derive/src/pymodule.rs | 37 ++++++++++++++++++++++++++++++++++++- derive/src/util.rs | 2 +- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/derive/src/pymodule.rs b/derive/src/pymodule.rs index d706da7c6..abeeb09b3 100644 --- a/derive/src/pymodule.rs +++ b/derive/src/pymodule.rs @@ -1,6 +1,6 @@ use crate::error::Diagnostic; use crate::util::{ - iter_use_idents, pyclass_ident_and_attrs, text_signature, AttributeExt, ClassItemMeta, + iter_use_idents, path_eq, pyclass_ident_and_attrs, text_signature, AttributeExt, ClassItemMeta, ContentItem, ContentItemInner, ErrorVec, ItemMeta, ItemNursery, SimpleItemMeta, ALL_ALLOWED_NAMES, }; @@ -37,6 +37,41 @@ pub fn impl_pymodule(attr: AttributeArgs, module_item: Item) -> Result { + unreachable!("#[pyattr] attached function must have return type.") + } + syn::ReturnType::Type(_, ty) => ty, + }; + let stmt: syn::Stmt = parse_quote! { + { + rustpython_common::static_cell! { + static ERROR: #return_type; + } + ERROR + .get_or_init(|| { + #(#stmts)* + }) + .clone() + } + }; + block.stmts = vec![stmt]; + } + } let (pyitems, cfgs) = attrs_to_module_items(attrs, new_module_item)?; for pyitem in pyitems.iter().rev() { let r = pyitem.gen_module_item(ModuleItemArgs { diff --git a/derive/src/util.rs b/derive/src/util.rs index ed790d810..1e494de85 100644 --- a/derive/src/util.rs +++ b/derive/src/util.rs @@ -226,7 +226,7 @@ pub(crate) trait ItemMeta: Sized { pub(crate) struct SimpleItemMeta(pub ItemMetaInner); impl ItemMeta for SimpleItemMeta { - const ALLOWED_NAMES: &'static [&'static str] = &["name"]; + const ALLOWED_NAMES: &'static [&'static str] = &["name", "once"]; fn from_inner(inner: ItemMetaInner) -> Self { Self(inner) From 5e8d3bcacb0d3e6c5eb46b2bac0e8558f3abb5dc Mon Sep 17 00:00:00 2001 From: snowapril Date: Sun, 7 Nov 2021 19:50:10 +0900 Subject: [PATCH 2/6] Remove duplicated static_cell! stmts in each modules Signed-off-by: snowapril --- stdlib/src/binascii.rs | 42 +++++++------------ stdlib/src/csv.rs | 2 +- stdlib/src/socket.rs | 63 ++++++++++------------------ stdlib/src/ssl.rs | 87 ++++++++++----------------------------- stdlib/src/termios.rs | 21 ++++------ stdlib/src/zlib.rs | 2 +- vm/src/stdlib/pystruct.rs | 21 ++++------ 7 files changed, 73 insertions(+), 165 deletions(-) diff --git a/stdlib/src/binascii.rs b/stdlib/src/binascii.rs index 4e3a53635..59526c193 100644 --- a/stdlib/src/binascii.rs +++ b/stdlib/src/binascii.rs @@ -11,38 +11,24 @@ mod decl { }; use itertools::Itertools; - #[pyattr(name = "Error")] + #[pyattr(name = "Error", once)] fn error_type(vm: &VirtualMachine) -> PyTypeRef { - rustpython_common::static_cell! { - static BINASCII_ERROR: PyTypeRef; - } - BINASCII_ERROR - .get_or_init(|| { - vm.ctx.new_class( - Some("binascii"), - "Error", - &vm.ctx.exceptions.value_error, - Default::default(), - ) - }) - .clone() + vm.ctx.new_class( + Some("binascii"), + "Error", + &vm.ctx.exceptions.value_error, + Default::default(), + ) } - #[pyattr(name = "Incomplete")] + #[pyattr(name = "Incomplete", once)] fn incomplete_type(vm: &VirtualMachine) -> PyTypeRef { - rustpython_common::static_cell! { - static BINASCII_INCOMPLTE: PyTypeRef; - } - BINASCII_INCOMPLTE - .get_or_init(|| { - vm.ctx.new_class( - Some("binascii"), - "Incomplete", - &vm.ctx.exceptions.exception_type, - Default::default(), - ) - }) - .clone() + vm.ctx.new_class( + Some("binascii"), + "Incomplete", + &vm.ctx.exceptions.exception_type, + Default::default(), + ) } fn hex_nibble(n: u8) -> u8 { diff --git a/stdlib/src/csv.rs b/stdlib/src/csv.rs index f89238ed1..2e8a44f8d 100644 --- a/stdlib/src/csv.rs +++ b/stdlib/src/csv.rs @@ -30,7 +30,7 @@ mod _csv { #[pyattr] const QUOTE_NONE: i32 = QuoteStyle::None as i32; - #[pyattr(name = "Error")] + #[pyattr(name = "Error", once)] fn error(vm: &VirtualMachine) -> PyTypeRef { PyType::new_simple_ref("_csv.Error", &vm.ctx.exceptions.exception_type).unwrap() } diff --git a/stdlib/src/socket.rs b/stdlib/src/socket.rs index 4de71fdd0..521531a42 100644 --- a/stdlib/src/socket.rs +++ b/stdlib/src/socket.rs @@ -80,53 +80,32 @@ mod _socket { vm.ctx.exceptions.os_error.clone() } - #[pyattr] + #[pyattr(once)] fn timeout(vm: &VirtualMachine) -> PyTypeRef { - rustpython_common::static_cell! { - static ERROR: PyTypeRef; - } - ERROR - .get_or_init(|| { - vm.ctx.new_class( - Some("socket"), - "timeout", - &vm.ctx.exceptions.os_error, - Default::default(), - ) - }) - .clone() + vm.ctx.new_class( + Some("socket"), + "timeout", + &vm.ctx.exceptions.os_error, + Default::default(), + ) } - #[pyattr] + #[pyattr(once)] fn herror(vm: &VirtualMachine) -> PyTypeRef { - rustpython_common::static_cell! { - static ERROR: PyTypeRef; - } - ERROR - .get_or_init(|| { - vm.ctx.new_class( - Some("socket"), - "herror", - &vm.ctx.exceptions.os_error, - Default::default(), - ) - }) - .clone() + vm.ctx.new_class( + Some("socket"), + "herror", + &vm.ctx.exceptions.os_error, + Default::default(), + ) } - #[pyattr] + #[pyattr(once)] fn gaierror(vm: &VirtualMachine) -> PyTypeRef { - rustpython_common::static_cell! { - static ERROR: PyTypeRef; - } - ERROR - .get_or_init(|| { - vm.ctx.new_class( - Some("socket"), - "gaierror", - &vm.ctx.exceptions.os_error, - Default::default(), - ) - }) - .clone() + vm.ctx.new_class( + Some("socket"), + "gaierror", + &vm.ctx.exceptions.os_error, + Default::default(), + ) } #[pyfunction] diff --git a/stdlib/src/ssl.rs b/stdlib/src/ssl.rs index 8709839d2..e7f00a6b6 100644 --- a/stdlib/src/ssl.rs +++ b/stdlib/src/ssl.rs @@ -174,90 +174,47 @@ mod _ssl { parse_version_info(openssl_api_version) } - #[pyattr(name = "SSLError")] + #[pyattr(name = "SSLError", once)] fn ssl_error(vm: &VirtualMachine) -> PyTypeRef { - rustpython_common::static_cell! { - static ERROR: PyTypeRef; - } - ERROR - .get_or_init(|| { - PyType::new_simple_ref("ssl.SSLError", &vm.ctx.exceptions.os_error).unwrap() - }) - .clone() + PyType::new_simple_ref("ssl.SSLError", &vm.ctx.exceptions.os_error).unwrap() } - #[pyattr(name = "SSLCertVerificationError")] + #[pyattr(name = "SSLCertVerificationError", once)] fn ssl_cert_verification_error(vm: &VirtualMachine) -> PyTypeRef { - rustpython_common::static_cell! { - static ERROR: PyTypeRef; - } - ERROR - .get_or_init(|| { - let ssl_error = ssl_error(vm); - PyType::new_ref( - "ssl.SSLCertVerificationError", - vec![ssl_error, vm.ctx.exceptions.value_error.clone()], - Default::default(), - PyBaseException::make_slots(), - vm.ctx.types.type_type.clone(), - ) - .unwrap() - }) - .clone() + let ssl_error = ssl_error(vm); + PyType::new_ref( + "ssl.SSLCertVerificationError", + vec![ssl_error, vm.ctx.exceptions.value_error.clone()], + Default::default(), + PyBaseException::make_slots(), + vm.ctx.types.type_type.clone(), + ) + .unwrap() } - #[pyattr(name = "SSLZeroReturnError")] + #[pyattr(name = "SSLZeroReturnError", once)] fn ssl_zero_return_error(vm: &VirtualMachine) -> PyTypeRef { - rustpython_common::static_cell! { - static ERROR: PyTypeRef; - } - ERROR - .get_or_init(|| { - PyType::new_simple_ref("ssl.SSLZeroReturnError", &ssl_error(vm)).unwrap() - }) - .clone() + PyType::new_simple_ref("ssl.SSLZeroReturnError", &ssl_error(vm)).unwrap() } - #[pyattr(name = "SSLWantReadError")] + #[pyattr(name = "SSLWantReadError", once)] fn ssl_want_read_error(vm: &VirtualMachine) -> PyTypeRef { - rustpython_common::static_cell! { - static ERROR: PyTypeRef; - } - ERROR - .get_or_init(|| PyType::new_simple_ref("ssl.SSLWantReadError", &ssl_error(vm)).unwrap()) - .clone() + PyType::new_simple_ref("ssl.SSLWantReadError", &ssl_error(vm)).unwrap() } - #[pyattr(name = "SSLWantWriteError")] + #[pyattr(name = "SSLWantWriteError", once)] fn ssl_want_write_error(vm: &VirtualMachine) -> PyTypeRef { - rustpython_common::static_cell! { - static ERROR: PyTypeRef; - } - ERROR - .get_or_init(|| { - PyType::new_simple_ref("ssl.SSLWantWriteError", &ssl_error(vm)).unwrap() - }) - .clone() + PyType::new_simple_ref("ssl.SSLWantWriteError", &ssl_error(vm)).unwrap() } - #[pyattr(name = "SSLSyscallError")] + #[pyattr(name = "SSLSyscallError", once)] fn ssl_syscall_error(vm: &VirtualMachine) -> PyTypeRef { - rustpython_common::static_cell! { - static ERROR: PyTypeRef; - } - ERROR - .get_or_init(|| PyType::new_simple_ref("ssl.SSLSyscallError", &ssl_error(vm)).unwrap()) - .clone() + PyType::new_simple_ref("ssl.SSLSyscallError", &ssl_error(vm)).unwrap() } - #[pyattr(name = "SSLEOFError")] + #[pyattr(name = "SSLEOFError", once)] fn ssl_eof_error(vm: &VirtualMachine) -> PyTypeRef { - rustpython_common::static_cell! { - static ERROR: PyTypeRef; - } - ERROR - .get_or_init(|| PyType::new_simple_ref("ssl.SSLEOFError", &ssl_error(vm)).unwrap()) - .clone() + PyType::new_simple_ref("ssl.SSLEOFError", &ssl_error(vm)).unwrap() } type OpensslVersionInfo = (u8, u8, u8, u8, u8); diff --git a/stdlib/src/termios.rs b/stdlib/src/termios.rs index 97ccdac29..1f203bb29 100644 --- a/stdlib/src/termios.rs +++ b/stdlib/src/termios.rs @@ -100,20 +100,13 @@ mod termios { ) } - #[pyattr(name = "error")] + #[pyattr(name = "error", once)] fn error_type(vm: &VirtualMachine) -> PyTypeRef { - rustpython_common::static_cell! { - static TERMIOS_ERROR: PyTypeRef; - } - TERMIOS_ERROR - .get_or_init(|| { - vm.ctx.new_class( - Some("termios"), - "error", - &vm.ctx.exceptions.os_error, - Default::default(), - ) - }) - .clone() + vm.ctx.new_class( + Some("termios"), + "error", + &vm.ctx.exceptions.os_error, + Default::default(), + ) } } diff --git a/stdlib/src/zlib.rs b/stdlib/src/zlib.rs index 492fc60e3..d466e248b 100644 --- a/stdlib/src/zlib.rs +++ b/stdlib/src/zlib.rs @@ -53,7 +53,7 @@ mod zlib { #[pyattr] const DEF_MEM_LEVEL: u8 = 8; - #[pyattr] + #[pyattr(once)] fn error(vm: &VirtualMachine) -> PyTypeRef { PyType::new_simple_ref("zlib.error", &vm.ctx.exceptions.exception_type).unwrap() } diff --git a/vm/src/stdlib/pystruct.rs b/vm/src/stdlib/pystruct.rs index 7530a303c..91e376cc0 100644 --- a/vm/src/stdlib/pystruct.rs +++ b/vm/src/stdlib/pystruct.rs @@ -960,21 +960,14 @@ pub(crate) mod _struct { #[pyfunction] fn _clearcache() {} - #[pyattr(name = "error")] + #[pyattr(name = "error", once)] fn error_type(vm: &VirtualMachine) -> PyTypeRef { - rustpython_common::static_cell! { - static STRUCT_ERROR: PyTypeRef; - } - STRUCT_ERROR - .get_or_init(|| { - vm.ctx.new_class( - Some("struct"), - "error", - &vm.ctx.exceptions.exception_type, - Default::default(), - ) - }) - .clone() + vm.ctx.new_class( + Some("struct"), + "error", + &vm.ctx.exceptions.exception_type, + Default::default(), + ) } fn new_struct_error(vm: &VirtualMachine, msg: String) -> PyBaseExceptionRef { From fee42a1074f621f0295c830fea5b6aa352cc4530 Mon Sep 17 00:00:00 2001 From: snowapril Date: Sat, 6 Nov 2021 16:17:11 +0900 Subject: [PATCH 3/6] Add docs for each error in ssl module Signed-off-by: snowapril --- stdlib/src/ssl.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/stdlib/src/ssl.rs b/stdlib/src/ssl.rs index e7f00a6b6..6cf0b55e3 100644 --- a/stdlib/src/ssl.rs +++ b/stdlib/src/ssl.rs @@ -174,11 +174,13 @@ mod _ssl { parse_version_info(openssl_api_version) } + /// An error occurred in the SSL implementation. #[pyattr(name = "SSLError", once)] fn ssl_error(vm: &VirtualMachine) -> PyTypeRef { PyType::new_simple_ref("ssl.SSLError", &vm.ctx.exceptions.os_error).unwrap() } + /// A certificate could not be verified. #[pyattr(name = "SSLCertVerificationError", once)] fn ssl_cert_verification_error(vm: &VirtualMachine) -> PyTypeRef { let ssl_error = ssl_error(vm); @@ -192,26 +194,31 @@ mod _ssl { .unwrap() } + /// SSL/TLS session closed cleanly. #[pyattr(name = "SSLZeroReturnError", once)] fn ssl_zero_return_error(vm: &VirtualMachine) -> PyTypeRef { PyType::new_simple_ref("ssl.SSLZeroReturnError", &ssl_error(vm)).unwrap() } + /// Non-blocking SSL socket needs to read more data before the requested operation can be completed. #[pyattr(name = "SSLWantReadError", once)] fn ssl_want_read_error(vm: &VirtualMachine) -> PyTypeRef { PyType::new_simple_ref("ssl.SSLWantReadError", &ssl_error(vm)).unwrap() } + /// Non-blocking SSL socket needs to write more data before the requested operation can be completed. #[pyattr(name = "SSLWantWriteError", once)] fn ssl_want_write_error(vm: &VirtualMachine) -> PyTypeRef { PyType::new_simple_ref("ssl.SSLWantWriteError", &ssl_error(vm)).unwrap() } + /// System error when attempting SSL operation. #[pyattr(name = "SSLSyscallError", once)] fn ssl_syscall_error(vm: &VirtualMachine) -> PyTypeRef { PyType::new_simple_ref("ssl.SSLSyscallError", &ssl_error(vm)).unwrap() } + /// SSL/TLS connection terminated abruptly. #[pyattr(name = "SSLEOFError", once)] fn ssl_eof_error(vm: &VirtualMachine) -> PyTypeRef { PyType::new_simple_ref("ssl.SSLEOFError", &ssl_error(vm)).unwrap() From 59582ed295a827225fe8bc393deff828be590b4d Mon Sep 17 00:00:00 2001 From: snowapril Date: Sat, 6 Nov 2021 17:17:31 +0900 Subject: [PATCH 4/6] Add new_exception_type for module-level exception At previous, `vm.ctx.new_class` did role for adding exception in module-level. This commit add `new_exception_type` for doing that part of role. As cpython implementation, if no bases is given, pass `exception_type` by default Signed-off-by: snowapril --- vm/src/pyobject.rs | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index d7cff5d60..0d78ba471 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -12,9 +12,9 @@ use crate::{ builtinfunc::{PyBuiltinFunction, PyBuiltinMethod, PyNativeFuncDef}, bytes, getset::{IntoPyGetterFunc, IntoPySetterFunc, PyGetSet}, - object, pystr, PyBaseExceptionRef, PyBoundMethod, PyDict, PyDictRef, PyEllipsis, PyFloat, - PyFrozenSet, PyGenericAlias, PyInt, PyIntRef, PyList, PyListRef, PyNone, PyNotImplemented, - PyStr, PyTuple, PyTupleRef, PyType, PyTypeRef, + object, pystr, PyBaseException, PyBaseExceptionRef, PyBoundMethod, PyDict, PyDictRef, + PyEllipsis, PyFloat, PyFrozenSet, PyGenericAlias, PyInt, PyIntRef, PyList, PyListRef, + PyNone, PyNotImplemented, PyStr, PyTuple, PyTupleRef, PyType, PyTypeRef, }, dictdatatype::Dict, exceptions, @@ -242,6 +242,30 @@ impl PyContext { .unwrap() } + pub fn new_exception_type( + &self, + module: &str, + name: &str, + bases: Option>, + ) -> PyTypeRef { + let bases = if let Some(bases) = bases { + bases + } else { + vec![self.exceptions.exception_type.clone()] + }; + let mut attrs = PyAttributes::default(); + attrs.insert("__module__".to_string(), self.new_str(module).into()); + + PyType::new_ref( + name, + bases, + attrs, + PyBaseException::make_slots(), + self.types.type_type.clone(), + ) + .unwrap() + } + #[inline] pub fn make_funcdef(&self, name: impl Into, f: F) -> PyNativeFuncDef where From ab1693e1317d01c5bec59989bd9993d046078cb4 Mon Sep 17 00:00:00 2001 From: snowapril Date: Sat, 6 Nov 2021 17:20:00 +0900 Subject: [PATCH 5/6] Replace `new_class` to `new_exception_type` Replace `new_class` method call for module-level exceptions to newly added `new_exception_type` Signed-off-by: snowapril --- stdlib/src/binascii.rs | 14 ++++---------- stdlib/src/csv.rs | 8 ++++++-- stdlib/src/socket.rs | 21 +++++++++------------ stdlib/src/ssl.rs | 34 +++++++++++++++++++--------------- stdlib/src/termios.rs | 7 +++---- stdlib/src/zlib.rs | 8 ++++++-- vm/src/stdlib/pystruct.rs | 7 +------ 7 files changed, 48 insertions(+), 51 deletions(-) diff --git a/stdlib/src/binascii.rs b/stdlib/src/binascii.rs index 59526c193..2130b5ddc 100644 --- a/stdlib/src/binascii.rs +++ b/stdlib/src/binascii.rs @@ -13,22 +13,16 @@ mod decl { #[pyattr(name = "Error", once)] fn error_type(vm: &VirtualMachine) -> PyTypeRef { - vm.ctx.new_class( - Some("binascii"), + vm.ctx.new_exception_type( + "binascii", "Error", - &vm.ctx.exceptions.value_error, - Default::default(), + Some(vec![vm.ctx.exceptions.value_error.clone()]), ) } #[pyattr(name = "Incomplete", once)] fn incomplete_type(vm: &VirtualMachine) -> PyTypeRef { - vm.ctx.new_class( - Some("binascii"), - "Incomplete", - &vm.ctx.exceptions.exception_type, - Default::default(), - ) + vm.ctx.new_exception_type("binascii", "Incomplete", None) } fn hex_nibble(n: u8) -> u8 { diff --git a/stdlib/src/csv.rs b/stdlib/src/csv.rs index 2e8a44f8d..a9fc1f1c9 100644 --- a/stdlib/src/csv.rs +++ b/stdlib/src/csv.rs @@ -11,7 +11,7 @@ pub(crate) fn make_module(vm: &VirtualMachine) -> PyObjectRef { mod _csv { use crate::common::lock::PyMutex; use crate::vm::{ - builtins::{PyStr, PyStrRef, PyType, PyTypeRef}, + builtins::{PyStr, PyStrRef, PyTypeRef}, function::{ArgIterable, ArgumentError, FromArgs, FuncArgs}, match_class, protocol::{PyIter, PyIterReturn}, @@ -32,7 +32,11 @@ mod _csv { #[pyattr(name = "Error", once)] fn error(vm: &VirtualMachine) -> PyTypeRef { - PyType::new_simple_ref("_csv.Error", &vm.ctx.exceptions.exception_type).unwrap() + vm.ctx.new_exception_type( + "_csv", + "Error", + Some(vec![vm.ctx.exceptions.exception_type.clone()]), + ) } #[pyfunction] diff --git a/stdlib/src/socket.rs b/stdlib/src/socket.rs index 521531a42..9543c02b2 100644 --- a/stdlib/src/socket.rs +++ b/stdlib/src/socket.rs @@ -82,29 +82,26 @@ mod _socket { #[pyattr(once)] fn timeout(vm: &VirtualMachine) -> PyTypeRef { - vm.ctx.new_class( - Some("socket"), + vm.ctx.new_exception_type( + "socket", "timeout", - &vm.ctx.exceptions.os_error, - Default::default(), + Some(vec![vm.ctx.exceptions.os_error.clone()]), ) } #[pyattr(once)] fn herror(vm: &VirtualMachine) -> PyTypeRef { - vm.ctx.new_class( - Some("socket"), + vm.ctx.new_exception_type( + "socket", "herror", - &vm.ctx.exceptions.os_error, - Default::default(), + Some(vec![vm.ctx.exceptions.os_error.clone()]), ) } #[pyattr(once)] fn gaierror(vm: &VirtualMachine) -> PyTypeRef { - vm.ctx.new_class( - Some("socket"), + vm.ctx.new_exception_type( + "socket", "gaierror", - &vm.ctx.exceptions.os_error, - Default::default(), + Some(vec![vm.ctx.exceptions.os_error.clone()]), ) } diff --git a/stdlib/src/ssl.rs b/stdlib/src/ssl.rs index 6cf0b55e3..5230ba865 100644 --- a/stdlib/src/ssl.rs +++ b/stdlib/src/ssl.rs @@ -30,7 +30,7 @@ mod _ssl { }, socket::{self, PySocket}, vm::{ - builtins::{PyBaseException, PyBaseExceptionRef, PyStrRef, PyType, PyTypeRef, PyWeak}, + builtins::{PyBaseExceptionRef, PyStrRef, PyType, PyTypeRef, PyWeak}, exceptions, function::{ ArgBytesLike, ArgCallable, ArgMemoryBuffer, ArgStrOrBytesLike, IntoPyException, @@ -39,7 +39,7 @@ mod _ssl { stdlib::os::PyPathLike, types::Constructor, utils::{Either, ToCString}, - ItemProtocol, PyClassImpl, PyObjectRef, PyRef, PyResult, PyValue, VirtualMachine, + ItemProtocol, PyObjectRef, PyRef, PyResult, PyValue, VirtualMachine, }, }; use crossbeam_utils::atomic::AtomicCell; @@ -177,45 +177,49 @@ mod _ssl { /// An error occurred in the SSL implementation. #[pyattr(name = "SSLError", once)] fn ssl_error(vm: &VirtualMachine) -> PyTypeRef { - PyType::new_simple_ref("ssl.SSLError", &vm.ctx.exceptions.os_error).unwrap() + vm.ctx.new_exception_type( + "ssl", + "SSLError", + Some(vec![vm.ctx.exceptions.os_error.clone()]), + ) } /// A certificate could not be verified. #[pyattr(name = "SSLCertVerificationError", once)] fn ssl_cert_verification_error(vm: &VirtualMachine) -> PyTypeRef { - let ssl_error = ssl_error(vm); - PyType::new_ref( - "ssl.SSLCertVerificationError", - vec![ssl_error, vm.ctx.exceptions.value_error.clone()], - Default::default(), - PyBaseException::make_slots(), - vm.ctx.types.type_type.clone(), + vm.ctx.new_exception_type( + "ssl", + "SSLCertVerificationError", + Some(vec![ssl_error(vm), vm.ctx.exceptions.value_error.clone()]), ) - .unwrap() } /// SSL/TLS session closed cleanly. #[pyattr(name = "SSLZeroReturnError", once)] fn ssl_zero_return_error(vm: &VirtualMachine) -> PyTypeRef { - PyType::new_simple_ref("ssl.SSLZeroReturnError", &ssl_error(vm)).unwrap() + vm.ctx + .new_exception_type("ssl", "SSLZeroReturnError", Some(vec![ssl_error(vm)])) } /// Non-blocking SSL socket needs to read more data before the requested operation can be completed. #[pyattr(name = "SSLWantReadError", once)] fn ssl_want_read_error(vm: &VirtualMachine) -> PyTypeRef { - PyType::new_simple_ref("ssl.SSLWantReadError", &ssl_error(vm)).unwrap() + vm.ctx + .new_exception_type("ssl", "SSLWantReadError", Some(vec![ssl_error(vm)])) } /// Non-blocking SSL socket needs to write more data before the requested operation can be completed. #[pyattr(name = "SSLWantWriteError", once)] fn ssl_want_write_error(vm: &VirtualMachine) -> PyTypeRef { - PyType::new_simple_ref("ssl.SSLWantWriteError", &ssl_error(vm)).unwrap() + vm.ctx + .new_exception_type("ssl", "SSLWantWriteError", Some(vec![ssl_error(vm)])) } /// System error when attempting SSL operation. #[pyattr(name = "SSLSyscallError", once)] fn ssl_syscall_error(vm: &VirtualMachine) -> PyTypeRef { - PyType::new_simple_ref("ssl.SSLSyscallError", &ssl_error(vm)).unwrap() + vm.ctx + .new_exception_type("ssl", "SSLSyscallError", Some(vec![ssl_error(vm)])) } /// SSL/TLS connection terminated abruptly. diff --git a/stdlib/src/termios.rs b/stdlib/src/termios.rs index 1f203bb29..507a655fa 100644 --- a/stdlib/src/termios.rs +++ b/stdlib/src/termios.rs @@ -102,11 +102,10 @@ mod termios { #[pyattr(name = "error", once)] fn error_type(vm: &VirtualMachine) -> PyTypeRef { - vm.ctx.new_class( - Some("termios"), + vm.ctx.new_exception_type( + "termios", "error", - &vm.ctx.exceptions.os_error, - Default::default(), + Some(vec![vm.ctx.exceptions.os_error.clone()]), ) } } diff --git a/stdlib/src/zlib.rs b/stdlib/src/zlib.rs index d466e248b..d2f44de20 100644 --- a/stdlib/src/zlib.rs +++ b/stdlib/src/zlib.rs @@ -4,7 +4,7 @@ pub(crate) use zlib::make_module; mod zlib { use crate::common::lock::PyMutex; use crate::vm::{ - builtins::{PyBaseExceptionRef, PyBytes, PyBytesRef, PyIntRef, PyType, PyTypeRef}, + builtins::{PyBaseExceptionRef, PyBytes, PyBytesRef, PyIntRef, PyTypeRef}, function::{ArgBytesLike, OptionalArg}, IntoPyRef, PyResult, PyValue, VirtualMachine, }; @@ -55,7 +55,11 @@ mod zlib { #[pyattr(once)] fn error(vm: &VirtualMachine) -> PyTypeRef { - PyType::new_simple_ref("zlib.error", &vm.ctx.exceptions.exception_type).unwrap() + vm.ctx.new_exception_type( + "zlib", + "error", + Some(vec![vm.ctx.exceptions.exception_type.clone()]), + ) } /// Compute an Adler-32 checksum of data. diff --git a/vm/src/stdlib/pystruct.rs b/vm/src/stdlib/pystruct.rs index 91e376cc0..bec416b06 100644 --- a/vm/src/stdlib/pystruct.rs +++ b/vm/src/stdlib/pystruct.rs @@ -962,12 +962,7 @@ pub(crate) mod _struct { #[pyattr(name = "error", once)] fn error_type(vm: &VirtualMachine) -> PyTypeRef { - vm.ctx.new_class( - Some("struct"), - "error", - &vm.ctx.exceptions.exception_type, - Default::default(), - ) + vm.ctx.new_exception_type("struct", "error", None) } fn new_struct_error(vm: &VirtualMachine, msg: String) -> PyBaseExceptionRef { From 97f3434c0a4f96e30bb7f89e1ec8c87edd5d221f Mon Sep 17 00:00:00 2001 From: snowapril Date: Thu, 11 Nov 2021 17:01:14 +0900 Subject: [PATCH 6/6] Add `AttrItemMeta` for handling attribute item attathced with `once` Signed-off-by: snowapril --- derive/src/pymodule.rs | 79 ++++++++++++++++++------------------------ derive/src/util.rs | 13 +++++++ 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/derive/src/pymodule.rs b/derive/src/pymodule.rs index abeeb09b3..28124aeca 100644 --- a/derive/src/pymodule.rs +++ b/derive/src/pymodule.rs @@ -1,7 +1,7 @@ use crate::error::Diagnostic; use crate::util::{ - iter_use_idents, path_eq, pyclass_ident_and_attrs, text_signature, AttributeExt, ClassItemMeta, - ContentItem, ContentItemInner, ErrorVec, ItemMeta, ItemNursery, SimpleItemMeta, + iter_use_idents, pyclass_ident_and_attrs, text_signature, AttrItemMeta, AttributeExt, + ClassItemMeta, ContentItem, ContentItemInner, ErrorVec, ItemMeta, ItemNursery, SimpleItemMeta, ALL_ALLOWED_NAMES, }; use proc_macro2::TokenStream; @@ -37,41 +37,6 @@ pub fn impl_pymodule(attr: AttributeArgs, module_item: Item) -> Result { - unreachable!("#[pyattr] attached function must have return type.") - } - syn::ReturnType::Type(_, ty) => ty, - }; - let stmt: syn::Stmt = parse_quote! { - { - rustpython_common::static_cell! { - static ERROR: #return_type; - } - ERROR - .get_or_init(|| { - #(#stmts)* - }) - .clone() - } - }; - block.stmts = vec![stmt]; - } - } let (pyitems, cfgs) = attrs_to_module_items(attrs, new_module_item)?; for pyitem in pyitems.iter().rev() { let r = pyitem.gen_module_item(ModuleItemArgs { @@ -276,7 +241,7 @@ impl ContentItem for AttributeItem { } struct ModuleItemArgs<'a> { - item: &'a Item, + item: &'a mut Item, attrs: &'a mut Vec, context: &'a mut ModuleContext, cfgs: &'a [Attribute], @@ -405,15 +370,36 @@ impl ModuleItem for AttributeItem { fn gen_module_item(&self, args: ModuleItemArgs<'_>) -> Result<()> { let cfgs = args.cfgs.to_vec(); let attr = args.attrs.remove(self.index()); - let get_py_name = |attr: &Attribute, ident: &Ident| -> Result<_> { - let item_meta = SimpleItemMeta::from_attr(ident.clone(), attr)?; - let py_name = item_meta.simple_name()?; - Ok(py_name) - }; let (py_name, tokens) = match args.item { - Item::Fn(syn::ItemFn { sig, .. }) => { + Item::Fn(syn::ItemFn { sig, block, .. }) => { let ident = &sig.ident; - let py_name = get_py_name(&attr, ident)?; + // If `once` keyword is in #[pyattr], + // wrapping it with static_cell for preventing it from using it as function + let attr_meta = AttrItemMeta::from_attr(ident.clone(), &attr)?; + if attr_meta.inner()._bool("once")? { + let stmts = &block.stmts; + let return_type = match &sig.output { + syn::ReturnType::Default => { + unreachable!("#[pyattr] attached function must have return type.") + } + syn::ReturnType::Type(_, ty) => ty, + }; + let stmt: syn::Stmt = parse_quote! { + { + rustpython_common::static_cell! { + static ERROR: #return_type; + } + ERROR + .get_or_init(|| { + #(#stmts)* + }) + .clone() + } + }; + block.stmts = vec![stmt]; + } + + let py_name = attr_meta.simple_name()?; ( py_name.clone(), quote_spanned! { ident.span() => @@ -422,7 +408,8 @@ impl ModuleItem for AttributeItem { ) } Item::Const(syn::ItemConst { ident, .. }) => { - let py_name = get_py_name(&attr, ident)?; + let item_meta = SimpleItemMeta::from_attr(ident.clone(), &attr)?; + let py_name = item_meta.simple_name()?; ( py_name.clone(), quote_spanned! { ident.span() => diff --git a/derive/src/util.rs b/derive/src/util.rs index 1e494de85..f104c03c9 100644 --- a/derive/src/util.rs +++ b/derive/src/util.rs @@ -226,6 +226,19 @@ pub(crate) trait ItemMeta: Sized { pub(crate) struct SimpleItemMeta(pub ItemMetaInner); impl ItemMeta for SimpleItemMeta { + const ALLOWED_NAMES: &'static [&'static str] = &["name"]; + + fn from_inner(inner: ItemMetaInner) -> Self { + Self(inner) + } + fn inner(&self) -> &ItemMetaInner { + &self.0 + } +} + +pub(crate) struct AttrItemMeta(pub ItemMetaInner); + +impl ItemMeta for AttrItemMeta { const ALLOWED_NAMES: &'static [&'static str] = &["name", "once"]; fn from_inner(inner: ItemMetaInner) -> Self {