Skip to content

Commit cd899d1

Browse files
authored
Merge pull request #1268 from nschloe/double-filetypes
Double filetypes
2 parents ac09d10 + 1b135ff commit cd899d1

File tree

9 files changed

+106
-49
lines changed

9 files changed

+106
-49
lines changed

setup.cfg

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[metadata]
22
name = meshio
3-
version = 5.2.6
3+
version = 5.3.0
44
author = Nico Schlömer et al.
55
author_email = [email protected]
66
description = I/O for many mesh formats

src/meshio/__init__.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@
3434
from .__about__ import __version__
3535
from ._exceptions import ReadError, WriteError
3636
from ._helpers import (
37-
extension_to_filetype,
37+
deregister_format,
38+
extension_to_filetypes,
3839
read,
3940
register_format,
4041
write,
@@ -77,8 +78,9 @@
7778
"read",
7879
"write",
7980
"register_format",
81+
"deregister_format",
8082
"write_points_cells",
81-
"extension_to_filetype",
83+
"extension_to_filetypes",
8284
"Mesh",
8385
"CellBlock",
8486
"ReadError",

src/meshio/_cli/_ascii.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from .. import ansys, flac3d, gmsh, mdpa, ply, stl, vtk, vtu, xdmf
55
from .._common import error
6-
from .._helpers import _filetype_from_path, read, reader_map
6+
from .._helpers import _filetypes_from_path, read, reader_map
77

88

99
def add_args(parser):
@@ -20,8 +20,12 @@ def add_args(parser):
2020

2121

2222
def ascii(args):
23-
# read mesh data
24-
fmt = args.input_format or _filetype_from_path(pathlib.Path(args.infile))
23+
if args.input_format:
24+
fmts = [args.input_format]
25+
else:
26+
fmts = _filetypes_from_path(pathlib.Path(args.infile))
27+
# pick the first
28+
fmt = fmts[0]
2529

2630
size = os.stat(args.infile).st_size
2731
print(f"File size before: {size / 1024 ** 2:.2f} MB")

src/meshio/_cli/_binary.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import pathlib
33

44
from .. import ansys, flac3d, gmsh, mdpa, ply, stl, vtk, vtu, xdmf
5-
from .._helpers import _filetype_from_path, read, reader_map
5+
from .._helpers import _filetypes_from_path, read, reader_map
66

77

88
def add_args(parser):
@@ -19,8 +19,12 @@ def add_args(parser):
1919

2020

2121
def binary(args):
22-
# read mesh data
23-
fmt = args.input_format or _filetype_from_path(pathlib.Path(args.infile))
22+
if args.input_format:
23+
fmts = [args.input_format]
24+
else:
25+
fmts = _filetypes_from_path(pathlib.Path(args.infile))
26+
# pick the first
27+
fmt = fmts[0]
2428

2529
size = os.stat(args.infile).st_size
2630
print(f"File size before: {size / 1024 ** 2:.2f} MB")

src/meshio/_cli/_compress.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from .. import ansys, cgns, gmsh, h5m, mdpa, ply, stl, vtk, vtu, xdmf
55
from .._common import error
6-
from .._helpers import _filetype_from_path, read, reader_map
6+
from .._helpers import _filetypes_from_path, read, reader_map
77

88

99
def add_args(parser):
@@ -26,8 +26,12 @@ def add_args(parser):
2626

2727

2828
def compress(args):
29-
# read mesh data
30-
fmt = args.input_format or _filetype_from_path(pathlib.Path(args.infile))
29+
if args.input_format:
30+
fmts = [args.input_format]
31+
else:
32+
fmts = _filetypes_from_path(pathlib.Path(args.infile))
33+
# pick the first
34+
fmt = fmts[0]
3135

3236
size = os.stat(args.infile).st_size
3337
print(f"File size before: {size / 1024 ** 2:.2f} MB")

src/meshio/_cli/_decompress.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from .. import cgns, h5m, vtu, xdmf
55
from .._common import error
6-
from .._helpers import _filetype_from_path, read, reader_map
6+
from .._helpers import _filetypes_from_path, read, reader_map
77

88

99
def add_args(parser):
@@ -19,8 +19,12 @@ def add_args(parser):
1919

2020

2121
def decompress(args):
22-
# read mesh data
23-
fmt = args.input_format or _filetype_from_path(pathlib.Path(args.infile))
22+
if args.input_format:
23+
fmts = [args.input_format]
24+
else:
25+
fmts = _filetypes_from_path(pathlib.Path(args.infile))
26+
# pick the first
27+
fmt = fmts[0]
2428

2529
size = os.stat(args.infile).st_size
2630
print(f"File size before: {size / 1024 ** 2:.2f} MB")

src/meshio/_helpers.py

+71-32
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,59 @@
11
from __future__ import annotations
22

3-
import pathlib
3+
import sys
4+
from pathlib import Path
45

56
import numpy as np
67
from numpy.typing import ArrayLike
78

8-
from ._common import num_nodes_per_cell
9+
from ._common import error, num_nodes_per_cell
910
from ._exceptions import ReadError, WriteError
1011
from ._files import is_buffer
1112
from ._mesh import CellBlock, Mesh
1213

13-
extension_to_filetype = {}
14+
extension_to_filetypes = {}
1415
reader_map = {}
1516
_writer_map = {}
1617

1718

18-
def register_format(name: str, extensions: list[str], reader, writer_map):
19+
def register_format(
20+
format_name: str, extensions: list[str], reader, writer_map
21+
) -> None:
1922
for ext in extensions:
20-
extension_to_filetype[ext] = name
23+
if ext not in extension_to_filetypes:
24+
extension_to_filetypes[ext] = []
25+
extension_to_filetypes[ext].append(format_name)
2126

2227
if reader is not None:
23-
reader_map[name] = reader
28+
reader_map[format_name] = reader
29+
2430
_writer_map.update(writer_map)
2531

2632

27-
def _filetype_from_path(path: pathlib.Path):
33+
def deregister_format(format_name: str):
34+
for value in extension_to_filetypes.values():
35+
if format_name in value:
36+
value.remove(format_name)
37+
38+
if format_name in reader_map:
39+
reader_map.pop(format_name)
40+
41+
if format_name in _writer_map:
42+
_writer_map.pop(format_name)
43+
44+
45+
def _filetypes_from_path(path: Path) -> list[str]:
2846
ext = ""
29-
out = None
47+
out = []
3048
for suffix in reversed(path.suffixes):
3149
ext = (suffix + ext).lower()
32-
if ext in extension_to_filetype:
33-
out = extension_to_filetype[ext]
50+
try:
51+
out += extension_to_filetypes[ext]
52+
except KeyError:
53+
pass
3454

35-
if out is None:
36-
raise ReadError(f"Could not deduce file format from extension '{ext}'.")
55+
if not out:
56+
raise ReadError(f"Could not deduce file format from path '{path}'.")
3757
return out
3858

3959

@@ -46,31 +66,48 @@ def read(filename, file_format: str | None = None):
4666
:returns mesh{2,3}d: The mesh data.
4767
"""
4868
if is_buffer(filename, "r"):
49-
if file_format is None:
50-
raise ReadError("File format must be given if buffer is used")
51-
if file_format == "tetgen":
52-
raise ReadError(
53-
"tetgen format is spread across multiple files "
54-
"and so cannot be read from a buffer"
55-
)
56-
msg = f"Unknown file format '{file_format}'"
57-
else:
58-
path = pathlib.Path(filename)
59-
if not path.exists():
60-
raise ReadError(f"File {filename} not found.")
69+
return _read_buffer(filename, file_format)
6170

62-
if not file_format:
63-
# deduce file format from extension
64-
file_format = _filetype_from_path(path)
71+
return _read_file(Path(filename), file_format)
6572

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

74+
def _read_buffer(filename, file_format: str | None):
75+
if file_format is None:
76+
raise ReadError("File format must be given if buffer is used")
77+
if file_format == "tetgen":
78+
raise ReadError(
79+
"tetgen format is spread across multiple files "
80+
"and so cannot be read from a buffer"
81+
)
6882
if file_format not in reader_map:
69-
raise ReadError(msg)
83+
raise ReadError(f"Unknown file format '{file_format}'")
7084

7185
return reader_map[file_format](filename)
7286

7387

88+
def _read_file(path: Path, file_format: str | None):
89+
if not path.exists():
90+
raise ReadError(f"File {path} not found.")
91+
92+
if file_format:
93+
possible_file_formats = [file_format]
94+
else:
95+
# deduce possible file formats from extension
96+
possible_file_formats = _filetypes_from_path(path)
97+
98+
for file_format in possible_file_formats:
99+
if file_format not in reader_map:
100+
raise ReadError(f"Unknown file format '{file_format}' of '{path}'.")
101+
102+
try:
103+
return reader_map[file_format](str(path))
104+
except ReadError:
105+
pass
106+
107+
error(f"Couldn't read file {path} as either of {', '.join(possible_file_formats)}")
108+
sys.exit(1)
109+
110+
74111
def write_points_cells(
75112
filename,
76113
points: ArrayLike,
@@ -113,10 +150,12 @@ def write(filename, mesh: Mesh, file_format: str | None = None, **kwargs):
113150
"tetgen format is spread across multiple files, and so cannot be written to a buffer"
114151
)
115152
else:
116-
path = pathlib.Path(filename)
153+
path = Path(filename)
117154
if not file_format:
118-
# deduce file format from extension
119-
file_format = _filetype_from_path(path)
155+
# deduce possible file formats from extension
156+
file_formats = _filetypes_from_path(path)
157+
# just take the first one
158+
file_format = file_formats[0]
120159

121160
try:
122161
writer = _writer_map[file_format]

src/meshio/ansys/_ansys.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -461,4 +461,4 @@ def write(filename, mesh, binary=True):
461461
first_index = last_index + 1
462462

463463

464-
register_format("ansys", [], read, {"ansys": write})
464+
register_format("ansys", [".msh"], read, {"ansys": write})

tests/test_public.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33

44
def test_public_attributes():
55
# Just make sure this is here
6-
meshio.extension_to_filetype
6+
meshio.extension_to_filetypes

0 commit comments

Comments
 (0)