示例#1
0
 def test_raw_load_simple_ascii(self):
     ply_file = '\n'.join(
         [
             'ply',
             'format ascii 1.0',
             'comment made by Greg Turk',
             'comment this file is a cube',
             'element vertex 8',
             'property float x',
             'property float y',
             'property float z',
             'element face 6',
             'property list uchar int vertex_index',
             'element irregular_list 3',
             'property list uchar int vertex_index',
             'end_header',
             '0 0 0',
             '0 0 1',
             '0 1 1',
             '0 1 0',
             '1 0 0',
             '1 0 1',
             '1 1 1',
             '1 1 0',
             '4 0 1 2 3',
             '4 7 6 5 4',
             '4 0 4 5 1',
             '4 1 5 6 2',
             '4 2 6 7 3',
             '4 3 7 4 0',  # end of faces
             '4 0 1 2 3',
             '4 7 6 5 4',
             '3 4 5 1',
         ]
     )
     for line_ending in [None, '\n', '\r\n']:
         if line_ending is None:
             stream = StringIO(ply_file)
         else:
             byte_file = ply_file.encode('ascii')
             if line_ending == '\r\n':
                 byte_file = byte_file.replace(b'\n', b'\r\n')
             stream = BytesIO(byte_file)
         header, data = _load_ply_raw(stream)
         self.assertTrue(header.ascii)
         self.assertEqual(len(data), 3)
         self.assertTupleEqual(data['face'].shape, (6, 4))
         self.assertClose([0, 1, 2, 3], data['face'][0])
         self.assertClose([3, 7, 4, 0], data['face'][5])
         self.assertTupleEqual(data['vertex'].shape, (8, 3))
         irregular = data['irregular_list']
         self.assertEqual(len(irregular), 3)
         self.assertEqual(type(irregular), list)
         [x] = irregular[0]
         self.assertClose(x, [0, 1, 2, 3])
         [x] = irregular[1]
         self.assertClose(x, [7, 6, 5, 4])
         [x] = irregular[2]
         self.assertClose(x, [4, 5, 1])
示例#2
0
 def test_raw_load_simple_ascii(self):
     ply_file = "\n".join(
         [
             "ply",
             "format ascii 1.0",
             "comment made by Greg Turk",
             "comment this file is a cube",
             "element vertex 8",
             "property float x",
             "property float y",
             "property float z",
             "element face 6",
             "property list uchar int vertex_index",
             "element irregular_list 3",
             "property list uchar int vertex_index",
             "end_header",
             "0 0 0",
             "0 0 1",
             "0 1 1",
             "0 1 0",
             "1 0 0",
             "1 0 1",
             "1 1 1",
             "1 1 0",
             "4 0 1 2 3",
             "4 7 6 5 4",
             "4 0 4 5 1",
             "4 1 5 6 2",
             "4 2 6 7 3",
             "4 3 7 4 0",  # end of faces
             "4 0 1 2 3",
             "4 7 6 5 4",
             "3 4 5 1",
         ]
     )
     for line_ending in [None, "\n", "\r\n"]:
         if line_ending is None:
             stream = StringIO(ply_file)
         else:
             byte_file = ply_file.encode("ascii")
             if line_ending == "\r\n":
                 byte_file = byte_file.replace(b"\n", b"\r\n")
             stream = BytesIO(byte_file)
         header, data = _load_ply_raw(stream)
         self.assertTrue(header.ascii)
         self.assertEqual(len(data), 3)
         self.assertTupleEqual(data["face"].shape, (6, 4))
         self.assertClose([0, 1, 2, 3], data["face"][0])
         self.assertClose([3, 7, 4, 0], data["face"][5])
         self.assertTupleEqual(data["vertex"].shape, (8, 3))
         irregular = data["irregular_list"]
         self.assertEqual(len(irregular), 3)
         self.assertEqual(type(irregular), list)
         [x] = irregular[0]
         self.assertClose(x, [0, 1, 2, 3])
         [x] = irregular[1]
         self.assertClose(x, [7, 6, 5, 4])
         [x] = irregular[2]
         self.assertClose(x, [4, 5, 1])
