Code is executing both the IF and ELSE statements

I have run into some errors in which my function seems to be reading in both if and else statements that I have created, instead of either one at a time.

So what I am trying to do is that, if it reads the importing file, first line/first character, if it is not v, it will prompts a warning and asked the user to re-import the relevant file. Else, if the file is correct, it will go on and creates the locators and group it.
Example - The file line in the correct obj file should be: v -0.6110637188 0.0093309134 8.1327419281

As soon as I tried another obj file in which it first line is started off as # This is a testing file… I was prompted with tons of errors as follows:

# Warning: Please import in a relevant Point Cloud Obj # 
# Warning: Please import in a relevant Point Cloud Obj # 
# Warning: Please import in a relevant Point Cloud Obj # 
# Warning: Please import in a relevant Point Cloud Obj # 
This part works if importing the right point cloud
This part works if importing the right point cloud
This part works if importing the right point cloud
This part works if importing the right point cloud
This part works if importing the right point cloud
This part works if importing the right point cloud
This part works if importing the right point cloud
This part works if importing the right point cloud
This part works if importing the right point cloud
# Failed to read file information
# Error: list index out of range
# Traceback (most recent call last):
#   File "<maya console>", line 62, in <module>
#   File "<maya console>", line 16, in __init__
#   File "<maya console>", line 58, in processLine
# IndexError: list index out of range # 

As you can see in the error log, it is printing the statement that I have inputted in both if and else statements. Additionally, it is creating out the locators as well which it should not be. This is my code:

import maya.cmds as cmds
import sys, os
import string

