1

I've built a tool that will be used to populate required metadata in the attributes of a specific schema. This tool is in a python toolbox and called by a python addin button.

The value entered for each input is saved to a text file to be used as the default for the next run of the tool.

All of this works, but as I understand it, the tool is only loaded once when ArcMap opens. So even when you change the input and run it, the old values are still used as the tool defaults until ArcMap is restarted.

I've tried loading the toolbox as a temp file posted here but that breaks the reference to the toolbox and text file location, which is based on the addin_addin.py location.

I've also tried to store/load new defaults with the ConfigParser from memory, but this isn't working for me either.

What I need is for the input values from each run of the tool to be set as the defaults for the next run without the user having to do anything.

I would prefer to find a way to refresh the toolbox or store defaults in memory until ArcMap is restarted over loading a temporary toolbox and finding a new way to reference the locations.

I'm also open to novel solutions.

Addin:

class populateAttributes(object):
"""Implementation for addin_addin.populateAttributes_button (Button)"""
def __init__(self):
    self.enabled = True
    self.checked = False
def onClick(self):
    try:
        relPath = os.path.dirname(__file__)
        toolboxPath = os.path.join(relPath,"IncidentToolbox.pyt")

        pythonaddins.GPToolDialog(toolboxPath, "populateReqAttributes")

    except SystemExit:
        pass
    except:
        traceback.print_exc()
        pythonaddins.MessageBox("Somethings gone horribly wrong, sorry.", "Populate Attributes")

Get Parameters:

relPath = os.path.dirname(__file__)
iniPath = os.path.join(relPath,"incidentTools.ini")

def getParameterInfo(self):
    """Define parameter definitions"""

    default_incidentName = None
    default_irwinid = None
    default_unitID = None
    default_localIncidentID = None
    default_gacc = None
    default_imtName = None
    default_contactName = None
    default_contactEmail = None
    default_contactPhone = None

    config = ConfigParser.SafeConfigParser()

    try:
        default_incidentName = config.get("incidentAttributes","incidentName")
        default_irwinid = config.get("incidentAttributes","irwinid")
        default_unitID = config.get("incidentAttributes","unitID")
        default_localIncidentID = config.get("incidentAttributes","localIncidentID")
        default_gacc = config.get("incidentAttributes","gacc")
        default_imtName = config.get("incidentAttributes","imtName")
        default_contactName = config.get("incidentAttributes","contactName")
        default_contactEmail = config.get("incidentAttributes","contactEmail")
        default_contactPhone = config.get("incidentAttributes","contactPhone")
        print "defaults set from in memory"

    except:
        if os.path.exists(iniPath):
            config.read(iniPath)

            if "incidentAttributes" in config.sections():
                try:
                    default_incidentName = config.get("incidentAttributes","incidentName")
                    default_irwinid = config.get("incidentAttributes","irwinid")
                    default_unitID = config.get("incidentAttributes","unitID")
                    default_localIncidentID = config.get("incidentAttributes","localIncidentID")
                    default_gacc = config.get("incidentAttributes","gacc")
                    default_imtName = config.get("incidentAttributes","imtName")
                    default_contactName = config.get("incidentAttributes","contactName")
                    default_contactEmail = config.get("incidentAttributes","contactEmail")
                    default_contactPhone = config.get("incidentAttributes","contactPhone")
                    print "defaults set from file"
                except:
                    print "default value missing"


    # IncidentName
    param0 = arcpy.Parameter(
        displayName="Incident Name",
        name="incidentName",
        datatype="GPString",
        parameterType="Required",
        direction="Input")
    if default_incidentName:
        param0.value = default_incidentName

    # IRWINID
    param1 = arcpy.Parameter(
        displayName="IRWINID",
        name="irwinid",
        datatype="GPString",
        parameterType="Required",
        direction="Input")
    if default_irwinid:
        param1.value = default_irwinid

    # UnitID
    param2 = arcpy.Parameter(
        displayName="Unit ID",
        name="unitID",
        datatype="GPString",
        parameterType="Required",
        direction="Input")
    if default_unitID:
        param2.value = default_unitID

    # LocalIncidentID
    param3 = arcpy.Parameter(
        displayName="Local Incident ID",
        name="localIncidentID",
        datatype="GPString",
        parameterType="Required",
        direction="Input")
    if default_localIncidentID:
        param3.value = default_localIncidentID

    # GACC
    param4 = arcpy.Parameter(
        displayName="GACC",
        name="gacc",
        datatype="GPString",
        parameterType="Required",
        direction="Input")
    if default_gacc:
        param4.value = default_gacc

    # IMTName
    param5 = arcpy.Parameter(
        displayName="IMT Name",
        name="imtName",
        datatype="GPString",
        parameterType="Required",
        direction="Input")
    if default_imtName:
        param5.value = default_imtName

    # ContactName
    param6 = arcpy.Parameter(
        displayName="Contact Name",
        name="contactName",
        datatype="GPString",
        parameterType="Required",
        direction="Input")
    if default_contactName:
        param6.value = default_contactName

    # ContactEmail
    param7 = arcpy.Parameter(
        displayName="Contact Email",
        name="contactEmail",
        datatype="GPString",
        parameterType="Required",
        direction="Input")
    if default_contactEmail:
        param7.value = default_contactEmail

    # ContactPhone
    param8 = arcpy.Parameter(
        displayName="Contact Phone",
        name="contactPhone",
        datatype="GPString",
        parameterType="Required",
        direction="Input")
    if default_contactPhone:
        param8.value = default_contactPhone

    params = [param0, param1, param2, param3, param4, param5, param6, param7, param8]
    return params