示例#3
0
    def test_bad_ply_syntax(self):
        """Some syntactically bad ply files."""
        lines = [
            "ply",
            "format ascii 1.0",
            "comment dashfadskfj;k",
            "element vertex 1",
            "property float x",
            "element listy 1",
            "property list uint int x",
            "end_header",
            "0",
            "0",
        ]
        lines2 = lines.copy()
        # this is ok
        _load_ply_raw(StringIO("\n".join(lines2)))

        lines2 = lines.copy()
        lines2[0] = "PLY"
        with self.assertRaisesRegex(ValueError, "Invalid file header."):
            _load_ply_raw(StringIO("\n".join(lines2)))

        lines2 = lines.copy()
        lines2[2] = "#this is a comment"
        with self.assertRaisesRegex(ValueError, "Invalid line.*"):
            _load_ply_raw(StringIO("\n".join(lines2)))

        lines2 = lines.copy()
        lines2[3] = lines[4]
        lines2[4] = lines[3]
        with self.assertRaisesRegex(
                ValueError, "Encountered property before any element."):
            _load_ply_raw(StringIO("\n".join(lines2)))

        lines2 = lines.copy()
        lines2[8] = "1 2"
        with self.assertRaisesRegex(ValueError,
                                    "Inconsistent data for vertex."):
            _load_ply_raw(StringIO("\n".join(lines2)))

        lines2 = lines[:-1]
        with self.assertRaisesRegex(ValueError, "Not enough data for listy."):
            _load_ply_raw(StringIO("\n".join(lines2)))

        lines2 = lines.copy()
        lines2[5] = "element listy 2"
        with self.assertRaisesRegex(ValueError, "Not enough data for listy."):
            _load_ply_raw(StringIO("\n".join(lines2)))

        lines2 = lines.copy()
        lines2.insert(4, "property short x")
        with self.assertRaisesRegex(
                ValueError, "Cannot have two properties called x in vertex."):
            _load_ply_raw(StringIO("\n".join(lines2)))

        lines2 = lines.copy()
        lines2.insert(4, "property zz short")
        with self.assertRaisesRegex(ValueError, "Invalid datatype: zz"):
            _load_ply_raw(StringIO("\n".join(lines2)))

        lines2 = lines.copy()
        lines2.append("3")
        with self.assertRaisesRegex(ValueError, "Extra data at end of file."):
            _load_ply_raw(StringIO("\n".join(lines2)))

        lines2 = lines.copy()
        lines2.append("comment foo")
        with self.assertRaisesRegex(ValueError, "Extra data at end of file."):
            _load_ply_raw(StringIO("\n".join(lines2)))

        lines2 = lines.copy()
        lines2.insert(4, "element bad 1")
        with self.assertRaisesRegex(ValueError,
                                    "Found an element with no properties."):
            _load_ply_raw(StringIO("\n".join(lines2)))

        lines2 = lines.copy()
        lines2[-1] = "3 2 3 3"
        _load_ply_raw(StringIO("\n".join(lines2)))

        lines2 = lines.copy()
        lines2[-1] = "3 1 2 3 4"
        msg = "A line of listy data did not have the specified length."
        with self.assertRaisesRegex(ValueError, msg):
            _load_ply_raw(StringIO("\n".join(lines2)))

        lines2 = lines.copy()
        lines2[3] = "element vertex one"
        msg = "Number of items for vertex was not a number."
        with self.assertRaisesRegex(ValueError, msg):
            _load_ply_raw(StringIO("\n".join(lines2)))

        # Heterogenous cases
        lines2 = lines.copy()
        lines2.insert(4, "property double y")

        with self.assertRaisesRegex(ValueError,
                                    "Too little data for an element."):
            _load_ply_raw(StringIO("\n".join(lines2)))

        lines2[-2] = "3.3 4.2"
        _load_ply_raw(StringIO("\n".join(lines2)))

        lines2[-2] = "3.3 4.3 2"
        with self.assertRaisesRegex(ValueError,
                                    "Too much data for an element."):
            _load_ply_raw(StringIO("\n".join(lines2)))

        # Now make the ply file actually be readable as a Mesh

        with self.assertRaisesRegex(ValueError,
                                    "The ply file has no face element."):
            load_ply(StringIO("\n".join(lines)))

        lines2 = lines.copy()
        lines2[5] = "element face 1"
        with self.assertRaisesRegex(ValueError, "Invalid vertices in file."):
            load_ply(StringIO("\n".join(lines2)))

        lines2.insert(5, "property float z")
        lines2.insert(5, "property float y")
        lines2[-2] = "0 0 0"
        lines2[-1] = ""
        with self.assertRaisesRegex(ValueError, "Not enough data for face."):
            load_ply(StringIO("\n".join(lines2)))

        lines2[-1] = "2 0 0"
        with self.assertRaisesRegex(ValueError,
                                    "Faces must have at least 3 vertices."):
            load_ply(StringIO("\n".join(lines2)))

        # Good one
        lines2[-1] = "3 0 0 0"
        load_ply(StringIO("\n".join(lines2)))