class ObjCloud():
    def __init__(self):
        try:
            fileHandle = open("/user_data/aaa.obj","r")
            filePath = os.path.basename(fileHandle.name)
            fileName = os.path.splitext(filePath)[0]
                            
            for line in fileHandle:
                self.processLine(line)
            fileHandle.close()
        except:
            sys.stderr.write( "Failed to read file information
")
            raise

        cmds.select("locator*")
        objGroup = cmds.group(n=("pointCloud_" + fileName))
        cmds.xform(os=True, piv=(0, 0, 0))
        cmds.scale(0.01, 0.01, 0.01)
        cmds.delete(constructionHistory=True)
    
        cmds.select(objGroup)
        cmds.group(n="cameraTrack")
        cmds.scale(10, 10, 10)
    
    def processLine(self, line):
        if(line[0] != "v"):
            cmds.warning("Please import in a relevant Point Cloud Obj")
        else:
            brokenString = string.split(line)

            cmds.spaceLocator(absolute=True, position=(\
            float(brokenString[1])*100\
            , float(brokenString[2])*100\
            , float(brokenString[3])*100))
            cmds.CenterPivot()
            

I don’t have tme to hack that up and try, but on first look i would suspect that you need to change your for loop:


from:
for line in fileHandle:

to:
for line in fileHandle.readlines():

You seem to be iterating over the filehandle which won’t work.

Cheers,
Thorsten

[QUOTE=instinct-vfx;25534]I don’t have tme to hack that up and try, but on first look i would suspect that you need to change your for loop:


from:
for line in fileHandle:

to:
for line in fileHandle.readlines():

You seem to be iterating over the filehandle which won’t work.

Cheers,
Thorsten[/QUOTE]

Hi Thorsten, tried out yout method, and the same error persists.
Also, I did try it out using .startswith and it does not seems to help me either :frowning:

Apparently, it would seem that my code is iterating the next line in the file though…

I am not sure why you are doing this as a class because it seems kind of confusing that way. Anyways, i’ll try and look at this a bit later as i currently can’t.

Can you provide a few lines of example obj or an sample obj?

Cheers,
Thorsten

[QUOTE=instinct-vfx;25536]I am not sure why you are doing this as a class because it seems kind of confusing that way. Anyways, i’ll try and look at this a bit later as i currently can’t.

Can you provide a few lines of example obj or an sample obj?

Cheers,
Thorsten[/QUOTE]

This is part of a plugin execution, and I am trying to stay in the same style of coding as it was without modifying too much on it, this current part is one that I am having trouble with.

Here are the sample contents within the obj files:
Correct version

v -0.6110637188 0.0093309134 8.1327419281
vn -0.2112581345 -0.7280599689 -0.6521492792
v 0.7267020941 0.0233836491 8.6937112808
vn -0.0528684395 -0.1126191291 -0.9922307493

Incorrect Version

# This file uses centimeters as units for non-parametric coordinates.

mtllib aaa.mtl
g default
v -7.768849 -7.768849 7.768849

So you do a loop:
for line in fileHandle:
self.processLine(line)

And then sometimes this happens and you throw a warning:
def processLine(self, line):
if(line[0] != “v”):
cmds.warning(“Please import in a relevant Point Cloud Obj”)

But a warning is no exception, so the loop continues, and eventaully you will find that, for a completely different line, this happens:
else:
brokenString = string.split(line)

        cmds.spaceLocator(absolute=True, position=(\
        float(brokenString[1])*100\
        , float(brokenString[2])*100\
        , float(brokenString[3])*100))

The error then is in the brokenString, as it has no 4 sections. I don’t know off the top of my hat what split does, I’d guess
it splits by spaces? So maybe you’re crossing a UV coordinate (vt) which has only 2 pieces?
What you want to check is line[0:2] != 'v ’ so that you don’t get vn and vt in your way. Also you may wish to trim whitespace off the line before using it in case of quircky exporters. Hope that helps… ?

FWIW, that actually does work. Each iteration it simply returns the next line from that file. It’s also faster and more memory efficient than preloading all the lines with .readlines().

Trevor’s got it. You’ve a for loop that is iterating over every line in the file and sending that line to a function to determine if it is valid or not. But, even if the line is invalid there is nothing telling the for loop to halt. So it is happily sending every line off to the function, the function is happily validating and writing to the error log its determinations, but nothing anywhere is telling the whole thing to stop if an invalid line is encountered. By your description up top, if you are only ever wanting to check the first line to determine if the file is valid you shouldn’t be looping over every line in the file.

  • Read the first line and pass it to the validator.
  • If the result from the validator is True then loop over every line and process the point cloud vertices as necessary
  • If the result from the validator is False then prompt the user to pick a different file and start over.

[QUOTE=Jeff Hanna;25543]Trevor’s got it. You’ve a for loop that is iterating over every line in the file and sending that line to a function to determine if it is valid or not. But, even if the line is invalid there is nothing telling the for loop to halt. So it is happily sending every line off to the function, the function is happily validating and writing to the error log its determinations, but nothing anywhere is telling the whole thing to stop if an invalid line is encountered. By your description up top, if you are only ever wanting to check the first line to determine if the file is valid you shouldn’t be looping over every line in the file.

  • Read the first line and pass it to the validator.
  • If the result from the validator is True then loop over every line and process the point cloud vertices as necessary
  • If the result from the validator is False then prompt the user to pick a different file and start over.[/QUOTE]

I managed to do something like this, this time round it seems to work, however, I am still having some trouble.
Tried using commands, like pass, continue, it does not seems to be working…

So I have pasted the following three functions in which chkBox when enabled, it will also enables the textfield. So if the textfield is blank, it will prompt a warning else it will carry on.
readFileIn is the function for the Creation button in my UI, so supposedly if everything is working fine and dandy, it should creates the locator and group it else it will halt any if the obj is wrong.

As for the ReadObjCloud, this parses the information of the obj file. So if the first character is not V, it will prompts and Invalid warning. But this portion seems to be the one giving me the most problem, as while it is able to differentiate whether there are V characters in the first character, the ui closes on me instead of the user going back to the ui and reimport a working obj file…

    

class CustomNodeTranslator(OpenMayaMPx.MPxFileTranslator):
    ...
    ...
    
    def chkBox(self):
        importCloudCheck = cmds.checkBox(self.cloudCheckbox, query=True, value=True)
        finalObjPath = cmds.textField(self.waveFileAddress, query=True, text=True)
        if(importCloudCheck == 1):
            if finalObjPath != "":
                ReadObjCloud(finalObjPath)
                return True
            else:
                return False
        else:
            print ("Importing in Camera only")
            return True
    
    
    def readFileIn(self, *args):
        if self.chkBox():
            chanRotationOrder = cmds.optionMenuGrp(self.rotationOrderControl, value=True, query=True)

            self.importTheChan = ChanFileImporter(chanRotationOrder)
            
            try:
                for line in self.fileHandle:
                    self.processLine(line)
                self.fileHandle.close()

                self.closeWindow()
            
            except:
                sys.stderr.write( "Failed to read file information
")
                raise
        else:
            cmds.warning("Input a valid Point Cloud Path or checked off the Import option ")

class ReadObjCloud():
    def __init__(self, objPath):
        try:
            fileHandle = open(objPath,"r")
            filePath = os.path.basename(fileHandle.name)
            fileName = os.path.splitext(filePath)[0]
            
            for item in fileHandle.readline()[0]:
                if item[0] == "v":
                    for line in fileHandle:
                        self.processLine(line)
                    fileHandle.close()
                    
                    # Selects all the imported locators, grouped and transformed it
                    cmds.select(camSel[0] + "_locator*")
                    objGroup = cmds.group(n=("pointCloud_" + fileName))
                    cmds.xform(os=True, piv=(0, 0, 0))
                    cmds.scale(0.01, 0.01, 0.01)
                    cmds.delete(constructionHistory=True)

                    cmds.select(objGroup, camSel[0], add=True)
                    cmds.group(n="cameraTrack")
                    cmds.scale(10, 10, 10)
                    
                else:
                    cmds.warning ("Invalid")
        except:
            sys.stderr.write( "Failed to read file information
")
            raise
    
    def processLine(self, line):
        brokenString = string.split(line)
        
        # Creation of locators and they are named with the prefix of the imported camera
        cmds.spaceLocator(name = camSel[0] + "_locator", absolute=True, position=(\
        float(brokenString[1])*100\
        , float(brokenString[2])*100\
        , float(brokenString[3])*100))
        cmds.CenterPivot()
        cmds.scale(0.5, 0.5, 0.5)

One common way this is handled is to create a set of functions which handle the data and return a value if they know how to handle a given input, or return None if they don’t. You then pass every line to the whole chain and the first function which knows what to do will say “i’m done” and then move on to the next line.


def parse_vertex_line(line):
     if not line.startwith("v="): return
     # real code here...
     return vertex(x,y,z)

def parse_face_line(line):
      if not line.startswith("f="): return
      #more magic
      return Face(x,y,z,w)

def skip_comments(line):
      if line.startswith("#") return 'comment'


chain = (skip_comments, parse_vertex_line,  parse_face_line)

for eachline  in file:
     for eachparser in chain:
         result = eachparser(line)
         if result:
             # do something with the result
             break # this line is done

This is a very common trick in writing file parsers, usually known as the Chain of Responsibility pattern. It’s a nice structure because it keeps the different processing steps nicely separated, and you can adjust the precedence of different operations by changing the order of checks in the chain.

You can also create modal checks which can handle multiple lines at once. For example, using the above code


class ModelParser(object):
     def __init__(self):
          self.active = false
          self.modelname = ""
          self.components = []

     def check(self, line):
          if not self.active:  # go to 'i'm inside a model' mode if this line starts a new model
              if not line.startswith("model="): return   
              self.modelname = line.split("=")[-1]
              return True
          else:
             # use a mini chain in here!
              for eachparser in (parse_vertex_line, parse_face_line)
                   result = eachparser(line)
                   if result: 
                       self.components.add(result)
                       return True
              #if you got here, you're out of faces and vertices so reset
              self.active = false
              return Model(self.modelname, self.components)


more examples:
http://books.google.com/books?id=gdN5AAAAQBAJ&pg=PA74&lpg=PA74&dq=python+chain+of+responsibility&source=bl&ots=I2wO_mo8lR&sig=zQw1UC3ZRvocHnqcAcfN_vKKJZ4&hl=en&sa=X&ei=Cg8bVJmqHIK4iwL4koCYDA&ved=0CEQQ6AEwBjgK#v=onepage&q=python%20chain%20of%20responsibility&f=false"]Chain Of Responsiblity
https://mail.python.org/pipermail/python-list/2009-March/528090.html

I have modify the code for the ReadObjCloud. Is it any better from my previous attempt, or no difference at all?
I am still trying to figure out the process of getting my UI to still be present or ‘loop’ back if it encounters a faulty file…

class ReadObjCloud():
    def __init__(self, objPath):
        
        try:
            fileHandle = open(objPath,"r")
            self.fileHandle = fileHandle
            filePath = os.path.basename(fileHandle.name)
            fileName = os.path.splitext(filePath)[0]
            
            for char in fileHandle.readline()[0]:
                if char.startswith("v"):
                    self.processLine()
                    
                    # Selects all the imported locators, grouped and transformed it
                    cmds.select(camSel[0] + "_locator*")
                    objGroup = cmds.group(n=("pointCloud_" + fileName))
                    cmds.xform(os=True, piv=(0, 0, 0))
                    cmds.scale(0.01, 0.01, 0.01)
                    cmds.delete(constructionHistory=True)

                    cmds.select(objGroup, camSel[0], add=True)
                    cmds.group(n="cameraTrack")
                    cmds.scale(10, 10, 10)

                else:
                    self.noProcess()
                
        except:
            sys.stderr.write( "Failed to read file information
")
            raise
        
    def processLine(self):
        for line in self.fileHandle:
            brokenString = string.split(line)
            
            # Creation of locators and they are named with the prefix of the imported camera
            cmds.spaceLocator(name = camSel[0] + "_locator", absolute=True, position=(\
            float(brokenString[1])*100\
            , float(brokenString[2])*100\
            , float(brokenString[3])*100))
            cmds.CenterPivot()
            cmds.scale(0.5, 0.5, 0.5)
        
        self.fileHandle.close()

    def noProcess(self):
        print "INVALID"

This is a bit confusing: in the main proc you have


for char in fileHandle.readline()[0]:
     if char.startswith("v"):
            self.processLine()

but in processline you have:


    def processLine(self):
        for line in self.fileHandle:
            brokenString = string.split(

Which is going to read the file again inside the processing of the line triggered above. That does not sound like what you want…

Very cool! Didn’t know that and definitely one to remember!

[QUOTE=Theodox;25571]This is a bit confusing: in the main proc you have


for char in fileHandle.readline()[0]:
     if char.startswith("v"):
            self.processLine()

but in processline you have:


    def processLine(self):
        for line in self.fileHandle:
            brokenString = string.split(

Which is going to read the file again inside the processing of the line triggered above. That does not sound like what you want…[/QUOTE]

I was thinking soemthing along these lines…
So when the fileHandle is reading the file, if the first chacracter of the word is ‘v’, it will then proceed on the the processLine function. Else it will simply pass but this will prompts back to my second problem where my ui keeps closing