Skip to content

Commit 7b6e6e2

Browse files
committed
Make mtl parsing more robust using regex
Now supports e.g. whitespaces in filename
1 parent fded04f commit 7b6e6e2

File tree

2 files changed

+49
-7
lines changed

2 files changed

+49
-7
lines changed

obj2mjcf/cli.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""A CLI for processing composite Wavefront OBJ files for use in MuJoCo."""
22

3+
from collections.abc import Iterable
34
import logging
45
import os
56
import re
@@ -110,6 +111,15 @@ def decompose_convex(filename: Path, work_dir: Path, coacd_args: CoacdArgs) -> b
110111
return True
111112

112113

114+
def parse_mtl_name(lines: Iterable[str]) -> Optional[str]:
115+
mtl_regex = re.compile(r"^mtllib\s+(.+?\.mtl)(?:\s*#.*)?\s*\n?$")
116+
for line in lines:
117+
match = mtl_regex.match(line)
118+
if match is not None:
119+
name = match.group(1)
120+
return name
121+
return None
122+
113123
def process_obj(filename: Path, args: Args) -> None:
114124
# Create a directory with the same name as the OBJ file. The processed submeshes
115125
# and materials will be stored there.
@@ -133,13 +143,11 @@ def process_obj(filename: Path, args: Args) -> None:
133143

134144
# Check if the OBJ files references an MTL file.
135145
# TODO(kevin): Should we support multiple MTL files?
136-
process_mtl = False
137-
with open(filename, "r") as f:
138-
for line in f.readlines():
139-
if line.startswith("mtllib"): # Deals with commented out lines.
140-
process_mtl = True
141-
name = line.split()[1]
142-
break
146+
with filename.open("r") as f:
147+
name = parse_mtl_name(f.readlines())
148+
149+
process_mtl = name is not None
150+
143151

144152
sub_mtls: List[List[str]] = []
145153
mtls: List[Material] = []

tests/test_cli.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
from itertools import product
12
import pathlib
23
import subprocess
34

5+
from obj2mjcf import cli
6+
47
# Path to the directory containing this file.
58
_THIS_DIR = pathlib.Path(__file__).parent.absolute()
69

@@ -18,3 +21,34 @@ def test_runs_without_error() -> None:
1821
]
1922
)
2023
assert retcode == 0
24+
25+
26+
def test_parse_mtl_line() -> None:
27+
file_names = [
28+
"A B.mtl",
29+
"A_B.mtl",
30+
"AbCd.mtl",
31+
"a.mtl",
32+
"a b.mtl",
33+
"a-b.mtl",
34+
"a_b.mtl",
35+
]
36+
comments = [
37+
"",
38+
"# comment",
39+
" # comment",
40+
" # comment #",
41+
]
42+
for file_name, comment in product(file_names, comments):
43+
line = f"mtllib {file_name}{comment}\n"
44+
result = cli.parse_mtl_name(iter([line]))
45+
assert result == file_name, result
46+
47+
for line in (
48+
"a",
49+
"a # b",
50+
"mtllib a.what",
51+
"a.mtl",
52+
):
53+
result = cli.parse_mtl_name(iter([line]))
54+
assert result is None, result

0 commit comments

Comments
 (0)