示例#4
0
    def test_load_simple_binary(self):
        for big_endian in [True, False]:
            verts = ("0 0 0 "
                     "0 0 1 "
                     "0 1 1 "
                     "0 1 0 "
                     "1 0 0 "
                     "1 0 1 "
                     "1 1 1 "
                     "1 1 0").split()
            faces = (
                "4 0 1 2 3 "
                "4 7 6 5 4 "
                "4 0 4 5 1 "
                "4 1 5 6 2 "
                "4 2 6 7 3 "
                "4 3 7 4 0 "  # end of first 6
                "4 0 1 2 3 "
                "4 7 6 5 4 "
                "3 4 5 1").split()
            short_one = b"\00\01" if big_endian else b"\01\00"
            mixed_data = b"\00\00" b"\03\03" + (short_one + b"\00\01\01\01"
                                                b"\00\02")
            minus_one_data = b"\xff" * 14
            endian_char = ">" if big_endian else "<"
            format = ("format binary_big_endian 1.0"
                      if big_endian else "format binary_little_endian 1.0")
            vertex_pattern = endian_char + "24f"
            vertex_data = struct.pack(vertex_pattern, *map(float, verts))
            vertex1_pattern = endian_char + "fdffdffdffdffdffdffdffdf"
            vertex1_data = struct.pack(vertex1_pattern, *map(float, verts))
            face_char_pattern = endian_char + "44b"
            face_char_data = struct.pack(face_char_pattern, *map(int, faces))
            header = "\n".join([
                "ply",
                format,
                "element vertex 8",
                "property float x",
                "property float y",
                "property float z",
                "element vertex1 8",
                "property float x",
                "property double y",
                "property float z",
                "element face 6",
                "property list uchar uchar vertex_index",
                "element irregular_list 3",
                "property list uchar uchar vertex_index",
                "element mixed 2",
                "property list short uint foo",
                "property short bar",
                "element minus_ones 1",
                "property char 1",
                "property uchar 2",
                "property short 3",
                "property ushort 4",
                "property int 5",
                "property uint 6",
                "end_header\n",
            ])
            ply_file = b"".join([
                header.encode("ascii"),
                vertex_data,
                vertex1_data,
                face_char_data,
                mixed_data,
                minus_one_data,
            ])
            metadata, data = _load_ply_raw(BytesIO(ply_file))
            self.assertFalse(metadata.ascii)
            self.assertEqual(len(data), 6)
            self.assertTupleEqual(data["face"].shape, (6, 4))
            self.assertClose([0, 1, 2, 3], data["face"][0])
            self.assertClose([3, 7, 4, 0], data["face"][5])

            self.assertTupleEqual(data["vertex"].shape, (8, 3))
            self.assertEqual(len(data["vertex1"]), 8)
            self.assertClose(data["vertex"], data["vertex1"])
            self.assertClose(data["vertex"].flatten(), list(map(float, verts)))

            irregular = data["irregular_list"]
            self.assertEqual(len(irregular), 3)
            self.assertEqual(type(irregular), list)
            [x] = irregular[0]
            self.assertClose(x, [0, 1, 2, 3])
            [x] = irregular[1]
            self.assertClose(x, [7, 6, 5, 4])
            [x] = irregular[2]
            self.assertClose(x, [4, 5, 1])

            mixed = data["mixed"]
            self.assertEqual(len(mixed), 2)
            self.assertEqual(len(mixed[0]), 2)
            self.assertEqual(len(mixed[1]), 2)
            self.assertEqual(mixed[0][1], 3 * 256 + 3)
            self.assertEqual(len(mixed[0][0]), 0)
            self.assertEqual(mixed[1][1], (2 if big_endian else 2 * 256))
            base = 1 + 256 + 256 * 256
            self.assertEqual(len(mixed[1][0]), 1)
            self.assertEqual(mixed[1][0][0],
                             base if big_endian else 256 * base)

            self.assertListEqual(data["minus_ones"],
                                 [(-1, 255, -1, 65535, -1, 4294967295)])
