Skip to content

Commit e5cfb7d

Browse files
committed
set builtin: add difference and difference_update builtins
- added basic unittest
1 parent d960ae3 commit e5cfb7d

File tree

4 files changed

+109
-1
lines changed

4 files changed

+109
-1
lines changed

graalpython/com.oracle.graal.python.test/src/tests/test_set.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,24 @@
3939
# Iterating by Sequence Index
4040

4141

42+
def assert_raises(err, fn, *args, **kwargs):
43+
raised = False
44+
try:
45+
fn(*args, **kwargs)
46+
except err:
47+
raised = True
48+
assert raised
49+
50+
51+
class PassThru(Exception):
52+
pass
53+
54+
55+
def check_pass_thru():
56+
raise PassThru
57+
yield 1
58+
59+
4260
def test_set_or():
4361
s1 = {1, 2, 3}
4462
s2 = {4, 5, 6}
@@ -65,3 +83,64 @@ def test_set_remove():
6583
def test_set_le():
6684
assert set("a") <= set("abc")
6785

86+
87+
def test_difference():
88+
word = 'simsalabim'
89+
otherword = 'madagascar'
90+
letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
91+
s = set(word)
92+
d = dict.fromkeys(word)
93+
94+
i = s.difference(otherword)
95+
for c in letters:
96+
assert (c in i) == (c in d and c not in otherword)
97+
98+
assert s == set(word)
99+
assert type(i) == set
100+
assert_raises(PassThru, s.difference, check_pass_thru())
101+
assert_raises(TypeError, s.difference, [[]])
102+
103+
for C in set, frozenset, dict.fromkeys, str, list, tuple:
104+
assert set('abcba').difference(C('cdc')) == set('ab')
105+
assert set('abcba').difference(C('efgfe')) == set('abc')
106+
assert set('abcba').difference(C('ccb')) == set('a')
107+
assert set('abcba').difference(C('ef')) == set('abc')
108+
assert set('abcba').difference() == set('abc')
109+
assert set('abcba').difference(C('a'), C('b')) == set('c')
110+
111+
112+
def test_difference_update():
113+
word = 'simsalabim'
114+
otherword = 'madagascar'
115+
s = set(word)
116+
117+
retval = s.difference_update(otherword)
118+
assert retval == None
119+
120+
for c in (word + otherword):
121+
if c in word and c not in otherword:
122+
assert c in s
123+
else:
124+
assert c not in s
125+
126+
assert_raises(PassThru, s.difference_update, check_pass_thru())
127+
assert_raises(TypeError, s.difference_update, [[]])
128+
# assert_raises(TypeError, s.symmetric_difference_update, [[]])
129+
130+
for p, q in (('cdc', 'ab'), ('efgfe', 'abc'), ('ccb', 'a'), ('ef', 'abc')):
131+
for C in set, frozenset, dict.fromkeys, str, list, tuple:
132+
s = set('abcba')
133+
assert s.difference_update(C(p)) == None
134+
assert s == set(q)
135+
136+
s = set('abcdefghih')
137+
s.difference_update()
138+
assert s == set('abcdefghih')
139+
140+
s = set('abcdefghih')
141+
s.difference_update(C('aba'))
142+
assert s == set('cdefghih')
143+
144+
s = set('abcdefghih')
145+
s.difference_update(C('cdc'), C('aba'))
146+
assert s == set('efghih')

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/PSet.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,4 @@ public void clear() {
7171
public void setDictStorage(HashingStorage newStorage) {
7272
throw new RuntimeException("set has fixed storage");
7373
}
74-
7574
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/set/SetNodes.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040

4141
import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError;
4242

43+
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
4344
import com.oracle.graal.python.builtins.objects.PNone;
4445
import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.SetItemNode;
4546
import com.oracle.graal.python.builtins.objects.type.PythonClass;
@@ -67,6 +68,10 @@ public abstract static class ConstructSetNode extends PBaseNode {
6768

6869
public abstract PSet execute(Object cls, Object value);
6970

71+
public final PSet executeWith(Object value) {
72+
return this.execute(lookupClass(PythonBuiltinClassType.PSet), value);
73+
}
74+
7075
@Specialization
7176
@TruffleBoundary
7277
public PSet setString(PythonClass cls, String arg) {

graalpython/lib-graalpython/set.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3636
# SOFTWARE.
3737

38+
3839
def update(self, *others):
3940
for seq in others:
4041
if not hasattr(seq, '__iter__'):
@@ -44,6 +45,26 @@ def update(self, *others):
4445
self.add(el)
4546

4647

48+
def difference(self, *others):
49+
diff_set = self
50+
for seq in others:
51+
diff_set = set(el for el in diff_set if el not in set(seq))
52+
return diff_set
53+
54+
55+
def difference_update(self, *others):
56+
for seq in others:
57+
other_set = set(seq)
58+
self_copy = set(self)
59+
for el in self_copy:
60+
if el in other_set:
61+
self.remove(el)
62+
63+
64+
def frozenset_difference(self, *others):
65+
return frozenset(difference(self, *others))
66+
67+
4768
def set_repr(self):
4869
if len(self):
4970
s = "{"
@@ -83,7 +104,11 @@ def frozenset_copy(self):
83104

84105

85106
set.update = update
107+
set.difference = difference
108+
set.difference_update = difference_update
86109
set.__repr__ = set_repr
87110
set.copy = set_copy
111+
112+
frozenset.difference = frozenset_difference
88113
frozenset.__repr__ = frozenset_repr
89114
frozenset.copy = frozenset_copy

0 commit comments

Comments
 (0)