Skip to content

Commit 6c6db76

Browse files
author
Kurt Yoder
authored
Merge pull request #33 from einarf/mat-name-spaces
Make dir available as instance attribute + tests
2 parents 33c716e + c7f3c73 commit 6c6db76

File tree

5 files changed

+36
-23
lines changed

5 files changed

+36
-23
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ Contributors
7878

7979
* Daniel Coelho
8080
* dav92lee
81+
* Einar Forselv
8182
* Jerek Shoemaker
8283
* Kurt Yoder
8384
* Marxlp

pywavefront/__init__.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,17 @@
3131
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3232
# POSSIBILITY OF SUCH DAMAGE.
3333
# ----------------------------------------------------------------------------
34+
import os
3435

3536
import pywavefront.material
3637
import pywavefront.mesh
3738
import pywavefront.parser
3839

40+
3941
class PywavefrontException(Exception):
4042
pass
4143

44+
4245
class Wavefront(object):
4346
"""Import a wavefront .obj file."""
4447
def __init__(self, file_name):
@@ -58,18 +61,20 @@ def add_mesh(self, the_mesh):
5861
self.mesh_list.append(the_mesh)
5962
self.meshes[the_mesh.name] = the_mesh
6063

64+
6165
class ObjParser(parser.Parser):
6266
"""This parser parses lines from .obj files."""
67+
6368
def __init__(self, wavefront, file_name):
64-
# unfortunately we can't escape from external effects on the
65-
# wavefront object
69+
super(ObjParser, self).__init__(file_name)
6670
self.wavefront = wavefront
71+
6772
self.mesh = None
6873
self.material = None
6974
self.vertices = [[0., 0., 0.]]
7075
self.normals = [[0., 0., 0.]]
7176
self.tex_coords = [[0., 0.]]
72-
self.read_file(file_name)
77+
self.read_file()
7378

7479
# methods for parsing types of wavefront lines
7580
def parse_v(self, args):
@@ -82,7 +87,7 @@ def parse_vt(self, args):
8287
self.tex_coords.append(list(map(float, args[0:2])))
8388

8489
def parse_mtllib(self, args):
85-
[mtllib] = args
90+
mtllib = os.path.join(self.dir, " ".join(args))
8691
materials = material.MaterialParser(mtllib).materials
8792
for material_name, material_object in materials.items():
8893
self.wavefront.materials[material_name] = material_object
@@ -121,7 +126,6 @@ def parse_f(self, args):
121126
# For fan triangulation, remember first and latest vertices
122127
v1 = None
123128
vlast = None
124-
points = []
125129
for i, v in enumerate(args[0:]):
126130
if type(v) is bytes:
127131
v = v.decode()

pywavefront/material.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3232
# POSSIBILITY OF SUCH DAMAGE.
3333
# ----------------------------------------------------------------------------
34+
import os
3435

3536
import pywavefront.parser as parser
3637
import pywavefront.texture as texture
@@ -97,9 +98,10 @@ class MaterialParser(parser.Parser):
9798
"""Object to parse lines of a materials definition file."""
9899

99100
def __init__(self, file_path):
101+
super(MaterialParser, self).__init__(file_path)
100102
self.materials = {}
101103
self.this_material = None
102-
self.read_file(file_path)
104+
self.read_file()
103105

104106
def parse_newmtl(self, args):
105107
[newmtl] = args
@@ -127,7 +129,7 @@ def parse_d(self, args):
127129
self.this_material.set_alpha(d)
128130

129131
def parse_map_Kd(self, args):
130-
[Kd] = args
132+
Kd = os.path.join(self.dir, " ".join(args))
131133
self.this_material.set_texture(Kd)
132134

133135
def parse_Ni(self, args):

pywavefront/parser.py

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,21 +31,25 @@
3131
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3232
# POSSIBILITY OF SUCH DAMAGE.
3333
# ----------------------------------------------------------------------------
34-
3534
import os
3635
import logging
3736

37+
3838
class Parser(object):
3939
"""This defines a generalized parse dispatcher; all parse functions
4040
reside in subclasses."""
4141
strict = False
4242

43-
def read_file(self, file_name):
44-
with open(file_name, 'r') as file:
43+
def __init__(self, file_name):
44+
self.file_name = file_name
45+
self.dir = os.path.dirname(file_name)
46+
47+
def read_file(self):
48+
with open(self.file_name, 'r') as file:
4549
for line in file:
46-
self.parse(line, dir=os.path.dirname(file_name))
50+
self.parse(line)
4751

48-
def parse(self, line, dir):
52+
def parse(self, line):
4953
"""Determine what type of line we are and dispatch
5054
appropriately."""
5155
if line.startswith('#'):
@@ -57,14 +61,6 @@ def parse(self, line, dir):
5761

5862
line_type = values[0]
5963
args = values[1:]
60-
i = 0
61-
for arg in args:
62-
if dir != '' and ('mtllib' in line or 'map_Kd' in line):
63-
args[i] = dir + '/' + arg
64-
else:
65-
args[i] = arg
66-
i += 1
67-
6864
attrib = 'parse_%s' % line_type
6965

7066
if Parser.strict:

test/test_parser.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33

44
import pywavefront.parser
55

6+
67
def prepend_dir(file):
78
return os.path.join(os.path.dirname(__file__), file)
89

10+
911
class TestParsers(unittest.TestCase):
1012
def setUp(self):
1113
# Append current path to locate files
@@ -36,6 +38,7 @@ def testObjMaterials(self):
3638
self.assertEqual(material1.name, 'Material.simple')
3739
self.assertEqual(material2.name, 'Material2.simple')
3840

41+
3942
class TestMtlParser(unittest.TestCase):
4043
def setUp(self):
4144
# Append current path to locate files
@@ -73,13 +76,20 @@ def testMtlTextureName(self):
7376
self.assertEqual(self.material1.texture.image_name,
7477
prepend_dir('4x4.png'))
7578

79+
7680
class TestParserFailure(unittest.TestCase):
7781

7882
def testMissingParseFunction(self):
7983
"Attempting to parse with a missing parse function should raise an exception."
80-
# since no parse functions have been defined, this will always fail
81-
self.assertRaises(Exception, pywavefront.parser.Parser, prepend_dir('uv_sphere.obj'))
84+
# since no parse functions have been defined, this will always fail in strict mode
85+
file_name = 'simple.obj'
86+
parser = pywavefront.parser.Parser(prepend_dir(file_name))
87+
pywavefront.parser.Parser.strict = True
88+
self.assertRaises(AttributeError, parser.read_file, prepend_dir(file_name))
89+
pywavefront.parser.Parser.strict = False
8290

8391
def testMissingParsedFile(self):
8492
"Referencing a missing parsed file should raise an exception."
85-
self.assertRaises(Exception, pywavefront.parser.Parser, 'missing.file.do.not.create')
93+
file_name = 'doesnotexist.obj'
94+
parser = pywavefront.parser.Parser(prepend_dir(file_name))
95+
self.assertRaises(FileNotFoundError, parser.read_file, prepend_dir(file_name))

0 commit comments

Comments
 (0)