示例#5
0
def load_ply(f):
    """
    Load the data from a .ply file.

    Example .ply file format:

    ply
    format ascii 1.0           { ascii/binary, format version number }
    comment made by Greg Turk  { comments keyword specified, like all lines }
    comment this file is a cube
    element vertex 8           { define "vertex" element, 8 of them in file }
    property float x           { vertex contains float "x" coordinate }
    property float y           { y coordinate is also a vertex property }
    property float z           { z coordinate, too }
    element face 6             { there are 6 "face" elements in the file }
    property list uchar int vertex_index { "vertex_indices" is a list of ints }
    end_header                 { delimits the end of the header }
    0 0 0                      { start of vertex list }
    0 0 1
    0 1 1
    0 1 0
    1 0 0
    1 0 1
    1 1 1
    1 1 0
    4 0 1 2 3                  { start of face list }
    4 7 6 5 4
    4 0 4 5 1
    4 1 5 6 2
    4 2 6 7 3
    4 3 7 4 0

    Args:
        f:  A binary or text file-like object (with methods read, readline,
            tell and seek), a pathlib path or a string containing a file name.
            If the ply file is in the binary ply format rather than the text
            ply format, then a text stream is not supported.
            It is easiest to use a binary stream in all cases.

    Returns:
        verts: FloatTensor of shape (V, 3).
        faces: LongTensor of vertex indices, shape (F, 3).
    """
    header, elements = _load_ply_raw(f)

    vertex = elements.get("vertex", None)
    if vertex is None:
        raise ValueError("The ply file has no vertex element.")

    face = elements.get("face", None)
    if face is None:
        raise ValueError("The ply file has no face element.")

    # if len(vertex) and (
    #     not isinstance(vertex, np.ndarray) or vertex.ndim != 2 or vertex.shape[1] != 3
    # ):
    #     raise ValueError("Invalid vertices in file.")
    vertex_pos = [vertex[0:3] for vertex in vertex]
    vertex_n = [vertex[3:6] for vertex in vertex]
    verts_st = [vertex[5:8] for vertex in vertex]
    vertex_rgba = [vertex[8:13] for vertex in vertex]

    verts = _make_tensor(vertex_pos, cols=3, dtype=torch.float32)
    verts_normal = _make_tensor(vertex_n, cols=3, dtype=torch.float32)
    verts_st = _make_tensor(verts_st, cols=2, dtype=torch.float32)
    verts_rgba = _make_tensor(vertex_rgba, cols=4, dtype=torch.uint8)

    face_head = next(head for head in header.elements if head.name == "face")
    if len(face_head.properties
           ) != 1 or face_head.properties[0].list_size_type is None:
        raise ValueError("Unexpected form of faces data.")
    # face_head.properties[0].name is usually "vertex_index" or "vertex_indices"
    # but we don't need to enforce this.

    if not len(face):
        faces = torch.zeros(size=(0, 3), dtype=torch.int64)
    elif isinstance(face,
                    np.ndarray) and face.ndim == 2:  # Homogeneous elements
        if face.shape[1] < 3:
            raise ValueError("Faces must have at least 3 vertices.")
        face_arrays = [
            face[:, [0, i + 1, i + 2]] for i in range(face.shape[1] - 2)
        ]
        faces = torch.LongTensor(np.vstack(face_arrays).astype(np.long))
    else:
        face_list = []
        for face_item in face:
            if face_item.ndim != 1:
                raise ValueError("Bad face data.")
            if face_item.shape[0] < 3:
                raise ValueError("Faces must have at least 3 vertices.")
            for i in range(face_item.shape[0] - 2):
                face_list.append(
                    [face_item[0], face_item[i + 1], face_item[i + 2]])
        faces = _make_tensor(face_list, cols=3, dtype=torch.int64)

    _check_faces_indices(faces, max_index=verts.shape[0])
    return verts, verts_normal, verts_st, verts_rgba, faces
