mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 10:44:36 +08:00
Fix bytes.isspace (#5655)
* Fix implementation of bytes.isspace to match the implementation in CPython. * Fix implementation of bytes.istitle so that test_bigmem now passes. Also added some extra_test to capture this. * Fix some clippy issues Signed-off-by: Hanif Ariffin <hanif.ariffin.4326@gmail.com> * bytes.istitle returns false when the bytes is empty. * Fix some edges of istitle with non-alphanumeric characters * Disable a line because python 3.12 errors on bad escape sequence * Match CPython's istitle a little closer * Fix clippy warning * Rewrite bytes.istitle along _Py_bytes_istitle The lookahead-based check accepted b"Not--a Titlecase String", which test_bytes covers. Track whether the previous byte was cased instead. isspace compares bytes directly rather than converting to char. Restore the b"omkmok\Xaa" assert: 3.14 reports an invalid escape sequence as a SyntaxWarning, not an error. Assisted-by: Claude --------- Signed-off-by: Hanif Ariffin <hanif.ariffin.4326@gmail.com> Co-authored-by: Jeong YunWon <jeong@youknowone.org>
This commit is contained in:
1 parent
74254421e4
commit
8e920098b2
3 files changed
+60
-41
No files matched your search
Vendored
-16
@@ -789,14 +789,6 @@ class BytesTest(unittest.TestCase, BaseStrTest):
|
||||
def test_swapcase(self, size):
|
||||
self._test_swapcase(size)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_isspace(self):
|
||||
return super().test_isspace()
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_istitle(self):
|
||||
return super().test_istitle()
|
||||
|
||||
|
||||
class BytearrayTest(unittest.TestCase, BaseStrTest):
|
||||
|
||||
@@ -823,14 +815,6 @@ class BytearrayTest(unittest.TestCase, BaseStrTest):
|
||||
test_hash = None
|
||||
test_split_large = None
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_isspace(self):
|
||||
return super().test_isspace()
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_istitle(self):
|
||||
return super().test_istitle()
|
||||
|
||||
class TupleTest(unittest.TestCase):
|
||||
|
||||
# Tuples have a small, fixed-sized head and an array of pointers to
|
||||
|
||||
@@ -397,44 +397,40 @@ impl PyBytesInner {
|
||||
self.elements.py_isupper()
|
||||
}
|
||||
|
||||
// _Py_bytes_isspace
|
||||
pub fn isspace(&self) -> bool {
|
||||
// is_ascii_whitespace excludes vertical tab, while Py_ISSPACE accepts it
|
||||
!self.elements.is_empty()
|
||||
&& self
|
||||
.elements
|
||||
.iter()
|
||||
.all(|x| char::from(*x).is_ascii_whitespace())
|
||||
.all(|x| x.is_ascii_whitespace() || *x == b'\x0b')
|
||||
}
|
||||
|
||||
// _Py_bytes_istitle
|
||||
pub fn istitle(&self) -> bool {
|
||||
if self.elements.is_empty() {
|
||||
return false;
|
||||
}
|
||||
let mut cased = false;
|
||||
let mut previous_is_cased = false;
|
||||
|
||||
let mut iter = self.elements.iter().peekable();
|
||||
let mut prev_cased = false;
|
||||
|
||||
while let Some(c) = iter.next() {
|
||||
let current = char::from(*c);
|
||||
let next = if let Some(k) = iter.peek() {
|
||||
char::from(**k)
|
||||
} else if current.is_uppercase() {
|
||||
return !prev_cased;
|
||||
for byte in &self.elements {
|
||||
if byte.is_ascii_uppercase() {
|
||||
if previous_is_cased {
|
||||
return false;
|
||||
}
|
||||
previous_is_cased = true;
|
||||
cased = true;
|
||||
} else if byte.is_ascii_lowercase() {
|
||||
if !previous_is_cased {
|
||||
return false;
|
||||
}
|
||||
previous_is_cased = true;
|
||||
cased = true;
|
||||
} else {
|
||||
return prev_cased;
|
||||
};
|
||||
|
||||
let is_cased = current.to_uppercase().next().unwrap() != current
|
||||
|| current.to_lowercase().next().unwrap() != current;
|
||||
if (is_cased && next.is_uppercase() && !prev_cased)
|
||||
|| (!is_cased && next.is_lowercase())
|
||||
{
|
||||
return false;
|
||||
previous_is_cased = false;
|
||||
}
|
||||
|
||||
prev_cased = is_cased;
|
||||
}
|
||||
|
||||
true
|
||||
cased
|
||||
}
|
||||
|
||||
pub fn lower(&self) -> Vec<u8> {
|
||||
|
||||
@@ -708,3 +708,42 @@ b = B1.fromhex("a0a1a2")
|
||||
assert b.foo == "bar"
|
||||
|
||||
skip_if_unsupported(3, 11, test__bytes__)
|
||||
|
||||
assert " \f\n\r\t\v".encode("utf-8").isspace()
|
||||
assert " \f\n\r\t\v".encode("latin-1").isspace()
|
||||
|
||||
# bytes.istitle tests
|
||||
s = b"Aa6A"
|
||||
assert s.istitle(), f"{s}"
|
||||
s = b"Aa6aA"
|
||||
assert not s.istitle(), f"{s}"
|
||||
s = b"Python Is Fun"
|
||||
assert s.istitle(), f"{s}"
|
||||
s = b"Python is fun"
|
||||
assert not s.istitle(), f"{s}"
|
||||
s = b"PYTHON IS FUN"
|
||||
assert not s.istitle(), f"{s}"
|
||||
s = b"Python 3.9 Is Awesome!"
|
||||
assert s.istitle(), f"{s}"
|
||||
s = b""
|
||||
assert not s.istitle(), f"{s}"
|
||||
s = b"Hello Is Amazing"
|
||||
assert s.istitle(), f"{s}"
|
||||
s = b"Not--a Titlecase String"
|
||||
assert not s.istitle(), f"{s}"
|
||||
s = b"123A"
|
||||
assert s.istitle(), f"{s}"
|
||||
s = b"123a"
|
||||
assert not s.istitle(), f"{s}"
|
||||
s = b"123A\ta"
|
||||
assert not s.istitle(), f"{s}"
|
||||
SUBSTR = b"123456"
|
||||
s = b"".join([b"A", b"a" * 64, SUBSTR])
|
||||
assert s.istitle(), f"{s}"
|
||||
s += b"A"
|
||||
assert s.istitle(), f"{s}"
|
||||
s += b"aA"
|
||||
assert not s.istitle(), f"{s}"
|
||||
assert "123A".istitle(), f"{s}"
|
||||
assert not "123a".istitle(), f"{s}"
|
||||
assert not "123A\ta".istitle(), f"{s}"
|
||||
Reference in new issue
Block a user