Skip to content

Commit f77717e

Browse files
committed
[GR-24387] Fix: filter should return lazy iterable.
PullRequest: graalpython/1067
2 parents 88fbf07 + 885899e commit f77717e

File tree

3 files changed

+87
-10
lines changed

3 files changed

+87
-10
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved.
2+
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3+
#
4+
# The Universal Permissive License (UPL), Version 1.0
5+
#
6+
# Subject to the condition set forth below, permission is hereby granted to any
7+
# person obtaining a copy of this software, associated documentation and/or
8+
# data (collectively the "Software"), free of charge and under any and all
9+
# copyright rights in the Software, and any and all patent rights owned or
10+
# freely licensable by each licensor hereunder covering either (i) the
11+
# unmodified Software as contributed to or provided by such licensor, or (ii)
12+
# the Larger Works (as defined below), to deal in both
13+
#
14+
# (a) the Software, and
15+
#
16+
# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
17+
# one is included with the Software each a "Larger Work" to which the Software
18+
# is contributed by such licensors),
19+
#
20+
# without restriction, including without limitation the rights to copy, create
21+
# derivative works of, display, perform, and distribute the Software and make,
22+
# use, sell, offer for sale, import, export, have made, and have sold the
23+
# Software and the Larger Work(s), and to sublicense the foregoing rights on
24+
# either these or other terms.
25+
#
26+
# This license is subject to the following condition:
27+
#
28+
# The above copyright notice and either this complete permission notice or at a
29+
# minimum a reference to the UPL must be included in all copies or substantial
30+
# portions of the Software.
31+
#
32+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38+
# SOFTWARE.
39+
40+
41+
def assert_iterable_eq(iterable, list):
42+
list_idx = 0
43+
for item in iterable:
44+
assert list_idx < len(list), "iterable is too long"
45+
assert item == list[list_idx], "difference at index " + str(list_idx) + ", got: " + repr(item)
46+
list_idx += 1
47+
assert list_idx == len(list), "iterator does not have enough items"
48+
49+
50+
def test_filter():
51+
assert_iterable_eq(filter(lambda a: a >= 3 and a < 5, [1,2,3,4,5]), [3,4])
52+
assert_iterable_eq(filter(lambda a: True, [1,2,3]), [1,2,3])
53+
assert_iterable_eq(filter(lambda a: False, [1,2,3]), [])
54+
it = filter(lambda a: False, [1,2,3])
55+
assert next(it, None) is None
56+
57+
58+
def test_filter_side_effect():
59+
shared = 0
60+
def fun(x):
61+
nonlocal shared
62+
shared = 42
63+
return True
64+
it = filter(fun, [1,2,3])
65+
assert shared == 0
66+
assert next(it) == 1
67+
assert shared == 42

graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_builtin.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*graalpython.lib-python.3.test.test_builtin.BuiltinTest.test_delattr
1010
*graalpython.lib-python.3.test.test_builtin.BuiltinTest.test_exec
1111
*graalpython.lib-python.3.test.test_builtin.BuiltinTest.test_exec_redirected
12+
*graalpython.lib-python.3.test.test_builtin.BuiltinTest.test_filter
1213
*graalpython.lib-python.3.test.test_builtin.BuiltinTest.test_hex
1314
*graalpython.lib-python.3.test.test_builtin.BuiltinTest.test_id
1415
*graalpython.lib-python.3.test.test_builtin.BuiltinTest.test_isinstance

graalpython/lib-graalpython/functions.py

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,16 +59,6 @@ def all(iterable):
5959
return True
6060

6161

62-
@__graalpython__.builtin
63-
def filter(func, iterable):
64-
result = []
65-
predicate = func if func is not None else lambda a: a
66-
for i in iterable:
67-
if predicate(i):
68-
result.append(i)
69-
return tuple(result)
70-
71-
7262
# This is re-defined later during bootstrap in classes.py
7363
def __build_class__(func, name, *bases, metaclass=None, **kwargs):
7464
"""
@@ -137,3 +127,22 @@ def input(prompt=None):
137127
else:
138128
break
139129
return "".join(result)
130+
131+
132+
class filter(object):
133+
def __init__(self, predicateOrNone, iterable):
134+
self.predicateOrNone = predicateOrNone
135+
self.iterable = iter(iterable)
136+
137+
def __iter__(self):
138+
return self
139+
140+
def __next__(self):
141+
while True:
142+
item = next(self.iterable)
143+
if self.predicateOrNone is None:
144+
if item:
145+
return item
146+
else:
147+
if self.predicateOrNone(item):
148+
return item

0 commit comments

Comments
 (0)