mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-29 03:04:38 +08:00
Match hashlib constructor name type diagnostics (#9066)
Use native type names, None spelling, and UTF-8 byte precision for invalid name arguments without changing accepted strings or hashing behavior. Assisted-by: OpenAI Codex:model identifier unavailable
This commit is contained in:
1 parent
4638b6a5f3
commit
924ef2f434
2 files changed
+43
-3
No files matched your search
@@ -8,7 +8,7 @@ pub(crate) use _hashlib::module_def;
|
||||
#[pymodule]
|
||||
pub(crate) mod _hashlib {
|
||||
use crate::vm::{
|
||||
Py, PyObject, PyObjectRef, PyPayload, PyResult, VirtualMachine,
|
||||
Py, PyObject, PyObjectRef, PyPayload, PyResult, TryFromObject, VirtualMachine,
|
||||
builtins::{
|
||||
PyBaseExceptionRef, PyBytes, PyFrozenSet, PyStr, PyType, PyTypeRef, PyUtf8StrRef,
|
||||
PyValueError,
|
||||
@@ -67,11 +67,35 @@ pub(crate) mod _hashlib {
|
||||
dict.into()
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct HashName(PyUtf8StrRef);
|
||||
|
||||
impl TryFromObject for HashName {
|
||||
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
|
||||
if !obj.downcastable::<PyStr>() {
|
||||
let name = if vm.is_none(&obj) {
|
||||
"None".into()
|
||||
} else {
|
||||
obj.class().slot_name()
|
||||
};
|
||||
let mut end = name.len().min(50);
|
||||
while !name.is_char_boundary(end) {
|
||||
end -= 1;
|
||||
}
|
||||
return Err(vm.new_type_error(format!(
|
||||
"new() argument 'name' must be str, not {}",
|
||||
&name[..end]
|
||||
)));
|
||||
}
|
||||
PyUtf8StrRef::try_from_object(vm, obj).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(FromArgs, Debug)]
|
||||
#[allow(unused)]
|
||||
struct NewHashArgs {
|
||||
#[pyarg(any)]
|
||||
name: PyUtf8StrRef,
|
||||
name: HashName,
|
||||
// Missing still allows the string keyword; b'' does not.
|
||||
#[pyarg(any, optional, py_default = "b''")]
|
||||
data: OptionalArg<ArgBytesLike>,
|
||||
@@ -785,7 +809,7 @@ pub(crate) mod _hashlib {
|
||||
#[pyfunction(name = "new")]
|
||||
fn hashlib_new(args: NewHashArgs, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
|
||||
let data = resolve_data(args.data, args.string, vm)?;
|
||||
match args.name.as_str().to_lowercase().as_str() {
|
||||
match args.name.0.as_str().to_lowercase().as_str() {
|
||||
"md5" => Ok(new_fixed_hasher("md5", data).into_pyobject(vm)),
|
||||
"sha1" => Ok(new_fixed_hasher("sha1", data).into_pyobject(vm)),
|
||||
"sha224" => Ok(new_fixed_hasher("sha224", data).into_pyobject(vm)),
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import _hashlib
|
||||
import _md5
|
||||
import _sha1
|
||||
import array
|
||||
import hashlib
|
||||
|
||||
from testutils import assert_raises
|
||||
@@ -64,3 +66,17 @@ assert _sha1.sha1(b"").hexdigest() == "da39a3ee5e6b4b0d3255bfef95601890afd80709"
|
||||
# narrower than the length asked for, converting the argument fails first.
|
||||
with assert_raises(OverflowError):
|
||||
hashlib.pbkdf2_hmac("sha256", b"password", b"salt", 1, 2**62)
|
||||
|
||||
|
||||
# Invalid names use the native constructor's bounded type diagnostic.
|
||||
for value, name in (
|
||||
(None, "None"),
|
||||
(42, "int"),
|
||||
(b"sha256", "bytes"),
|
||||
(array.array("b"), "array.array"),
|
||||
(type("x" * 60, (), {})(), "x" * 50),
|
||||
(type("€" * 17, (), {})(), "€" * 16),
|
||||
):
|
||||
with assert_raises(TypeError) as caught:
|
||||
_hashlib.new(value)
|
||||
assert str(caught.exception) == f"new() argument 'name' must be str, not {name}"
|
||||
Reference in new issue
Block a user