Skip to content

Commit 00ef668

Browse files
committed
String is* methods return false on empty string RustPython#363
1 parent 94dc6ec commit 00ef668

File tree

1 file changed

+60
-33
lines changed

1 file changed

+60
-33
lines changed

vm/src/obj/objstr.rs

Lines changed: 60 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -464,26 +464,34 @@ fn str_isidentifier(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
464464
// which is why isspace is using is_ascii_whitespace. Same for isupper & islower
465465
fn str_isspace(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
466466
arg_check!(vm, args, required = [(s, Some(vm.ctx.str_type()))]);
467-
let is_whitespace = get_value(&s).chars().all(|c| c.is_ascii_whitespace());
468-
Ok(vm.ctx.new_bool(is_whitespace))
467+
let value = get_value(&s);
468+
Ok(vm
469+
.ctx
470+
.new_bool(!value.is_empty() && value.chars().all(|c| c.is_ascii_whitespace())))
469471
}
470472

471473
fn str_isupper(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
472474
arg_check!(vm, args, required = [(s, Some(vm.ctx.str_type()))]);
473-
let is_upper = get_value(&s)
474-
.chars()
475-
.filter(|x| !x.is_ascii_whitespace())
476-
.all(|c| c.is_uppercase());
477-
Ok(vm.ctx.new_bool(is_upper))
475+
let value = get_value(&s);
476+
Ok(vm.ctx.new_bool(
477+
!value.is_empty()
478+
&& value
479+
.chars()
480+
.filter(|x| !x.is_ascii_whitespace())
481+
.all(|c| c.is_uppercase()),
482+
))
478483
}
479484

480485
fn str_islower(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
481486
arg_check!(vm, args, required = [(s, Some(vm.ctx.str_type()))]);
482-
let is_lower = get_value(&s)
483-
.chars()
484-
.filter(|x| !x.is_ascii_whitespace())
485-
.all(|c| c.is_lowercase());
486-
Ok(vm.ctx.new_bool(is_lower))
487+
let value = get_value(&s);
488+
Ok(vm.ctx.new_bool(
489+
!value.is_empty()
490+
&& value
491+
.chars()
492+
.filter(|x| !x.is_ascii_whitespace())
493+
.all(|c| c.is_lowercase()),
494+
))
487495
}
488496

489497
// doesn't implement keep new line delimeter just yet
@@ -785,10 +793,15 @@ fn str_istitle(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
785793
arg_check!(vm, args, required = [(s, Some(vm.ctx.str_type()))]);
786794
let value = get_value(&s);
787795
let mut is_titled = true;
788-
for word in value.split(" ") {
789-
if word != make_title(&word) {
790-
is_titled = false;
791-
break;
796+
797+
if value.is_empty() {
798+
is_titled = false;
799+
} else {
800+
for word in value.split(" ") {
801+
if word != make_title(&word) {
802+
is_titled = false;
803+
break;
804+
}
792805
}
793806
}
794807
Ok(vm.ctx.new_bool(is_titled))
@@ -845,14 +858,18 @@ fn str_contains(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
845858

846859
fn str_isalnum(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
847860
arg_check!(vm, args, required = [(s, Some(vm.ctx.str_type()))]);
848-
let is_alnum = get_value(&s).chars().all(|c| c.is_alphanumeric());
849-
Ok(vm.ctx.new_bool(is_alnum))
861+
let value = get_value(&s);
862+
Ok(vm
863+
.ctx
864+
.new_bool(!value.is_empty() && value.chars().all(|c| c.is_alphanumeric())))
850865
}
851866

852867
fn str_isascii(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
853868
arg_check!(vm, args, required = [(s, Some(vm.ctx.str_type()))]);
854-
let is_ascii = get_value(&s).chars().all(|c| c.is_ascii());
855-
Ok(vm.ctx.new_bool(is_ascii))
869+
let value = get_value(&s);
870+
Ok(vm
871+
.ctx
872+
.new_bool(!value.is_empty() && value.chars().all(|c| c.is_ascii())))
856873
}
857874

858875
fn str_rindex(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -905,14 +922,18 @@ fn str_rfind(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
905922

906923
fn str_isnumeric(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
907924
arg_check!(vm, args, required = [(s, Some(vm.ctx.str_type()))]);
908-
let is_numeric = get_value(&s).chars().all(|c| c.is_numeric());
909-
Ok(vm.ctx.new_bool(is_numeric))
925+
let value = get_value(&s);
926+
Ok(vm
927+
.ctx
928+
.new_bool(!value.is_empty() && value.chars().all(|c| c.is_numeric())))
910929
}
911930

912931
fn str_isalpha(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
913932
arg_check!(vm, args, required = [(s, Some(vm.ctx.str_type()))]);
914-
let is_alpha = get_value(&s).chars().all(|c| c.is_alphanumeric());
915-
Ok(vm.ctx.new_bool(is_alpha))
933+
let value = get_value(&s);
934+
Ok(vm
935+
.ctx
936+
.new_bool(!value.is_empty() && value.chars().all(|c| c.is_alphanumeric())))
916937
}
917938

918939
fn str_isdigit(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
@@ -923,18 +944,24 @@ fn str_isdigit(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
923944
0x2070, 0x00B9, 0x00B2, 0x00B3, 0x2074, 0x2075, 0x2076, 0x2077, 0x2078, 0x2079,
924945
];
925946
let mut is_digit: bool = true;
926-
for c in value.chars() {
927-
if !c.is_digit(10) {
928-
// checking if char is exponent
929-
let char_as_uni: u16 = c as u16;
930-
if valid_unicodes.contains(&char_as_uni) {
931-
continue;
932-
} else {
933-
is_digit = false;
934-
break;
947+
948+
if value.is_empty() {
949+
is_digit = false;
950+
} else {
951+
for c in value.chars() {
952+
if !c.is_digit(10) {
953+
// checking if char is exponent
954+
let char_as_uni: u16 = c as u16;
955+
if valid_unicodes.contains(&char_as_uni) {
956+
continue;
957+
} else {
958+
is_digit = false;
959+
break;
960+
}
935961
}
936962
}
937963
}
964+
938965
Ok(vm.ctx.new_bool(is_digit))
939966
}
940967

0 commit comments

Comments
 (0)