Global value can't be assigned inside the expression in python toolbox

1398
7
01-17-2020 04:26 AM
AarthiBalamurugan1
New Contributor

I am trying to call the global value 'total_rows' inside the expression. But I am getting an error.

and my code is

def execute(self, parameters, messages):
"""The source code of the tool."""
   inputdataset = parameters[0].valueAsText #getting the parameters

   count_rows = arcpy.GetCount_management(inputdataset)
   total_rows = int(count_rows.getOutput(0))

expression = '''

   def getCitation(p_dataset_id):
      global total_rows
      if(total_rows == 5):
            ds=PanDataSet(p_dataset_id)
   return ds.citation

'''

0 Kudos
7 Replies
RandyBurton
MVP Alum

Using globals in a Python toolbox or script tool is a bit tricky.  The toolbox/script creates a number of instances during function calls.  It is best to declare a global in getParameterInfo as this function appears to be called only once.  An example of a toolbox script that uses "junk" as a global variable is:

import arcpy

class Toolbox(object):
    def __init__(self):
        self.label = "Toolbox"
        self.alias = ""
        self.tools = [Tool]


class Tool(object):
    def __init__(self):
        self.label = "Tool"
        self.description = ""
        self.canRunInBackground = False

    def getParameterInfo(self):
        global junk
        junk = None
        param0 = arcpy.Parameter(
            displayName="Something",
            name="something",
            datatype="GPString",
            parameterType="Required",
            direction="Input"
        )
        params = [param0]
        return params

    def isLicensed(self):
        return True

    def updateParameters(self, parameters):
        global junk
        junk = "XYZ"
        return

    def updateMessages(self, parameters):
        return

    def execute(self, parameters, messages):
        global junk
        arcpy.AddMessage("The value junk is: " + junk)
        return

For more discussion see the following:

Using Global Variables in Python Toolbox?

Python toolbox tool objects do not remember instance variables between function calls?

AarthiBalamurugan1
New Contributor

Inside the expression the global value is not working. I want to get the number of row values inside the expression.

0 Kudos
DanPatterson_Retired
MVP Emeritus
expression = '''
   global total_rows
   total_rows=5
   def getCitation(p_dataset_id):
      if(total_rows == 5):
            ds=PanDataSet(p_dataset_id)
   return ds.citation‍‍‍‍‍‍‍‍‍‍‍‍

so this didn't work either?

But I am not sure what it is the script is doing since there is nowhere in the script that collects information to compare to total rows

0 Kudos
AarthiBalamurugan1
New Contributor

No It didn't work as well. I am getting the same error. If it is outside the expression it works.

Right now I am just testing the code whether the global values can be assigned inside the expression.

I am sending the dataset id value to the server to collect the data. Within 30 seconds the server can handle 60 data if it is more than that it stops working.

So I want to get the total number of rows and if it's more than 60 rows I want to delay the processing.

0 Kudos
DanPatterson_Retired
MVP Emeritus

you need to assign an initial value to the global somewhere, like outside the def in your enclosing expression

RandyBurton
MVP Alum

Did you try something like indicating that total_rows was a global in the "execute" function (line 3) below:

def execute(self, parameters, messages):
"""The source code of the tool."""
   global total_rows # indicate that total_rows is a global
   inputdataset = parameters[0].valueAsText #getting the parameters

   count_rows = arcpy.GetCount_management(inputdataset)
   total_rows = int(count_rows.getOutput(0))

expression = '''

   def getCitation(p_dataset_id):
      global total_rows
      if(total_rows == 5):
            ds=PanDataSet(p_dataset_id)
   return ds.citation

'''

I'm also puzzled by the indentation in the code snippet you posted.  Is the "expression" section (lines 9 -17) part of the "execute" function?  It may not be indented properly.

0 Kudos
Luke_Pinner
MVP Regular Contributor

It's a string expression and is evaluated outside the scope of your current code so has no knowledge about any of your variables.

You need to insert the actual value into the string:

class YourTool(object):
    def __init__(self):
        etc...

    def getParameterInfo(self):
        etc...

    def execute(self, parameters, messages):
        """The source code of the tool."""
    
        inputdataset = parameters[0].valueAsText  # getting the parameters
    
        count_rows = arcpy.GetCount_management(inputdataset)
        total_rows = int(count_rows.getOutput(0))
    
        expression = '''
def getCitation(p_dataset_id):
  total_rows = {}
  if(total_rows == 5):
      ds=PanDataSet(p_dataset_id)
      return ds.citation
'''.format(total_rows)
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Note - you can't indent the expression, or it won't be valid python syntax when the tool evaluates it - IndentationError: unexpected indent.  If you want your code to look cleaner and have the expression indented, you can use inspect.cleandoc(expression) 

inspect — Python 2.7 documentation 

inspect — Python 3.8 documentation 

inspect.cleandoc(doc)

Clean up indentation from docstrings that are indented to line up with blocks of code.

All leading whitespace is removed from the first line. Any leading whitespace that can be uniformly removed from the second line onwards is removed. Empty lines at the beginning and end are subsequently removed. Also, all tabs are expanded to spaces.

import inspect

class YourTool(object):
    def __init__(self):
        etc...

    def getParameterInfo(self):
        etc...

    def execute(self, parameters, messages):
        """The source code of the tool."""
    
        inputdataset = parameters[0].valueAsText  # getting the parameters
    
        count_rows = arcpy.GetCount_management(inputdataset)
        total_rows = int(count_rows.getOutput(0))
    
        expression = inspect.cleandoc('''
            def getCitation(p_dataset_id):
                total_rows = {}
                if(total_rows == 5):
                    ds=PanDataSet(p_dataset_id)
                    return ds.citation
        '''.format(total_rows))‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos