Merge pull request #73 from fragmuffin/feature/matrix-err-messages

Matrix validation robustness
This commit is contained in:
Jeremy Wright
2019-01-05 17:02:58 -05:00
committed by GitHub
2 changed files with 37 additions and 21 deletions

View File

@ -215,20 +215,21 @@ class Matrix:
self.wrapped = gp_Trsf()
elif isinstance(matrix, gp_Trsf):
self.wrapped = matrix
elif isinstance(matrix, list):
elif isinstance(matrix, (list, tuple)):
# Validate matrix size & 4x4 last row value
valid_sizes = all(
(isinstance(row, (list, tuple)) and (len(row) == 4))
for row in matrix
) and len(matrix) in (3, 4)
if not valid_sizes:
raise TypeError("Matrix constructor requires 2d list of 4x3 or 4x4, but got: {!r}".format(matrix))
elif (len(matrix) == 4) and (tuple(matrix[3]) != (0,0,0,1)):
raise ValueError("Expected the last row to be [0,0,0,1], but got: {!r}".format(matrix[3]))
# Assign values to matrix
self.wrapped = gp_Trsf()
if len(matrix) == 3:
flattened = [e for row in matrix for e in row]
flattened = [e for row in matrix[:3] for e in row]
self.wrapped.SetValues(*flattened)
elif len(matrix) == 4:
# Only use first 3 rows - the last must be [0, 0, 0, 1].
lastRow = matrix[3]
if lastRow != [0., 0., 0., 1.]:
raise ValueError("Expected the last row to be [0,0,0,1], but got: {}".format(lastRow))
flattened = [e for row in matrix[0:3] for e in row]
self.wrapped.SetValues(*flattened)
else:
raise TypeError("Matrix constructor requires list of length 12 or 16")
else:
raise TypeError(
"Invalid param to matrix constructor: {}".format(matrix))
@ -282,18 +283,18 @@ class Matrix:
and column parameters start at zero, which is consistent with most
python libraries, but is counter to gp_Trsf(), which is 1-indexed.
"""
if len(rc) != 2:
if not isinstance(rc, tuple) or (len(rc) != 2):
raise IndexError("Matrix subscript must provide (row, column)")
r, c = rc[0], rc[1]
if r >= 0 and r < 4 and c >= 0 and c < 4:
(r, c) = rc
if (0 <= r <= 3) and (0 <= c <= 3):
if r < 3:
return self.wrapped.Value(r+1,c+1)
return self.wrapped.Value(r + 1, c + 1)
else:
# gp_Trsf doesn't provide access to the 4th row because it has
# an implied value as below:
return [0., 0., 0., 1.][c]
else:
raise IndexError("Out of bounds access into 4x4 matrix: {}".format(rc))
raise IndexError("Out of bounds access into 4x4 matrix: {!r}".format(rc))
class Plane(object):

View File

@ -166,14 +166,19 @@ class TestCadObjects(BaseTest):
[0., 1., 0., 2.],
[0., 0., 1., 3.],
[0., 0., 0., 1.]]
vals4x4_tuple = tuple(tuple(r) for r in vals4x4)
# test constructor with 16-value input
m = Matrix(vals4x4)
self.assertEqual(vals4x4, matrix_vals(m))
m = Matrix(vals4x4_tuple)
self.assertEqual(vals4x4, matrix_vals(m))
# test constructor with 12-value input (the last 4 are an implied
# [0,0,0,1])
m = Matrix(vals4x4[0:12])
m = Matrix(vals4x4[:3])
self.assertEqual(vals4x4, matrix_vals(m))
m = Matrix(vals4x4_tuple[:3])
self.assertEqual(vals4x4, matrix_vals(m))
# Test 16-value input with invalid values for the last 4
@ -184,14 +189,24 @@ class TestCadObjects(BaseTest):
with self.assertRaises(ValueError):
Matrix(invalid)
# Test input with invalid size
# Test input with invalid size / nested types
with self.assertRaises(TypeError):
Matrix([[1, 2, 3, 4], [1, 2, 3], [1, 2, 3, 4]])
with self.assertRaises(TypeError):
Matrix([1,2,3])
# Invalid sub-type
with self.assertRaises(TypeError):
Matrix([[1, 2, 3, 4], 'abc', [1, 2, 3, 4]])
# test out-of-bounds access
m = Matrix()
with self.assertRaises(IndexError):
m[5, 5]
m[0, 4]
with self.assertRaises(IndexError):
m[4, 0]
with self.assertRaises(IndexError):
m['ab']
def testTranslate(self):