From ffb374f6ae4c3e291f1fdefc235bc03f34727bbc Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 10 Sep 2019 19:59:37 +0200 Subject: [PATCH 01/10] Add `sorted` and `list.sort` Mostly finished, needs some argument parsing changes. --- builtin/builtin.go | 27 ++++++++- py/list.go | 133 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+), 1 deletion(-) diff --git a/builtin/builtin.go b/builtin/builtin.go index bb4158c4..96e615cc 100644 --- a/builtin/builtin.go +++ b/builtin/builtin.go @@ -60,7 +60,7 @@ func init() { py.MustNewMethod("repr", builtin_repr, 0, repr_doc), py.MustNewMethod("round", builtin_round, 0, round_doc), py.MustNewMethod("setattr", builtin_setattr, 0, setattr_doc), - // py.MustNewMethod("sorted", builtin_sorted, 0, sorted_doc), + py.MustNewMethod("sorted", builtin_sorted, 0, sorted_doc), py.MustNewMethod("sum", builtin_sum, 0, sum_doc), // py.MustNewMethod("vars", builtin_vars, 0, vars_doc), } @@ -1074,3 +1074,28 @@ func builtin_sum(self py.Object, args py.Tuple) (py.Object, error) { } return start, nil } + +const sorted_doc = `sorted(iterable, key=None, reverse=False) +Return a new list containing all items from the iterable in ascending order. + +A custom key function can be supplied to customize the sort order, and the +reverse flag can be set to request the result in descending order.` + +func builtin_sorted(self py.Object, args py.Tuple, kwargs py.StringDict) (py.Object, error) { + var iterable py.Object + var keyFunc py.Object = py.None + var reverse py.Object = py.False + err := py.ParseTupleAndKeywords(args, kwargs, "O|Op:sorted", []string{"iterable", "key", "reverse"}, &iterable, &keyFunc, &reverse) + if err != nil { + return nil, err + } + l, err := py.SequenceList(iterable) + if err != nil { + return nil, err + } + err = py.SortInPlace(l, keyFunc, reverse) + if err != nil { + return nil, err + } + return l, nil +} diff --git a/py/list.go b/py/list.go index 9e8e3dca..a338040e 100644 --- a/py/list.go +++ b/py/list.go @@ -6,6 +6,10 @@ package py +import ( + "sort" +) + var ListType = ObjectType.NewType("list", "list() -> new empty list\nlist(iterable) -> new list initialized from iterable's items", ListNew, nil) // FIXME lists are mutable so this should probably be struct { Tuple } then can use the sub methods on Tuple @@ -34,6 +38,29 @@ func init() { return NoneType{}, nil }, 0, "extend([item])") + ListType.Dict["sort"] = MustNewMethod("sort", func(self Object, args Tuple, kwargs StringDict) (Object, error) { + + if len(args) != 0 { + return nil, ExceptionNewf(TypeError, "sort() takes no positional arguments") + } + + var keyFunc Object = None + var reverse Object = False + + err := ParseTupleAndKeywords(nil, kwargs, "|Op:sort", []string{"key", "reverse"}, &keyFunc, &reverse) + if err != nil { + return nil, err + } + + listSelf := self.(*List) + + err = SortInPlace(listSelf, keyFunc, reverse) + if err != nil { + return nil, err + } + return NoneType{}, nil + }, 0, "sort(key=None, reverse=False)") + } // Type of this List object @@ -331,3 +358,109 @@ func (a *List) M__ne__(other Object) (Object, error) { } return False, nil } + +type sortable struct { + l *List + keyFunc Object + reverse bool + firstErr error +} + +type ptrSortable struct { + s *sortable +} + +func (s ptrSortable) Len() int { + return s.s.l.Len() +} + +func (s ptrSortable) Swap(i, j int) { + elemI, err := s.s.l.M__getitem__(Int(i)) + if err != nil { + if s.s.firstErr == nil { + s.s.firstErr = err + } + return + } + elemJ, err := s.s.l.M__getitem__(Int(j)) + if err != nil { + if s.s.firstErr == nil { + s.s.firstErr = err + } + return + } + _, err = s.s.l.M__setitem__(Int(i), elemJ) + if err != nil { + if s.s.firstErr == nil { + s.s.firstErr = err + } + } + _, err = s.s.l.M__setitem__(Int(j), elemI) + if err != nil { + if s.s.firstErr == nil { + s.s.firstErr = err + } + } +} + +func (s ptrSortable) Less(i, j int) bool { + elemI, err := s.s.l.M__getitem__(Int(i)) + if err != nil { + if s.s.firstErr == nil { + s.s.firstErr = err + } + return false + } + elemJ, err := s.s.l.M__getitem__(Int(j)) + if err != nil { + if s.s.firstErr == nil { + s.s.firstErr = err + } + return false + } + + if s.s.keyFunc != None { + elemI, err = Call(s.s.keyFunc, Tuple{elemI}, nil) + if err != nil { + if s.s.firstErr == nil { + s.s.firstErr = err + } + } + elemJ, err = Call(s.s.keyFunc, Tuple{elemJ}, nil) + if err != nil { + if s.s.firstErr == nil { + s.s.firstErr = err + } + } + } + + var cmpResult Object + if s.s.reverse { + cmpResult, err = Lt(elemJ, elemI) + } else { + cmpResult, err = Lt(elemI, elemJ) + } + + if err != nil { + if s.s.firstErr == nil { + s.s.firstErr = err + } + } + + if boolResult, ok := cmpResult.(Bool); ok { + return bool(boolResult) + } + + return false +} + +func SortInPlace(l *List, keyFunc Object, reverse Object) error { + switch keyFunc.(type) { + case NoneType, I__call__: + default: + return ExceptionNewf(TypeError, "'%s' object is not callable", keyFunc.Type().Name) + } + s := ptrSortable{&sortable{l, keyFunc, ObjectIsTrue(reverse), nil}} + sort.Stable(s) + return s.s.firstErr +} From 7cc1d0bc87c47793402481137185d78769ec4a66 Mon Sep 17 00:00:00 2001 From: Tim S Date: Sun, 15 Sep 2019 12:54:21 +0200 Subject: [PATCH 02/10] Unpacking of args works now for `sorted` and `list.sort` --- builtin/builtin.go | 8 +++---- py/list.go | 58 +++++++++++++++++++++++++--------------------- 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/builtin/builtin.go b/builtin/builtin.go index 96e615cc..27e31965 100644 --- a/builtin/builtin.go +++ b/builtin/builtin.go @@ -1076,16 +1076,16 @@ func builtin_sum(self py.Object, args py.Tuple) (py.Object, error) { } const sorted_doc = `sorted(iterable, key=None, reverse=False) + Return a new list containing all items from the iterable in ascending order. A custom key function can be supplied to customize the sort order, and the reverse flag can be set to request the result in descending order.` func builtin_sorted(self py.Object, args py.Tuple, kwargs py.StringDict) (py.Object, error) { + const funcName = "sorted" var iterable py.Object - var keyFunc py.Object = py.None - var reverse py.Object = py.False - err := py.ParseTupleAndKeywords(args, kwargs, "O|Op:sorted", []string{"iterable", "key", "reverse"}, &iterable, &keyFunc, &reverse) + err := py.UnpackTuple(args, nil, funcName, 1, 1, &iterable) if err != nil { return nil, err } @@ -1093,7 +1093,7 @@ func builtin_sorted(self py.Object, args py.Tuple, kwargs py.StringDict) (py.Obj if err != nil { return nil, err } - err = py.SortInPlace(l, keyFunc, reverse) + err = py.SortInPlace(l, kwargs, funcName) if err != nil { return nil, err } diff --git a/py/list.go b/py/list.go index a338040e..1c575f2a 100644 --- a/py/list.go +++ b/py/list.go @@ -39,22 +39,13 @@ func init() { }, 0, "extend([item])") ListType.Dict["sort"] = MustNewMethod("sort", func(self Object, args Tuple, kwargs StringDict) (Object, error) { - - if len(args) != 0 { - return nil, ExceptionNewf(TypeError, "sort() takes no positional arguments") - } - - var keyFunc Object = None - var reverse Object = False - - err := ParseTupleAndKeywords(nil, kwargs, "|Op:sort", []string{"key", "reverse"}, &keyFunc, &reverse) + const funcName = "sort" + err := UnpackTuple(args, nil, funcName, 0, 0) if err != nil { return nil, err } - listSelf := self.(*List) - - err = SortInPlace(listSelf, keyFunc, reverse) + err = SortInPlace(listSelf, kwargs, funcName) if err != nil { return nil, err } @@ -375,27 +366,27 @@ func (s ptrSortable) Len() int { } func (s ptrSortable) Swap(i, j int) { - elemI, err := s.s.l.M__getitem__(Int(i)) + itemI, err := s.s.l.M__getitem__(Int(i)) if err != nil { if s.s.firstErr == nil { s.s.firstErr = err } return } - elemJ, err := s.s.l.M__getitem__(Int(j)) + itemJ, err := s.s.l.M__getitem__(Int(j)) if err != nil { if s.s.firstErr == nil { s.s.firstErr = err } return } - _, err = s.s.l.M__setitem__(Int(i), elemJ) + _, err = s.s.l.M__setitem__(Int(i), itemJ) if err != nil { if s.s.firstErr == nil { s.s.firstErr = err } } - _, err = s.s.l.M__setitem__(Int(j), elemI) + _, err = s.s.l.M__setitem__(Int(j), itemI) if err != nil { if s.s.firstErr == nil { s.s.firstErr = err @@ -404,14 +395,14 @@ func (s ptrSortable) Swap(i, j int) { } func (s ptrSortable) Less(i, j int) bool { - elemI, err := s.s.l.M__getitem__(Int(i)) + itemI, err := s.s.l.M__getitem__(Int(i)) if err != nil { if s.s.firstErr == nil { s.s.firstErr = err } return false } - elemJ, err := s.s.l.M__getitem__(Int(j)) + itemJ, err := s.s.l.M__getitem__(Int(j)) if err != nil { if s.s.firstErr == nil { s.s.firstErr = err @@ -420,31 +411,34 @@ func (s ptrSortable) Less(i, j int) bool { } if s.s.keyFunc != None { - elemI, err = Call(s.s.keyFunc, Tuple{elemI}, nil) + itemI, err = Call(s.s.keyFunc, Tuple{itemI}, nil) if err != nil { if s.s.firstErr == nil { s.s.firstErr = err } + return false } - elemJ, err = Call(s.s.keyFunc, Tuple{elemJ}, nil) + itemJ, err = Call(s.s.keyFunc, Tuple{itemJ}, nil) if err != nil { if s.s.firstErr == nil { s.s.firstErr = err } + return false } } var cmpResult Object if s.s.reverse { - cmpResult, err = Lt(elemJ, elemI) + cmpResult, err = Lt(itemJ, itemI) } else { - cmpResult, err = Lt(elemI, elemJ) + cmpResult, err = Lt(itemI, itemJ) } if err != nil { if s.s.firstErr == nil { s.s.firstErr = err } + return false } if boolResult, ok := cmpResult.(Bool); ok { @@ -454,12 +448,22 @@ func (s ptrSortable) Less(i, j int) bool { return false } -func SortInPlace(l *List, keyFunc Object, reverse Object) error { - switch keyFunc.(type) { - case NoneType, I__call__: - default: - return ExceptionNewf(TypeError, "'%s' object is not callable", keyFunc.Type().Name) +// SortInPlace sorts the given List in place using a stable sort. +// kwargs can have the keys "key" and "reverse". +func SortInPlace(l *List, kwargs StringDict, funcName string) error { + var keyFunc Object + var reverse Object + err := ParseTupleAndKeywords(nil, kwargs, "|$OO:"+funcName, []string{"key", "reverse"}, &keyFunc, &reverse) + if err != nil { + return err + } + if keyFunc == nil { + keyFunc = None + } + if reverse == nil { + reverse = False } + // FIXME: requires the same bool-check like CPython (or better "|$Op" that doesn't panic on nil). s := ptrSortable{&sortable{l, keyFunc, ObjectIsTrue(reverse), nil}} sort.Stable(s) return s.s.firstErr From d31767d924816d4664f24c4856575dca730a3708 Mon Sep 17 00:00:00 2001 From: Tim S Date: Sun, 15 Sep 2019 15:03:30 +0200 Subject: [PATCH 03/10] add tests --- builtin/tests/sorting.py | 55 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 builtin/tests/sorting.py diff --git a/builtin/tests/sorting.py b/builtin/tests/sorting.py new file mode 100644 index 00000000..24e0619c --- /dev/null +++ b/builtin/tests/sorting.py @@ -0,0 +1,55 @@ +# Copyright 2019 The go-python Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +l = [] +l2 = sorted(l) +assert l == l2 +assert not l is l2 +assert sorted([5, 2, 3, 1, 4]) == [1, 2, 3, 4, 5] +a = [5, 2, 3, 1, 4] +assert a.sort() == None +assert a == [1, 2, 3, 4, 5] +assert sorted({"1": "D", "2": "B", "3": "B", "5": "E", "4": "A"}) == ["1", "2", "3", "4", "5"] + +kwargs = {"key": lambda l: l&1+l, "reverse": True} +l = list(range(10)) +l.sort(**kwargs) +assert l == sorted(range(10), **kwargs) == [8, 9, 6, 4, 5, 2, 0, 1, 3, 7] + +assert sorted([1, 2, 1.1], reverse=1) == [2, 1.1, 1] + +try: + sorted() +except TypeError: + pass +else: + assert False + +try: + sorted([], 1) +except TypeError: + pass +else: + assert False + +try: + sorted(1) +except TypeError: + pass +else: + assert False + +try: + sorted(None) +except TypeError: + pass +else: + assert False + +try: + sorted([1, 2], key=1) +except TypeError: + pass +else: + assert False \ No newline at end of file From cf32df75566dece84ed0138755828f5248a2888c Mon Sep 17 00:00:00 2001 From: Tim S Date: Sun, 15 Sep 2019 15:30:00 +0200 Subject: [PATCH 04/10] new try --- builtin/tests/sorting.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/builtin/tests/sorting.py b/builtin/tests/sorting.py index 24e0619c..398e06df 100644 --- a/builtin/tests/sorting.py +++ b/builtin/tests/sorting.py @@ -2,6 +2,7 @@ # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. +doc = "sort: order" l = [] l2 = sorted(l) assert l == l2 @@ -10,15 +11,21 @@ a = [5, 2, 3, 1, 4] assert a.sort() == None assert a == [1, 2, 3, 4, 5] + +doc = "sort: dict-type as iterable" assert sorted({"1": "D", "2": "B", "3": "B", "5": "E", "4": "A"}) == ["1", "2", "3", "4", "5"] + +doc = "sort: complex arguments" kwargs = {"key": lambda l: l&1+l, "reverse": True} l = list(range(10)) l.sort(**kwargs) assert l == sorted(range(10), **kwargs) == [8, 9, 6, 4, 5, 2, 0, 1, 3, 7] +doc = "sort: different types that are comparable" assert sorted([1, 2, 1.1], reverse=1) == [2, 1.1, 1] +doc = "sort: call syntax and types" try: sorted() except TypeError: @@ -52,4 +59,6 @@ except TypeError: pass else: - assert False \ No newline at end of file + assert False + +doc = "finished" \ No newline at end of file From f411862f3a8545ecb0a9b9e75828d367e0a8c680 Mon Sep 17 00:00:00 2001 From: Tim S Date: Sat, 28 Sep 2019 11:27:49 +0200 Subject: [PATCH 05/10] Add tests for `list.sort` --- py/tests/list.py | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/py/tests/list.py b/py/tests/list.py index 4fb1066c..0e3dfae7 100644 --- a/py/tests/list.py +++ b/py/tests/list.py @@ -1,4 +1,4 @@ -# Copyright 2018 The go-python Authors. All rights reserved. +# Copyright 2019 The go-python Authors. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. @@ -39,4 +39,37 @@ assert a * 0 == [] assert a * -1 == [] +doc="sort" +a = [3, 1.1, 1, 2] +s1 = list(a) +s1.sort() +assert s1 == [1, 1.1, 2, 3] +s1.sort() # sort a sorted list +assert s1 == [1, 1.1, 2, 3] +s2 = list(a) +s2.sort(reverse=True) +assert s2 == [3, 2, 1.1, 1] +s2.sort() # sort a reversed list +assert s2 == [1, 1.1, 2, 3] +s3 = list(a) +s3.sort(key=lambda l: l+1) # test lambda key +assert s3 == [1, 1.1, 2, 3] +s4 = [2.0, 2, 1, 1.0] +s4.sort(key=lambda l: 0) # test stability +assert s4 == [2.0, 2, 1, 1.0] +assert [type(t) for t in s4] == [float, int, int, float] +s4 = [2.0, 2, 1, 1.0] +s4.sort() # test stability +assert s4 == [1, 1.0, 2.0, 2] +assert [type(t) for t in s4] == [int, float, float, int] +s5 = [2.0, "abc"] +assertRaises(TypeError, lambda: s5.sort()) +s5 = [] +s5.sort() +assert s5 == [] +s5 = [0] +s5.sort() +assert s5 == [0] +assertRaises(TypeError, lambda: s5.sort(key=1)) + doc="finished" From a432c5463fa4270940915a06ac784952784848c7 Mon Sep 17 00:00:00 2001 From: Tim S Date: Sat, 28 Sep 2019 11:49:04 +0200 Subject: [PATCH 06/10] Update list.py --- py/tests/list.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/py/tests/list.py b/py/tests/list.py index 0e3dfae7..9b3c1f53 100644 --- a/py/tests/list.py +++ b/py/tests/list.py @@ -70,6 +70,8 @@ s5 = [0] s5.sort() assert s5 == [0] +s5 = [0, 1] +# Sorting a list of len >= 2 with uncallable key must fail on all Python implementations. assertRaises(TypeError, lambda: s5.sort(key=1)) doc="finished" From 6b844622de682397e43725e46058b00165082b86 Mon Sep 17 00:00:00 2001 From: Tim S Date: Sat, 28 Sep 2019 14:07:06 +0200 Subject: [PATCH 07/10] support `list.sort([], **kwargs)` --- py/list.go | 27 ++++++++++++++++++++++----- py/tests/list.py | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/py/list.go b/py/list.go index 1c575f2a..daf16fbe 100644 --- a/py/list.go +++ b/py/list.go @@ -18,6 +18,7 @@ type List struct { } func init() { + // FIXME: all methods should be callable using list.method([], *args, **kwargs) or [].method(*args, **kwargs) ListType.Dict["append"] = MustNewMethod("append", func(self Object, args Tuple) (Object, error) { listSelf := self.(*List) if len(args) != 1 { @@ -40,12 +41,28 @@ func init() { ListType.Dict["sort"] = MustNewMethod("sort", func(self Object, args Tuple, kwargs StringDict) (Object, error) { const funcName = "sort" - err := UnpackTuple(args, nil, funcName, 0, 0) - if err != nil { - return nil, err + var l *List + if self.Type() == NoneTypeType { + // method called using `list.sort([], **kwargs)` + var o Object + err := UnpackTuple(args, nil, funcName, 1, 1, &o) + if err != nil { + return nil, err + } + var ok bool + l, ok = o.(*List) + if !ok { + return nil, ExceptionNewf(TypeError, "descriptor 'sort' requires a 'list' object but received a '%s'", args[0].Type()) + } + } else { + // method called using `[].sort(**kargs)` + err := UnpackTuple(args, nil, funcName, 0, 0) + if err != nil { + return nil, err + } + l = self.(*List) } - listSelf := self.(*List) - err = SortInPlace(listSelf, kwargs, funcName) + err := SortInPlace(l, kwargs, funcName) if err != nil { return nil, err } diff --git a/py/tests/list.py b/py/tests/list.py index 9b3c1f53..3e8468b0 100644 --- a/py/tests/list.py +++ b/py/tests/list.py @@ -40,6 +40,7 @@ assert a * -1 == [] doc="sort" +# [].sort a = [3, 1.1, 1, 2] s1 = list(a) s1.sort() @@ -74,4 +75,40 @@ # Sorting a list of len >= 2 with uncallable key must fail on all Python implementations. assertRaises(TypeError, lambda: s5.sort(key=1)) +# list.sort([]) +a = [3, 1.1, 1, 2] +s1 = list(a) +assert list.sort(s1) is None +assert s1 == [1, 1.1, 2, 3] +assert list.sort(s1) is None # sort a sorted list +assert s1 == [1, 1.1, 2, 3] +s2 = list(a) +list.sort(s2, reverse=True) +assert s2 == [3, 2, 1.1, 1] +list.sort(s2) # sort a reversed list +assert s2 == [1, 1.1, 2, 3] +s3 = list(a) +list.sort(s3, key=lambda l: l+1) # test lambda key +assert s3 == [1, 1.1, 2, 3] +s4 = [2.0, 2, 1, 1.0] +list.sort(s4, key=lambda l: 0) # test stability +assert s4 == [2.0, 2, 1, 1.0] +assert [type(t) for t in s4] == [float, int, int, float] +s4 = [2.0, 2, 1, 1.0] +list.sort(s4) # test stability +assert s4 == [1, 1.0, 2.0, 2] +assert [type(t) for t in s4] == [int, float, float, int] +s5 = [2.0, "abc"] +assertRaises(TypeError, lambda: list.sort(s5)) +s5 = [] +list.sort(s5) +assert s5 == [] +s5 = [0] +list.sort(s5) +assert s5 == [0] +s5 = [0, 1] +# Sorting a list of len >= 2 with uncallable key must fail on all Python implementations. +assertRaises(TypeError, lambda: list.sort(s5, key=1)) +assertRaises(TypeError, lambda: list.sort(1)) + doc="finished" From af6732df78556e7f94be6b58a38f5c27d8fa762c Mon Sep 17 00:00:00 2001 From: Tim S Date: Sat, 28 Sep 2019 14:09:06 +0200 Subject: [PATCH 08/10] Update list.go --- py/list.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/list.go b/py/list.go index daf16fbe..ae4878eb 100644 --- a/py/list.go +++ b/py/list.go @@ -52,7 +52,7 @@ func init() { var ok bool l, ok = o.(*List) if !ok { - return nil, ExceptionNewf(TypeError, "descriptor 'sort' requires a 'list' object but received a '%s'", args[0].Type()) + return nil, ExceptionNewf(TypeError, "descriptor 'sort' requires a 'list' object but received a '%s'", o.Type()) } } else { // method called using `[].sort(**kargs)` From c8d35a9130f3b828c36e3d999de14d36aabf2e1a Mon Sep 17 00:00:00 2001 From: Tim S Date: Sat, 28 Sep 2019 17:24:09 +0200 Subject: [PATCH 09/10] better NoneType comparison --- py/list.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/list.go b/py/list.go index ae4878eb..eee7bf3e 100644 --- a/py/list.go +++ b/py/list.go @@ -42,7 +42,7 @@ func init() { ListType.Dict["sort"] = MustNewMethod("sort", func(self Object, args Tuple, kwargs StringDict) (Object, error) { const funcName = "sort" var l *List - if self.Type() == NoneTypeType { + if self == None { // method called using `list.sort([], **kwargs)` var o Object err := UnpackTuple(args, nil, funcName, 1, 1, &o) From 5f7a289cb2581e35541b49c7b80d03c007462de7 Mon Sep 17 00:00:00 2001 From: Tim S Date: Sun, 29 Sep 2019 10:09:02 +0200 Subject: [PATCH 10/10] put tests for `sorted` in `builtin.py` --- builtin/tests/builtin.py | 46 ++++++++++++++++++++++++++++- builtin/tests/sorting.py | 64 ---------------------------------------- 2 files changed, 45 insertions(+), 65 deletions(-) delete mode 100644 builtin/tests/sorting.py diff --git a/builtin/tests/builtin.py b/builtin/tests/builtin.py index 88cc38c2..9d0bff95 100644 --- a/builtin/tests/builtin.py +++ b/builtin/tests/builtin.py @@ -1,4 +1,4 @@ -# Copyright 2018 The go-python Authors. All rights reserved. +# Copyright 2019 The go-python Authors. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. @@ -329,6 +329,50 @@ class C: pass finally: assert ok +doc="sorted" +a = [3, 1.1, 1, 2] +assert sorted(a) == [1, 1.1, 2, 3] +assert sorted(sorted(a)) == [1, 1.1, 2, 3] +assert sorted(a, reverse=True) == [3, 2, 1.1, 1] +assert sorted(a, key=lambda l: l+1) == [1, 1.1, 2, 3] +s = [2.0, 2, 1, 1.0] +assert sorted(s, key=lambda l: 0) == [2.0, 2, 1, 1.0] +assert [type(t) for t in sorted(s, key=lambda l: 0)] == [float, int, int, float] +assert sorted(s) == [1, 1.0, 2.0, 2] +assert [type(t) for t in sorted(s)] == [int, float, float, int] + +try: + sorted([2.0, "abc"]) +except TypeError: + pass +else: + assert False + +assert sorted([]) == [] +assert sorted([0]) == [0] +s = [0, 1] +try: + # Sorting a list of len >= 2 with uncallable key must fail on all Python implementations. + sorted(s, key=1) +except TypeError: + pass +else: + assert False + +try: + sorted(1) +except TypeError: + pass +else: + assert False + +try: + sorted() +except TypeError: + pass +else: + assert False + doc="sum" assert sum([1,2,3]) == 6 assert sum([1,2,3], 3) == 9 diff --git a/builtin/tests/sorting.py b/builtin/tests/sorting.py deleted file mode 100644 index 398e06df..00000000 --- a/builtin/tests/sorting.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright 2019 The go-python Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -doc = "sort: order" -l = [] -l2 = sorted(l) -assert l == l2 -assert not l is l2 -assert sorted([5, 2, 3, 1, 4]) == [1, 2, 3, 4, 5] -a = [5, 2, 3, 1, 4] -assert a.sort() == None -assert a == [1, 2, 3, 4, 5] - -doc = "sort: dict-type as iterable" -assert sorted({"1": "D", "2": "B", "3": "B", "5": "E", "4": "A"}) == ["1", "2", "3", "4", "5"] - - -doc = "sort: complex arguments" -kwargs = {"key": lambda l: l&1+l, "reverse": True} -l = list(range(10)) -l.sort(**kwargs) -assert l == sorted(range(10), **kwargs) == [8, 9, 6, 4, 5, 2, 0, 1, 3, 7] - -doc = "sort: different types that are comparable" -assert sorted([1, 2, 1.1], reverse=1) == [2, 1.1, 1] - -doc = "sort: call syntax and types" -try: - sorted() -except TypeError: - pass -else: - assert False - -try: - sorted([], 1) -except TypeError: - pass -else: - assert False - -try: - sorted(1) -except TypeError: - pass -else: - assert False - -try: - sorted(None) -except TypeError: - pass -else: - assert False - -try: - sorted([1, 2], key=1) -except TypeError: - pass -else: - assert False - -doc = "finished" \ No newline at end of file