Script tool parameters for a file that can be created or appended.

495
4
Jump to solution
08-13-2023 07:18 AM
SzymAdamowski
New Contributor III

I'd like to assign path to some file (let's say it's a log file) in a script tool as a parameter. This file may already exist (some information might have been written and I don't want to lose it) or may not (then I want to create it).

Now - if I set Direction to Input in Tool Properties  -> Parameters - then it is only possible to point to existing file (it won't allow me to create a new name). If I set Direction to Output then I can create new file, but if I point to old one, it will automatically overwrite it (not what I want as I want to retain the contents of the file)

SzymAdamowski_0-1691935730607.png

Is there any smart way to make the tool parameter to behave the way I want?

Tags (2)
0 Kudos
1 Solution

Accepted Solutions
StaticK
MVP

Matrix glitched and the JeffK account was deleted...

Ok, sure. Didn't know that the Folder/File dialog was a requirement but with that, get the folder first using the Folder Datatype, then list the files for folder selected through the ToolValidator class. The user can select one from the list if it does exists or type in a file name if it doesn't exist. New files will have to be typed in- how would you select something that doesn't exist? You can include/exclude the returned files list by extension or name in the ToolValidator to narrow the selection down.

StaticK_0-1692184097719.png

StaticK_0-1692276444251.png

 

import os

class ToolValidator:
  # Class to add custom behavior and properties to the tool and tool parameters.

    def __init__(self):
        # set self.params for use in other function
        self.params = arcpy.GetParameterInfo()
        self.fileNames = []
        
    def initializeParameters(self):
        # Customize parameter properties. 
        # This gets called when the tool is opened.
        
        return

    def updateParameters(self):
        # Modify parameter values and properties.
        # This gets called each time a parameter is modified, before 
        # standard validation.
        
               
        if self.params[0].altered:
            fileFilter = self.params[1].filter # <- change this param to the country list parameter index.

            # use list comprehension and set to return a distinct list of file names.
            self.fileNames = [filenames for filenames in os.listdir(self.params[0].valueAsText) if os.path.isfile(os.path.join(self.params[0].valueAsText, filenames))]
           
            fileFilter.list = self.fileNames
        if self.params[1].altered:
            if self.params[1].valueAsText not in self.fileNames:
                self.fileNames.append(self.params[1].valueAsText)
                fileFilter.list = self.fileNames       
        return

    def updateMessages(self):
        # Customize messages for the parameters.
        # This gets called after standard validation.
        return

    def isLicensed(self):
    # set tool isLicensed.
        return True

    def postExecute(self):
        # This method takes place after outputs are processed and
        # added to the display.
        return
import os
"""
Script documentation

- Tool parameters are accessed using arcpy.GetParameter() or 
                                     arcpy.GetParameterAsText()
- Update derived parameter values using arcpy.SetParameter() or
                                        arcpy.SetParameterAsText()
"""
import arcpy


def script_tool(filePath, fileName):
    """Script code goes below"""
    arcpy.AddMessage(f'param1: {filePath} param2: {fileName}')
    outPath = os.path.join(filePath, fileName)
    
    file_type = 'w' if not os.path.exists(outPath) else 'a'
    
    with open(outPath, file_type) as tFile:
        tFile.write(f'hello dude\n')


if __name__ == "__main__":
    
    filePath = arcpy.GetParameterAsText(0) if arcpy.GetParameterAsText(0) else None
    fileName = arcpy.GetParameterAsText(1) if arcpy.GetParameterAsText(1) else None
    
    
    script_tool(filePath, fileName)

 

View solution in original post

4 Replies
by Anonymous User
Not applicable

You need to handle that in your script logic. Set the parameter to input, and use it the code

import arcpy


def script_tool(fileName, filePath):
    """Script code goes below"""

    file_type = 'w' if not os.path.exists(filePath) else 'a'

    with open(filePath, file_type) as tFile:
        tFile.write(f'hello dude {fileName}\n')


if __name__ == "__main__":

    fileName = arcpy.GetParameterAsText(0)
    filePath = arcpy.GetParameterAsText(1)

    script_tool(fileName, filePath)

 

0 Kudos
SzymAdamowski
New Contributor III

I am aware that I'll have to handle file creation or appending in script. My question is related to parameter  Data Type. I'd like to use Data Type = File (as shown in the screenshot) so that I can take advantage of ArcGIS file selecting window and logic (i.e. I can also filter files by extension). In your example you suggest separate parameters for fileName and filePath (but it looks like filePath contains full path to the file, including its name, and fileName is just used to write the data). What Data Type would you suggest for filePath parameter? Of course using string Data Type would be a workaround - but definitely not a smart one - as there would be no window dialog.

0 Kudos
StaticK
MVP

Matrix glitched and the JeffK account was deleted...

Ok, sure. Didn't know that the Folder/File dialog was a requirement but with that, get the folder first using the Folder Datatype, then list the files for folder selected through the ToolValidator class. The user can select one from the list if it does exists or type in a file name if it doesn't exist. New files will have to be typed in- how would you select something that doesn't exist? You can include/exclude the returned files list by extension or name in the ToolValidator to narrow the selection down.

StaticK_0-1692184097719.png

StaticK_0-1692276444251.png

 

import os

class ToolValidator:
  # Class to add custom behavior and properties to the tool and tool parameters.

    def __init__(self):
        # set self.params for use in other function
        self.params = arcpy.GetParameterInfo()
        self.fileNames = []
        
    def initializeParameters(self):
        # Customize parameter properties. 
        # This gets called when the tool is opened.
        
        return

    def updateParameters(self):
        # Modify parameter values and properties.
        # This gets called each time a parameter is modified, before 
        # standard validation.
        
               
        if self.params[0].altered:
            fileFilter = self.params[1].filter # <- change this param to the country list parameter index.

            # use list comprehension and set to return a distinct list of file names.
            self.fileNames = [filenames for filenames in os.listdir(self.params[0].valueAsText) if os.path.isfile(os.path.join(self.params[0].valueAsText, filenames))]
           
            fileFilter.list = self.fileNames
        if self.params[1].altered:
            if self.params[1].valueAsText not in self.fileNames:
                self.fileNames.append(self.params[1].valueAsText)
                fileFilter.list = self.fileNames       
        return

    def updateMessages(self):
        # Customize messages for the parameters.
        # This gets called after standard validation.
        return

    def isLicensed(self):
    # set tool isLicensed.
        return True

    def postExecute(self):
        # This method takes place after outputs are processed and
        # added to the display.
        return
import os
"""
Script documentation

- Tool parameters are accessed using arcpy.GetParameter() or 
                                     arcpy.GetParameterAsText()
- Update derived parameter values using arcpy.SetParameter() or
                                        arcpy.SetParameterAsText()
"""
import arcpy


def script_tool(filePath, fileName):
    """Script code goes below"""
    arcpy.AddMessage(f'param1: {filePath} param2: {fileName}')
    outPath = os.path.join(filePath, fileName)
    
    file_type = 'w' if not os.path.exists(outPath) else 'a'
    
    with open(outPath, file_type) as tFile:
        tFile.write(f'hello dude\n')


if __name__ == "__main__":
    
    filePath = arcpy.GetParameterAsText(0) if arcpy.GetParameterAsText(0) else None
    fileName = arcpy.GetParameterAsText(1) if arcpy.GetParameterAsText(1) else None
    
    
    script_tool(filePath, fileName)

 

SzymAdamowski
New Contributor III

Thank you for the code, it works excatly as I wish. Below is the code for ToolValidator with small modification - I wanted to filter files by extensions so I introduced self.extensionsFilter list defined in __init__ function to achieve this.

import os

class ToolValidator:
  # Class to add custom behavior and properties to the tool and tool parameters.

    def __init__(self):
        # set self.params for use in other function
        self.params = arcpy.GetParameterInfo()
        self.fileNames = []
        self.extensionsFilter=['.txt','.log'] #list of allowed extensions should be with dots and in lowercase. 
        #It can be also empty list, no filtering will be applied then.
        
    def initializeParameters(self):
        # Customize parameter properties. 
        # This gets called when the tool is opened.
        
        return

    def updateParameters(self):
        # Modify parameter values and properties.
        # This gets called each time a parameter is modified, before 
        # standard validation.
        
               
        if self.params[0].altered:
            fileFilter = self.params[1].filter # 

            # use list comprehension and set to return a distinct list of file names.
            if len (self.extensionsFilter)>0:  #only files matching extension list should be returned
                self.fileNames = [filename for filename in os.listdir(self.params[0].valueAsText)
                 if os.path.isfile(os.path.join(self.params[0].valueAsText, filename))
                 and os.path.splitext(filename)[1].lower() in self.extensionsFilter ]
            else: #all files should be returned
                self.fileNames = [filename for filename in os.listdir(self.params[0].valueAsText)
                 if os.path.isfile(os.path.join(self.params[0].valueAsText, filename))]
           
            fileFilter.list = self.fileNames
        if self.params[1].altered:
            if self.params[1].valueAsText not in self.fileNames:
                self.fileNames.append(self.params[1].valueAsText)
                fileFilter.list = self.fileNames       
        return

    def updateMessages(self):
        # Customize messages for the parameters.
        # This gets called after standard validation.
        return

    # def isLicensed(self):
    #     # set tool isLicensed.
    # return True

    # def postExecute(self):
    #     # This method takes place after outputs are processed and
    #     # added to the display.
    # return
0 Kudos