7
  • 1
    Did you think about writing your parameters to a txt file, and then rereading it on when the tool is started? So why not simply rewrite the file every time to have fresh settings.
    – Piskr
    Commented Feb 20, 2018 at 23:22
  • 1
    The way @Piskr describes is how I have done that in one application and it seems to work well.
    – PolyGeo
    Commented Feb 20, 2018 at 23:25
  • Thanks @Piskr for the suggestion. I actually do write the txt file fresh each time the tool is run. There's something about how the class is loaded only at the start of ArcMap because it's an addin that caches the values at that point and wont update with subsequent opening of the tool.
    – merlin
    Commented Feb 20, 2018 at 23:34
  • If text files dont update as usual it means that somewhere something isn't being closed and therefor comes to lock problems, where different processes are trying to accesses the same file, while 1 is reading and the other 1 is writing.
    – Piskr
    Commented Feb 20, 2018 at 23:37
  • @Piskr. The txt file updates fine. It's the default values that show up in the tool dialog that are not updating. Closing and reopening ArcMap will refresh them.
    – merlin
    Commented Feb 20, 2018 at 23:40

2 Answers 2

1

I would write the settings on the tool finish:

def writeParameters(parameters):
   #gets array of parameters
   fil = fopen('parms.txt','w')

   #then loop and write
   for parm in parameters:
       fil.write(str(parm) +'\n')

   #dont forget to close up that file behind you
   fil.close()

And reread them on tool start:

def readParameters():
    with open('parms.txt') as fil:
        content = fil.readlines()
    return content
0

ArcGIS only loads the toolbox once, I assume to improve performance. I workaround this by making a temporary copy of the toolbox every time I want to call it.

import os, sys  
import glob  
import shutil  
import tempfile  
import threading  
import time  

import arcpy, pythonaddins  

class Button(object):  
    # ...  
    def onClick(self):  
        GPToolDialog('path/to/toolbox.pyt', 'ToolName')  

def GPToolDialog(toolbox, tool):  
    """ 
         * Workaround for NIM089253 - "TypeError: GPToolDialog() takes at most 1 argument (2 given) 
           http://support.esri.com/en/bugs/nimbus/TklNMDg5MjUz 
         * Workaround for defaults only refreshing on first run - copy the pyt (and xml docs) 
           which forces Arc to reload it every time. 
    """  
    tmpdir = tempfile.mkdtemp(prefix='toolbox')  
    tmpfile = os.path.join(tmpdir,os.path.basename(toolbox))  
    docs=glob.glob(toolbox[:-4]+'*.xml')  
    shutil.copy(toolbox,tmpdir)  
    for doc in docs:shutil.copy(doc,tmpdir)  
    try:  
        result=pythonaddins.GPToolDialog(tmpfile,tool)  
    except TypeError:  
        pass  
    finally:  
        #Give ArcMap time to load the toolbox before it gets cleaned up  
        threading.Thread(target=rm, args = (tmpdir,3)).start()  
        return None  

def rm(d, wait=1):  
    time.sleep(wait)  
    try: shutil.rmtree(d)  
    except: pass  
2
  • As I posted, I'm aware of this solution and looking for alternatives. I will be using this as a last resort, likely with an added input for the original toolbox dirname for the parameter txt file. Thanks.
    – merlin
    Commented Feb 21, 2018 at 15:31
  • @merlin there are no alternatives. The only way to set the defaults is when the toolbox is imported by ArcGIS and that only happens once. You need to use the temp toolbox method and read the defaults from a text file. Just store the ini in a known location like %APPDATA%/yourtool.ini
    – user2856
    Commented Feb 21, 2018 at 19:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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