Skip to content

Commit

Permalink
Merge pull request beeware#961 from whydoubt/unpack_iterable
Browse files Browse the repository at this point in the history
Extended Iterable Unpacking
  • Loading branch information
freakboy3742 authored Aug 19, 2019
2 parents 235e838 + f10acac commit 92ec688
Show file tree
Hide file tree
Showing 9 changed files with 306 additions and 66 deletions.
21 changes: 21 additions & 0 deletions python/common/org/Python.java
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,27 @@ public static java.util.Map<java.lang.String, org.python.Object> addToKwargs(jav
return kwargs;
}

/**
* Check that the number of targets given for unpacking matches the number of provided values
*/
public static void checkUnpackValues(org.python.types.List values, int tcount, int scount) {
int values_count = (int) ((org.python.types.Int) values.__len__()).value;
int min_target_count = tcount - scount;

if (scount == 0 && min_target_count < values_count) {
throw new org.python.exceptions.ValueError("too many values to unpack (expected " + min_target_count + ")");
} else if (min_target_count > values_count) {
if (org.Python.VERSION < 0x03050000) {
java.lang.String num_values = (values_count == 1) ? "1 value" : ("" + values_count + " values");
throw new org.python.exceptions.ValueError("need more than " + num_values + " to unpack");
} else {
java.lang.String expected_num = ((scount == 1) ? "expected at least " : "expected ") + min_target_count;
java.lang.String got_num = "got " + values_count;
throw new org.python.exceptions.ValueError("not enough values to unpack (" + expected_num + ", " + got_num + ")");
}
}
}

@org.python.Method(
__doc__ = "__import__(name, globals=None, locals=None, fromlist=(), level=0) -> module" +
"\n" +
Expand Down
2 changes: 1 addition & 1 deletion tests/benchmarks/unpack_sequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,10 @@ def do_unpacking(iterations, to_unpack):
a, b, c, d, e, f, g, h, i, j = to_unpack
a, b, c, d, e, f, g, h, i, j = to_unpack
a, b, c, d, e, f, g, h, i, j = to_unpack
"""
a, b, c, d, e, f, g, h, i, j = to_unpack
a, b, c, d, e, f, g, h, i, j = to_unpack
a, b, c, d, e, f, g, h, i, j = to_unpack
"""
a, b, c, d, e, f, g, h, i, j = to_unpack
a, b, c, d, e, f, g, h, i, j = to_unpack
a, b, c, d, e, f, g, h, i, j = to_unpack
Expand Down
8 changes: 8 additions & 0 deletions tests/datatypes/test_bytes.py
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,14 @@ def test_too_many_arguments(self):
print(err)
""")

def test_long_literal(self):
self.assertCodeExecution("""
b = b'''00000000001111111111222222222233333333334444444444
55555555556666666666777777777888888888899999999990000000000
11111111112222222222'''
print(b)
""")


class UnaryBytesOperationTests(UnaryOperationTestCase, TranspileTestCase):
data_type = 'bytes'
Expand Down
168 changes: 135 additions & 33 deletions tests/structures/test_assignment.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,36 @@ def test_list_assignment(self):
print(z)
""")

@expectedFailure
def test_bad_list_assignment(self):
def test_list_assignment_nested(self):
self.assertCodeExecution("""
[x, [y, z]] = 1, (2, 3)
print(x)
print(y)
print(z)
""")

def test_list_assignment_starred_0(self):
self.assertCodeExecution("""
[*x, y, z] = range(2)
print(x)
print(y)
print(z)
""")

def test_list_assignment_starred_1(self):
self.assertCodeExecution("""
[*x, y] = range(2)
print(x)
print(y)
""")

def test_list_assignment_starred_2(self):
self.assertCodeExecution("""
[*x] = range(2)
print(x)
""")

def test_bad_list_assignment_too_few(self):
self.assertCodeExecution("""
try:
[x, y, z, a] = range(3)
Expand All @@ -86,21 +114,27 @@ def test_bad_list_assignment(self):
print("Got a ValueError:", e)
""")

def test_bad_list_assignment_raises_StopIteration(self):
"""
This test is a copy of test_bad_list_assignment.
Raising ValueError as a result of a bad unpacking is not currently implemented;
this test should be deleted when it is.
"""
def test_bad_list_assignment_too_many(self):
self.assertCodeExecution("""
try:
[x, y, z, a] = range(3)
[x, y, z] = range(4)
print(x)
print(y)
print(z)
except ValueError as e:
print("Got a ValueError:", e)
""")