示例#6
0
    def test_bad_ply_syntax(self):
        """Some syntactically bad ply files."""
        lines = [
            'ply',
            'format ascii 1.0',
            'comment dashfadskfj;k',
            'element vertex 1',
            'property float x',
            'element listy 1',
            'property list uint int x',
            'end_header',
            '0',
            '0',
        ]
        lines2 = lines.copy()
        # this is ok
        _load_ply_raw(StringIO('\n'.join(lines2)))

        lines2 = lines.copy()
        lines2[0] = 'PLY'
        with self.assertRaisesRegex(ValueError, 'Invalid file header.'):
            _load_ply_raw(StringIO('\n'.join(lines2)))

        lines2 = lines.copy()
        lines2[2] = '#this is a comment'
        with self.assertRaisesRegex(ValueError, 'Invalid line.*'):
            _load_ply_raw(StringIO('\n'.join(lines2)))

        lines2 = lines.copy()
        lines2[3] = lines[4]
        lines2[4] = lines[3]
        with self.assertRaisesRegex(
            ValueError, 'Encountered property before any element.'
        ):
            _load_ply_raw(StringIO('\n'.join(lines2)))

        lines2 = lines.copy()
        lines2[8] = '1 2'
        with self.assertRaisesRegex(
            ValueError, 'Inconsistent data for vertex.'
        ):
            _load_ply_raw(StringIO('\n'.join(lines2)))

        lines2 = lines[:-1]
        with self.assertRaisesRegex(ValueError, 'Not enough data for listy.'):
            _load_ply_raw(StringIO('\n'.join(lines2)))

        lines2 = lines.copy()
        lines2[5] = 'element listy 2'
        with self.assertRaisesRegex(ValueError, 'Not enough data for listy.'):
            _load_ply_raw(StringIO('\n'.join(lines2)))

        lines2 = lines.copy()
        lines2.insert(4, 'property short x')
        with self.assertRaisesRegex(
            ValueError, 'Cannot have two properties called x in vertex.'
        ):
            _load_ply_raw(StringIO('\n'.join(lines2)))

        lines2 = lines.copy()
        lines2.insert(4, 'property zz short')
        with self.assertRaisesRegex(ValueError, 'Invalid datatype: zz'):
            _load_ply_raw(StringIO('\n'.join(lines2)))

        lines2 = lines.copy()
        lines2.append('3')
        with self.assertRaisesRegex(ValueError, 'Extra data at end of file.'):
            _load_ply_raw(StringIO('\n'.join(lines2)))

        lines2 = lines.copy()
        lines2.append('comment foo')
        with self.assertRaisesRegex(ValueError, 'Extra data at end of file.'):
            _load_ply_raw(StringIO('\n'.join(lines2)))

        lines2 = lines.copy()
        lines2.insert(4, 'element bad 1')
        with self.assertRaisesRegex(
            ValueError, 'Found an element with no properties.'
        ):
            _load_ply_raw(StringIO('\n'.join(lines2)))

        lines2 = lines.copy()
        lines2[-1] = '3 2 3 3'
        _load_ply_raw(StringIO('\n'.join(lines2)))

        lines2 = lines.copy()
        lines2[-1] = '3 1 2 3 4'
        msg = 'A line of listy data did not have the specified length.'
        with self.assertRaisesRegex(ValueError, msg):
            _load_ply_raw(StringIO('\n'.join(lines2)))

        lines2 = lines.copy()
        lines2[3] = 'element vertex one'
        msg = 'Number of items for vertex was not a number.'
        with self.assertRaisesRegex(ValueError, msg):
            _load_ply_raw(StringIO('\n'.join(lines2)))

        # Heterogenous cases
        lines2 = lines.copy()
        lines2.insert(4, 'property double y')

        with self.assertRaisesRegex(
            ValueError, 'Too little data for an element.'
        ):
            _load_ply_raw(StringIO('\n'.join(lines2)))

        lines2[-2] = '3.3 4.2'
        _load_ply_raw(StringIO('\n'.join(lines2)))

        lines2[-2] = '3.3 4.3 2'
        with self.assertRaisesRegex(
            ValueError, 'Too much data for an element.'
        ):
            _load_ply_raw(StringIO('\n'.join(lines2)))

        # Now make the ply file actually be readable as a Mesh

        with self.assertRaisesRegex(
            ValueError, 'The ply file has no face element.'
        ):
            load_ply(StringIO('\n'.join(lines)))

        lines2 = lines.copy()
        lines2[5] = 'element face 1'
        with self.assertRaisesRegex(ValueError, 'Invalid vertices in file.'):
            load_ply(StringIO('\n'.join(lines2)))

        lines2.insert(5, 'property float z')
        lines2.insert(5, 'property float y')
        lines2[-2] = '0 0 0'
        lines2[-1] = ''
        with self.assertRaisesRegex(ValueError, 'Not enough data for face.'):
            load_ply(StringIO('\n'.join(lines2)))

        lines2[-1] = '2 0 0'
        with self.assertRaisesRegex(
            ValueError, 'Faces must have at least 3 vertices.'
        ):
            load_ply(StringIO('\n'.join(lines2)))

        # Good one
        lines2[-1] = '3 0 0 0'
        load_ply(StringIO('\n'.join(lines2)))
