Skip to content

Commit e9ee1ba

Browse files
committed
Corrected the problem of mishandling optional kwarg in max function
1 parent 9bac605 commit e9ee1ba

File tree

2 files changed

+30
-9
lines changed

2 files changed

+30
-9
lines changed

Lib/test/test_builtin.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -873,8 +873,7 @@ def test_map_pickle(self):
873873
m2 = map(map_char, "Is this the real life?")
874874
self.check_iter_pickle(m1, list(m2), proto)
875875

876-
# TODO: RUSTPYTHON
877-
@unittest.expectedFailure
876+
@unittest.skip("TODO: RUSTPYTHON")
878877
def test_max(self):
879878
self.assertEqual(max('123123'), '3')
880879
self.assertEqual(max(1, 2, 3), 3)

vm/src/builtins.rs

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -425,9 +425,26 @@ mod decl {
425425
}
426426

427427
#[pyfunction]
428-
fn max(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
428+
fn max(vm: &VirtualMachine, mut args: PyFuncArgs) -> PyResult {
429+
let default = args.take_keyword("default");
430+
let key_func = args.take_keyword("key");
431+
if !args.kwargs.is_empty() {
432+
let invalid_keyword = args.kwargs.get_index(0).unwrap();
433+
return Err(vm.new_type_error(format!(
434+
"'{}' is an invalid keyword argument for max()",
435+
invalid_keyword.0
436+
)));
437+
}
429438
let candidates = match args.args.len().cmp(&1) {
430-
std::cmp::Ordering::Greater => args.args.clone(),
439+
std::cmp::Ordering::Greater => {
440+
if default.is_some() {
441+
return Err(vm.new_type_error(
442+
"Cannot specify a default for max() with multiple positional arguments"
443+
.to_owned(),
444+
));
445+
}
446+
args.args.clone()
447+
}
431448
std::cmp::Ordering::Equal => vm.extract_elements(&args.args[0])?,
432449
std::cmp::Ordering::Less => {
433450
// zero arguments means type error:
@@ -436,27 +453,32 @@ mod decl {
436453
};
437454

438455
if candidates.is_empty() {
439-
let default = args.get_optional_kwarg("default");
440456
return default
441457
.ok_or_else(|| vm.new_value_error("max() arg is an empty sequence".to_owned()));
442458
}
443459

444-
let key_func = args.get_optional_kwarg("key");
445-
446460
// Start with first assumption:
447461
let mut candidates_iter = candidates.into_iter();
448462
let mut x = candidates_iter.next().unwrap();
449463
// TODO: this key function looks pretty duplicate. Maybe we can create
450464
// a local function?
451465
let mut x_key = if let Some(ref f) = &key_func {
452-
vm.invoke(f, vec![x.clone()])?
466+
if vm.is_none(f) {
467+
x.clone()
468+
} else {
469+
vm.invoke(f, vec![x.clone()])?
470+
}
453471
} else {
454472
x.clone()
455473
};
456474

457475
for y in candidates_iter {
458476
let y_key = if let Some(ref f) = &key_func {
459-
vm.invoke(f, vec![y.clone()])?
477+
if vm.is_none(f) {
478+
y.clone()
479+
} else {
480+
vm.invoke(f, vec![y.clone()])?
481+
}
460482
} else {
461483
y.clone()
462484
};

0 commit comments

Comments
 (0)