Skip to content

Commit

Permalink
Merge pull request #1268 from nschloe/double-filetypes
Browse files Browse the repository at this point in the history
Double filetypes
  • Loading branch information
nschloe authored Jan 24, 2022
2 parents ac09d10 + 1b135ff commit cd899d1
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 49 deletions.
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = meshio
version = 5.2.6
version = 5.3.0
author = Nico Schlömer et al.
author_email = nico.schloemer@gmail.com
description = I/O for many mesh formats
Expand Down
6 changes: 4 additions & 2 deletions src/meshio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
from .__about__ import __version__
from ._exceptions import ReadError, WriteError
from ._helpers import (
extension_to_filetype,
deregister_format,
extension_to_filetypes,
read,
register_format,
write,
Expand Down Expand Up @@ -77,8 +78,9 @@
"read",
"write",
"register_format",
"deregister_format",
"write_points_cells",
"extension_to_filetype",
"extension_to_filetypes",
"Mesh",
"CellBlock",
"ReadError",
Expand Down
10 changes: 7 additions & 3 deletions src/meshio/_cli/_ascii.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from .. import ansys, flac3d, gmsh, mdpa, ply, stl, vtk, vtu, xdmf
from .._common import error
from .._helpers import _filetype_from_path, read, reader_map
from .._helpers import _filetypes_from_path, read, reader_map


def add_args(parser):
Expand All @@ -20,8 +20,12 @@ def add_args(parser):


def ascii(args):
# read mesh data
fmt = args.input_format or _filetype_from_path(pathlib.Path(args.infile))
if args.input_format:
fmts = [args.input_format]
else:
fmts = _filetypes_from_path(pathlib.Path(args.infile))
# pick the first
fmt = fmts[0]

size = os.stat(args.infile).st_size
print(f"File size before: {size / 1024 ** 2:.2f} MB")
Expand Down
10 changes: 7 additions & 3 deletions src/meshio/_cli/_binary.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import pathlib

from .. import ansys, flac3d, gmsh, mdpa, ply, stl, vtk, vtu, xdmf
from .._helpers import _filetype_from_path, read, reader_map
from .._helpers import _filetypes_from_path, read, reader_map


def add_args(parser):
Expand All @@ -19,8 +19,12 @@ def add_args(parser):


def binary(args):
# read mesh data
fmt = args.input_format or _filetype_from_path(pathlib.Path(args.infile))
if args.input_format:
fmts = [args.input_format]
else:
fmts = _filetypes_from_path(pathlib.Path(args.infile))
# pick the first
fmt = fmts[0]

size = os.stat(args.infile).st_size
print(f"File size before: {size / 1024 ** 2:.2f} MB")
Expand Down
10 changes: 7 additions & 3 deletions src/meshio/_cli/_compress.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from .. import ansys, cgns, gmsh, h5m, mdpa, ply, stl, vtk, vtu, xdmf
from .._common import error
from .._helpers import _filetype_from_path, read, reader_map
from .._helpers import _filetypes_from_path, read, reader_map


def add_args(parser):
Expand All @@ -26,8 +26,12 @@ def add_args(parser):


def compress(args):
# read mesh data
fmt = args.input_format or _filetype_from_path(pathlib.Path(args.infile))
if args.input_format:
fmts = [args.input_format]
else:
fmts = _filetypes_from_path(pathlib.Path(args.infile))
# pick the first
fmt = fmts[0]

size = os.stat(args.infile).st_size
print(f"File size before: {size / 1024 ** 2:.2f} MB")
Expand Down
10 changes: 7 additions & 3 deletions src/meshio/_cli/_decompress.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from .. import cgns, h5m, vtu, xdmf
from .._common import error
from .._helpers import _filetype_from_path, read, reader_map
from .._helpers import _filetypes_from_path, read, reader_map


def add_args(parser):
Expand All @@ -19,8 +19,12 @@ def add_args(parser):


def decompress(args):
# read mesh data
fmt = args.input_format or _filetype_from_path(pathlib.Path(args.infile))
if args.input_format:
fmts = [args.input_format]
else:
fmts = _filetypes_from_path(pathlib.Path(args.infile))
# pick the first
fmt = fmts[0]

size = os.stat(args.infile).st_size
print(f"File size before: {size / 1024 ** 2:.2f} MB")
Expand Down
103 changes: 71 additions & 32 deletions src/meshio/_helpers.py
Original file line number Diff line number Diff line change
@@ -1,39 +1,59 @@
from __future__ import annotations

import pathlib
import sys
from pathlib import Path

import numpy as np
from numpy.typing import ArrayLike

from ._common import num_nodes_per_cell
from ._common import error, num_nodes_per_cell
from ._exceptions import ReadError, WriteError
from ._files import is_buffer
from ._mesh import CellBlock, Mesh

extension_to_filetype = {}
extension_to_filetypes = {}
reader_map = {}
_writer_map = {}


def register_format(name: str, extensions: list[str], reader, writer_map):
def register_format(
format_name: str, extensions: list[str], reader, writer_map
) -> None:
for ext in extensions:
extension_to_filetype[ext] = name

This comment has been minimized.

Copy link
@kinnala

kinnala Jan 26, 2022

Concerning #1272. I think previously the last format to register was used by default. Now it is the first one in the list?

if ext not in extension_to_filetypes:
extension_to_filetypes[ext] = []
extension_to_filetypes[ext].append(format_name)

if reader is not None:
reader_map[name] = reader
reader_map[format_name] = reader

_writer_map.update(writer_map)


def _filetype_from_path(path: pathlib.Path):
def deregister_format(format_name: str):
for value in extension_to_filetypes.values():
if format_name in value:
value.remove(format_name)

if format_name in reader_map:
reader_map.pop(format_name)

if format_name in _writer_map:
_writer_map.pop(format_name)


def _filetypes_from_path(path: Path) -> list[str]:
ext = ""
out = None
out = []
for suffix in reversed(path.suffixes):
ext = (suffix + ext).lower()
if ext in extension_to_filetype:
out = extension_to_filetype[ext]
try:
out += extension_to_filetypes[ext]
except KeyError:
pass

if out is None:
raise ReadError(f"Could not deduce file format from extension '{ext}'.")
if not out:
raise ReadError(f"Could not deduce file format from path '{path}'.")
return out


Expand All @@ -46,31 +66,48 @@ def read(filename, file_format: str | None = None):
:returns mesh{2,3}d: The mesh data.
"""
if is_buffer(filename, "r"):
if file_format is None:
raise ReadError("File format must be given if buffer is used")
if file_format == "tetgen":
raise ReadError(
"tetgen format is spread across multiple files "
"and so cannot be read from a buffer"
)
msg = f"Unknown file format '{file_format}'"
else:
path = pathlib.Path(filename)
if not path.exists():
raise ReadError(f"File {filename} not found.")
return _read_buffer(filename, file_format)

if not file_format:
# deduce file format from extension
file_format = _filetype_from_path(path)
return _read_file(Path(filename), file_format)

msg = f"Unknown file format '{file_format}' of '{filename}'."

def _read_buffer(filename, file_format: str | None):
if file_format is None:
raise ReadError("File format must be given if buffer is used")
if file_format == "tetgen":
raise ReadError(
"tetgen format is spread across multiple files "
"and so cannot be read from a buffer"
)
if file_format not in reader_map:
raise ReadError(msg)
raise ReadError(f"Unknown file format '{file_format}'")

return reader_map[file_format](filename)


def _read_file(path: Path, file_format: str | None):
if not path.exists():
raise ReadError(f"File {path} not found.")

if file_format:
possible_file_formats = [file_format]
else:
# deduce possible file formats from extension
possible_file_formats = _filetypes_from_path(path)

for file_format in possible_file_formats:
if file_format not in reader_map:
raise ReadError(f"Unknown file format '{file_format}' of '{path}'.")

try:
return reader_map[file_format](str(path))
except ReadError:
pass

error(f"Couldn't read file {path} as either of {', '.join(possible_file_formats)}")
sys.exit(1)


def write_points_cells(
filename,
points: ArrayLike,
Expand Down Expand Up @@ -113,10 +150,12 @@ def write(filename, mesh: Mesh, file_format: str | None = None, **kwargs):
"tetgen format is spread across multiple files, and so cannot be written to a buffer"
)
else:
path = pathlib.Path(filename)
path = Path(filename)
if not file_format:
# deduce file format from extension
file_format = _filetype_from_path(path)
# deduce possible file formats from extension
file_formats = _filetypes_from_path(path)
# just take the first one
file_format = file_formats[0]

try:
writer = _writer_map[file_format]
Expand Down
2 changes: 1 addition & 1 deletion src/meshio/ansys/_ansys.py
Original file line number Diff line number Diff line change
Expand Up @@ -461,4 +461,4 @@ def write(filename, mesh, binary=True):
first_index = last_index + 1


register_format("ansys", [], read, {"ansys": write})
register_format("ansys", [".msh"], read, {"ansys": write})
2 changes: 1 addition & 1 deletion tests/test_public.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@

def test_public_attributes():
# Just make sure this is here
meshio.extension_to_filetype
meshio.extension_to_filetypes

0 comments on commit cd899d1

Please sign in to comment.