def test_bad_list_assignment_starred(self):
self.assertCodeExecution("""
try:
[x, *y, z, a] = range(2)
print(x)
print(y)
print(z)
print(a)
except (StopIteration, ValueError) as e:
print("ValueError: not enough values to unpack (expected 4, got 3)")
except ValueError as e:
print("Got a ValueError:", e)
""")

def test_tuple_assignment(self):
Expand All @@ -111,8 +145,36 @@ def test_tuple_assignment(self):
print(z)
""")

@expectedFailure
def test_bad_tuple_assignment(self):
def test_tuple_assignment_nested(self):
self.assertCodeExecution("""
(x, (y, z)) = 1, (2, 3)
print(x)
print(y)
print(z)
""")

def test_tuple_assignment_starred_0(self):
self.assertCodeExecution("""
(*x, y, z) = range(2)
print(x)
print(y)
print(z)
""")

def test_tuple_assignment_starred_1(self):
self.assertCodeExecution("""
(*x, y) = range(2)
print(x)
print(y)
""")

def test_tuple_assignment_starred_2(self):
self.assertCodeExecution("""
(*x,) = range(2)
print(x)
""")

def test_bad_tuple_assignment_too_few(self):
self.assertCodeExecution("""
try:
(x, y, z, a) = range(3)
Expand All @@ -124,21 +186,27 @@ def test_bad_tuple_assignment(self):
print("Got a ValueError:", e)
""")

def test_bad_tuple_assignment_raises_StopIteration(self):
"""
This test is a copy of test_bad_tuple_assignment.
Raising ValueError as a result of a bad unpacking is not currently implemented;
this test should be deleted when it is.
"""
def test_bad_tuple_assignment_too_many(self):
self.assertCodeExecution("""
try:
(x, y, z, a) = range(3)
(x, y, z) = range(4)
print(x)
print(y)
print(z)
except ValueError as e:
print("Got a ValueError:", e)
""")

def test_bad_tuple_assignment_starred(self):
self.assertCodeExecution("""
try:
(x, *y, z, a) = range(2)
print(x)
print(y)
print(z)
print(a)
except (StopIteration, ValueError) as e:
print("ValueError: not enough values to unpack (expected 4, got 3)")
except ValueError as e:
print("Got a ValueError:", e)
""")

def test_implied_tuple_assignment(self):
Expand All @@ -149,8 +217,36 @@ def test_implied_tuple_assignment(self):
print(z)
""")

@expectedFailure
def test_bad_implied_tuple_assignment(self):
def test_implied_tuple_assignment_nested(self):
self.assertCodeExecution("""
x, (y, z) = 1, (2, 3)
print(x)
print(y)
print(z)
""")

def test_implied_tuple_assignment_starred_0(self):
self.assertCodeExecution("""
*x, y, z = range(2)
print(x)
print(y)
print(z)
""")

def test_implied_tuple_assignment_starred_1(self):
self.assertCodeExecution("""
*x, y = range(2)
print(x)
print(y)
""")

def test_implied_tuple_assignment_starred_2(self):
self.assertCodeExecution("""
*x, = range(2)
print(x)
""")

def test_bad_implied_tuple_assignment_too_few(self):
self.assertCodeExecution("""
try:
x, y, z, a = range(3)
Expand All @@ -162,21 +258,27 @@ def test_bad_implied_tuple_assignment(self):
print("Got a ValueError:", e)
""")

def test_bad_implied_tuple_assignment_raises_StopIteration(self):
"""
This test is a copy of test_bad_implied_tuple_assignment.
Raising ValueError as a result of a bad unpacking is not currently implemented;
this test should be deleted when it is.
"""
def test_bad_implied_tuple_assignment_too_many(self):
self.assertCodeExecution("""
try:
x, y, z, a = range(3)
x, y, z = range(4)
print(x)
print(y)
print(z)
except ValueError as e:
print("Got a ValueError:", e)
""")

def test_bad_implied_tuple_assignment_starred(self):
self.assertCodeExecution("""
try:
x, *y, z, a = range(2)
print(x)
print(y)
print(z)
print(a)
except (StopIteration, ValueError) as e:
print("ValueError: not enough values to unpack (expected 4, got 3)")
except ValueError as e:
print("Got a ValueError:", e)
""")

def test_increment_assignment(self):
Expand Down
4 changes: 2 additions & 2 deletions voc/java/opcodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -463,11 +463,11 @@ def __arg_repr__(self):

@classmethod
def read_extra(cls, reader, dump=None):
const = reader.read_u1()
const = reader.read_s1()
return cls(const)

def write_extra(self, writer):
writer.write_u1(self.const)
writer.write_s1(self.const)

@property
def produce_count(self):
Expand Down
Loading

0 comments on commit 92ec688

Please sign in to comment.