I'm creating a script tool inside of a python toolbox (.pyt) and having a frustrating time dealing with files relative to the .pyt file location. This is a very standard thing in python (or really any development project) to have ancillary files in same directory and to access them based on their relative path. For an unexplained reason ArcGIS Pro chooses to change the working directory to an entirely different location from where the .pyt actually is stored. Please tell me I don't have to hardcode a path to access some files...
It looks like you should be able to use either arcpy.env.scriptWorkspace or arcpy.env.packageWorkspace, on my machine those both mapped to the folder that the pyt file is stored in, so like this
import os, sys import arcpy sys.path.append(arcpy.env.packageWorkspace) from taxmap import BuildTaxMap
Both my pyt and script tool versions run with that code.
The logical endpoint of this is the geoprocessing modules feature, which allow you to bundle your Python toolbox(es) as members of a standard Python package. There's a very big learning curve and you're forced to deal with Python's perpetually half-baked build systems but your reward is a fully managed, easy to read bundle of code that you can load into different environments, complete with proper dependency management. And the toolboxes are accessed just like system tools which is pretty slick. Just watch out for using them in web tools, that's a whole other can of worms.
@DonMorrison1 I consider this essential, because it's so very easy to break a PYT file and it's almost impossible to debug them from a normal developer environment.
I put a __version__ number in each file so that I can see what actually loaded. Output looks like this, I use arcpy.AddMessage to report on each at the start of a script.
ormap_script_tool 0.6taxmap 0.8ormapnum 1.1Exported to C:\Temp\pdflib\tp8_9_17CB.pdf
This is what I was looking for. ESRI needs to start thinking a little harder when they put together documentation, something like this definitely should be mentioned in the guide for creating tools in a python toolbox. I wrote this post when I was a pretty frustrated after spending an hour going through their docs trying to find this.
I do something very similar - minimizing the code logic in the .pyt file and reloading the imported files each time. I also set up the tools so they can be easily run from the command line/debugger. For me it lets me organize the code better and makes testing and debugging much easier.
Not sure exactly what you have set up, but I have each of the tools in my python toolbox as separate .py files, in a folder named toolboxscripts that is in the same directory as the .pyt file. I load them in like this:
import sys import os import arcpy from importlib import reload sys.path.append(os.path.join(os.path.dirname(__file__), "toolboxscripts")) #import the individual tool scripts, forcing a reload of any imported tools/modules #otherwise you would have to restart Arc each time you edited an individual tool script #this way you just have to right click -> Refresh the toolbox import pyFilename reload(pyFilename) from pyFilename import classToolName class Toolbox(object): # List of tool classes associated with this toolbox self.tools = [classToolName]
I usually use something like:
from pathlib import Path tool_dir = Path(__file__).parent # Or import os.path tool_dir = os.path.dirname(__file__)
@CarlVricella wrote:... This is a very standard thing in python (or really any development project) to have ancillary files in same directory and to access them based on their relative path...
... This is a very standard thing in python (or really any development project) to have ancillary files in same directory and to access them based on their relative path...
Yes, but... the working directory for a python module or script is never guaranteed to be the directory in which that module or script is located. This is only going to be the case when you run a script or import a module that is located in the same directory as the current working directory.
I have code that uses os.path.dirname(__file__) to find the directory of the current .py file, then access the files based on that. Would that work?
Okay! I won't tell you that. Just put ALL YOUR CODE ALL IN ONE FILE and then paste it into a tiny box in ArcGIS Pro! What could go wrong? Ha ha ha ha. Who cares about version control? ANYWAY
I am working on this problem right now too. I've been fiddling with the differences between Python toolboxes and Script tools the last couple days.
Something that might help you (since I have no real answer for you yet) is to print out the entire environment from inside a tool so you can look at what environment settings you have. This should include BOTH the system environment and the arcpy environment.
Then you can decide if you want to try to force it to use an environment setting in your Python to make it find your modules.
import os import sys import arcpy # HA HA HA YES THIS IS WHAT I DO RIGHT NOW BUT I HATE IT AND WANT TO FIX IT sys.path.append("K:/ORMAP_CONVERSION/ORMAP_PRO") from taxmap import BuildTaxMap def show_environment(): arcpy.AddMessage(f"Current directory: \"{os.getcwd()}\"") arcpy.AddMessage("os environment --------------") for i in sorted(os.environ): arcpy.AddMessage(f"{i}, {os.environ[i]}") arcpy.AddMessage("arcpy environment --------------") for i in sorted(arcpy.env): arcpy.AddMessage(f"{i}, {arcpy.env[i]}") return # Then call that function, in a PYT you can call it from "execute" # or from a script tool, from the "main" section if __name__ == "__main__": # This code executes every time you run the tool # from the toolbox, not just from the debugger. show_environment()
I will try to post something more definitive later but now I have to go fix a printing problem in a web app. Grr.
Les membres connectés peuvent publier, suivre les mises à jour, et plus encore. Nouveau ici ? Inscrivez-vous gratuitement.
Find useful guides, FAQs, and documents to help you navigate and make the most of Esri Community.