class MeshReader(base.BaseReader):
def __init__(
self,
output: str,
fmt: str = DEFAULT_FMT,
attrs: Optional[Dict[str, Any]] = None,
errors: str = "raise",
):
super().__init__(
fmt=fmt,
attrs=attrs,
file_ext=MESH_LOAD_EXT,
name_fallback="MESH",
read_binary=True,
errors=errors,
)
self.output = output
def format_output(self, x):
# This function replaces the BaseReader.format_output()
# This is to avoid trying to convert multiple (image, header) to NeuronList
if self.output == "trimesh":
return x
elif x:
return core.NeuronList(x)
else:
return core.NeuronList([])
@base.handle_errors
def read_buffer(
self, f, attrs: Optional[Dict[str, Any]] = None
) -> Union[tm.Trimesh, "core.Volume", "core.MeshNeuron"]:
"""Read buffer into mesh.
Parameters
----------
f : IO
Readable buffer (must be bytes).
attrs : dict | None
Arbitrary attributes to include in the neurons.
Returns
-------
Trimesh | MeshNeuron | Volume
"""
if isinstance(f, HTTPResponse):
f = io.StringIO(f.content)
if isinstance(f, bytes):
f = io.BytesIO(f)
# We need to tell trimesh what file type we are reading
if "file" not in attrs:
raise KeyError(
f'Unable to parse file type. "file" not in attributes: {attrs}'
)
file_type = attrs["file"].split(".")[-1]
mesh = tm.load_mesh(f, file_type=file_type)
if self.output == "trimesh":
return mesh
elif self.output == "volume":
return core.Volume(mesh.vertices, mesh.faces, **attrs)
# Turn into a MeshNeuron
n = core.MeshNeuron(mesh)
# Try adding properties one-by-one. If one fails, we'll keep track of it
# in the `.meta` attribute
meta = {}
for k, v in attrs.items():
try:
n._register_attr(k, v)
except (AttributeError, ValueError, TypeError):
meta[k] = v
if meta:
n.meta = meta
return n