示例#7
0
    def test_load_simple_binary(self):
        for big_endian in [True, False]:
            verts = (
                '0 0 0 '
                '0 0 1 '
                '0 1 1 '
                '0 1 0 '
                '1 0 0 '
                '1 0 1 '
                '1 1 1 '
                '1 1 0'
            ).split()
            faces = (
                '4 0 1 2 3 '
                '4 7 6 5 4 '
                '4 0 4 5 1 '
                '4 1 5 6 2 '
                '4 2 6 7 3 '
                '4 3 7 4 0 '  # end of first 6
                '4 0 1 2 3 '
                '4 7 6 5 4 '
                '3 4 5 1'
            ).split()
            short_one = b'\00\01' if big_endian else b'\01\00'
            mixed_data = b'\00\00' b'\03\03' + (
                short_one + b'\00\01\01\01' b'\00\02'
            )
            minus_one_data = b'\xff' * 14
            endian_char = '>' if big_endian else '<'
            format = (
                'format binary_big_endian 1.0'
                if big_endian
                else 'format binary_little_endian 1.0'
            )
            vertex_pattern = endian_char + '24f'
            vertex_data = struct.pack(vertex_pattern, *map(float, verts))
            vertex1_pattern = endian_char + 'fdffdffdffdffdffdffdffdf'
            vertex1_data = struct.pack(vertex1_pattern, *map(float, verts))
            face_char_pattern = endian_char + '44b'
            face_char_data = struct.pack(face_char_pattern, *map(int, faces))
            header = '\n'.join(
                [
                    'ply',
                    format,
                    'element vertex 8',
                    'property float x',
                    'property float32 y',
                    'property float z',
                    'element vertex1 8',
                    'property float x',
                    'property double y',
                    'property float z',
                    'element face 6',
                    'property list uchar uchar vertex_index',
                    'element irregular_list 3',
                    'property list uchar uchar vertex_index',
                    'element mixed 2',
                    'property list short uint foo',
                    'property short bar',
                    'element minus_ones 1',
                    'property char 1',
                    'property uchar 2',
                    'property short 3',
                    'property ushort 4',
                    'property int 5',
                    'property uint 6',
                    'end_header\n',
                ]
            )
            ply_file = b''.join(
                [
                    header.encode('ascii'),
                    vertex_data,
                    vertex1_data,
                    face_char_data,
                    mixed_data,
                    minus_one_data,
                ]
            )
            metadata, data = _load_ply_raw(BytesIO(ply_file))
            self.assertFalse(metadata.ascii)
            self.assertEqual(len(data), 6)
            self.assertTupleEqual(data['face'].shape, (6, 4))
            self.assertClose([0, 1, 2, 3], data['face'][0])
            self.assertClose([3, 7, 4, 0], data['face'][5])

            self.assertTupleEqual(data['vertex'].shape, (8, 3))
            self.assertEqual(len(data['vertex1']), 8)
            self.assertClose(data['vertex'], data['vertex1'])
            self.assertClose(data['vertex'].flatten(), list(map(float, verts)))

            irregular = data['irregular_list']
            self.assertEqual(len(irregular), 3)
            self.assertEqual(type(irregular), list)
            [x] = irregular[0]
            self.assertClose(x, [0, 1, 2, 3])
            [x] = irregular[1]
            self.assertClose(x, [7, 6, 5, 4])
            [x] = irregular[2]
            self.assertClose(x, [4, 5, 1])

            mixed = data['mixed']
            self.assertEqual(len(mixed), 2)
            self.assertEqual(len(mixed[0]), 2)
            self.assertEqual(len(mixed[1]), 2)
            self.assertEqual(mixed[0][1], 3 * 256 + 3)
            self.assertEqual(len(mixed[0][0]), 0)
            self.assertEqual(mixed[1][1], (2 if big_endian else 2 * 256))
            base = 1 + 256 + 256 * 256
            self.assertEqual(len(mixed[1][0]), 1)
            self.assertEqual(mixed[1][0][0], base if big_endian else 256 * base)

            self.assertListEqual(
                data['minus_ones'], [(-1, 255, -1, 65535, -1, 4294967295)]
            )