4

I have been developing a Python toolbox which consists of 6 parameters. I have received immense amounts of help on this through StackExchange through the following posts:

How to Determine if a Layer is a Point

How to Change a Parameter Type from Optional to Required

I must say, you guys rock! I'm getting close to finishing up this toolbox and have yet again hit another wall.

For one of my parameters, I would like to throw a warning to the user if it is not a point shapefile. The main purpose of this tool is to label point shapefiles, so if they enter a polygon, that's going to potentially be a whole lot of labels showing on one map (at least for polygon shapefiles that I deal with). For some reason, the only way for the warning to appear correctly is for my updateParameters and updateMessages functions to consist of the following:

    def updateParameters(self, parameters):

    describe = arcpy.Describe(parameters[0].value)
    if describe.shapeType not in ('Point', 'Multipoint)':
        parameters[0].setWarningMessage('This is not a point feature class')
    else:
        parameters[0].clearMessage()    

    if parameters[2].value == True:
        parameters[3].enabled = True
        parameters[4].enabled = True
        parameters[5].enabled = True

    else:       
        parameters[3].enabled = False
        parameters[4].enabled = False
        parameters[5].enabled = False       

    return

def updateMessages(self, parameters):

    if parameters[0] != None:
        describe = arcpy.Describe(parameters[0].value)
        if describe.shapeType not in ('Point', 'Multipoint'):
            parameters[0].setWarningMessage('This is not a point shapefile. Labeling is not recommended.')
        else:
            parameters[0].clearMessage()

    return 

I can feed in a polygon shapefile and the warning appears and everything runs as it should. However, if I comment out the first 5 lines of the updateParameters method (the portion that checks if its a point and which also appears to be redundant), then my toolbox initially appears to have a bunch of errors with it once I open it:

enter image description here

enter image description here

My guess is that this has something to do with the order of validation that is performed for the tool. However, once I feed in a shapefile into the tool, all of the errors go away and the tool runs fine. So I have my tool working, just not in the way that I want it to since (a) I don't want to include a piece of code that I feel is redundant and (b) I shouldn't have error flags all over the place with the initial state of my tool.

  • Try describe = arcpy.Describe(parameters[0].valueAsText) instead. – Jason Scheirer Oct 10 '14 at 22:08
2

Update: You can just use filters for this and not bother with tool validation code: See Defining parameters in a Python toolbox use a filter (Applying filters to parameters section). There is a filter type for Feature Classes, against which you can specify Point and Multipoint geometry types.

Update 2: If you'd like to customize the filter behavior to change its message and make it a warning instead of an error to enter a non-point feature class, you can use updateMessages to do this:

def updateMessages(self, parameters):
  if parameters[0].hasError and parameters[0].message == 'ERROR 000366: Invalid geometry type':
     parameters[0].clearMessage()
     parameters[0].setWarningMessage('This is not a point shapefile. Labeling is not recommended.')
  return

Original post:

Looks like you just need to consistently guard against the first parameter being empty, so that Describe is not called when it is.

For example:

def updateParameters(self, parameters):
  if parameters[0].value:
    describe = arcpy.Describe(parameters[0].value)
    if describe.shapeType not in ('Point', 'Multipoint)':
      parameters[0].setWarningMessage('This is not a point feature class')
    else:
      parameters[0].clearMessage()
    if parameters[2].value == True:
      parameters[3].enabled = True
      parameters[4].enabled = True
      parameters[5].enabled = True
    else:
      parameters[3].enabled = False
      parameters[4].enabled = False
      parameters[5].enabled = False
  return

def updateMessages(self, parameters):
  if parameters[0].value:
    describe = arcpy.Describe(parameters[0].value)
    if describe.shapeType not in ('Point', 'Multipoint'):
      parameters[0].setWarningMessage('This is not a point shapefile. Labeling is not recommended.')
    else:
      parameters[0].clearMessage()
  return
  • I would need the same code in both updateParameters and updateMessages though? That's one part that doesn't sit well with me. In my opinion, I should only need to include that stretch of code into one of the functions, not both. . . – coolDude Oct 10 '14 at 21:36
  • I have used a filter, so I am familiar with them. How would I use a filter though to throw a warning? Or is your idea to not throw a warning and just use a filter to select either point or polygon as one of the parameters? – coolDude Oct 10 '14 at 21:38
  • I believe the filter will prevent you from selecting a disallowed feature type interactively, but if you enter one manually, it will set an error message saying that it's not allowed. If you need to allow the user to continue then you might be able to use updateMessages to replace the error with a warning. I'm not positive on this though. – blah238 Oct 10 '14 at 21:48
  • Yep that works, see update. – blah238 Oct 10 '14 at 22:06
  • I tried your idea and its still not working as I expected it to. . . Using the filter, it won't even allow me to use a polygon shapefile as an input to the first parameter. I simply get an error message that says "One or more dropped items were invalid and will not be added to the control." – coolDude Oct 13 '14 at 15:42
2

Thank you everyone for your help on this! I knew that this had something to do with how ArcMap performs its internal tool validation and I noticed the hasBeenValidated property for Parameters. I now have my update functions set up as follows and the tool works the way I've wanted it to:

def updateParameters(self, parameters): 

    if parameters[2].value == True:
        parameters[3].enabled = True
        parameters[4].enabled = True
        parameters[5].enabled = True

    else:       
        parameters[3].enabled = False
        parameters[4].enabled = False
        parameters[5].enabled = False       

    return

def updateMessages(self, parameters):

    if parameters[0].hasBeenValidated:
        describe = arcpy.Describe(parameters[0].value)
        if describe.shapeType not in ('Point', 'Multipoint') and parameters[2]:
            parameters[0].setWarningMessage('This is not a point shapefile. Labeling is not recommended.')
        else:
            parameters[0].clearMessage()

    return

No unnecessary, redundant code. I will be honest that I still don't completely understand why this works and how ArcMap's internal validation interacts with the tool. It's definitely some food for thought though :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.