Select to view content in your preferred language

Map Automation - Seeking Scripting Solution for Opening an APRX from Python IDLE

253
5
2 weeks ago
CMorneau
Occasional Contributor

ArcGIS Pro 3.4.3

Hello! I am developing a Python script that is intended to be run outside of an ArcGIS Pro session (e.g., from Python IDLE). The script copies an APRX to a different folder & renames it. It contains seven template layouts, each of which are renamed by the script per customer requirements. Likewise, the script updates a few text elements & resizes/repositions additional elements (rectangle graphics, legends, etc.). So far, so good - works great.

Ideally, though, I'd also like the script to automatically open the APRX in Pro once it has completed & saved all of the updates. I cannot figure out the coding to do so. After the last elements are updated, I execute save(). But if I also run os.system("start " + aprx), where aprx has been defined with a correctly formatted filepath, an error message is returned basically stating no-can-do, that the file is already in use by another application. From what I can tell, Python IDLE is that very application.

Of course, I could click-open my copied APRX directly from File Explorer or call it upon opening Pro. But for efficiency's sake, I want to bundle that operation with the map automation script. Note: in my script, I start with importing the arcpy, shutil, & os modules. Note also: I'm not an experienced Python programmer, so forgive me if the answer is painfully obvious. Hopefully, a solution for this posting will help not only me, but others at my level of experience. Thank you.

0 Kudos
5 Replies
CodyPatterson
MVP Regular Contributor

Hey @CMorneau 

You're definitely correct that Python is maintaining a lock on the file so it cannot be opened. I've had similar issues doing something pretty close to this. Would it be possible to share a snippet of your code?

From what I've done, I think it's possible to use Python's del functionality to delete an object. It would be used something like this:

aprx = arcpy.mp.ArcGISProject(target_aprx)

# Do your things around here

del aprx

time.sleep(1) # 1 second sleep to make sure that the object is deleted

# I would have the os.system attempt to open the file here

This is one of the ways that I've gotten it to work, del will not remove the file but remove the object itself, here is documentation for that, hopefully it works!

https://www.w3schools.com/python/ref_keyword_del.asp

Cody

0 Kudos
CMorneau
Occasional Contributor

Thank you, Cody.  Yesterday, I had given some thought to trying del aprx, but I ran out of time.  I'll give that a try today, along with time.sleep(1).  That's interesting - I have not seen that before, so I appreciate learning something new.  Also, thank you for sharing the link to the w3schools site.

Per your request, below is a shortened & annotated version of my script:

import shutil, arcpy, os

# Enter parameters: Ticket, Case, Project, Project Folder, etc.:
Ticket = '123456'
Case = 'RPPL2025123456' # Case #
CaseType = 'CUP' # Case type
ProjectNum = 'PRJ-123456'

DestFolder = r'C:\GIS\PROJECTS\GIS_Public_Hearing_Maps\Projects' # From internal customer request

# APRX with seven template layouts:
Source = r'C:\GIS\PROJECTS\DRP_CURRENT_PLANNING\GIS_Public_Hearing_Maps\Hearing_Maps_Templates_Standard.aprx'

# Create the variable APRX:
APRX = DestFolder + '\\' + Case + '_T' + Ticket + '.aprx'
print(APRX) # To verify correct formatting.

# Copy & rename the APRX (see below for results):
shutil.copyfile(Source, APRX)

# Rename the layouts:
p = arcpy.mp.ArcGISProject(APRX)
CaseTicket = Case + '_' + Ticket
for lyt in p.listLayouts():
oldName = lyt.name
nameRep = oldName.replace('Template_8x11', CaseTicket)
lyt.name = nameRep

# Not included in this snippet are all the subsequent steps to update &/or reposition elements in each of the seven layouts. Coding for these steps works fine.

p.save()

os.system("start " + APRX) # This doesn't work while the Python IDLE is still open with the above script. It throws an error message saying that the file is already in use (Python IDLE appears to have the lock on it).

# But this works fine for opening the APRX in read+write mode when the Python IDLE session is closed & re-opened:
import arcpy, shutil, os
aprx = r'C:\GIS\PROJECTS\GIS_Public_Hearing_Maps\Projects\RPPL2025123456_T123456.aprx'
os.system("start " + aprx)

 

0 Kudos
CMorneau
Occasional Contributor

Attached is a better view of it from Notepad++:

 

0 Kudos
CMorneau
Occasional Contributor

Thus far, I have not been successful with this proposed solution.  Quite possibly, it cannot be done.  I stumbled upon an 03-20-2024 reply from Esri's Robert LeClair on a posting entitled arcpy.mp.ArcGISProject .aprx lock issue.  In it, he wrote the following:

So there was an enhancement request, ENH-000140298 - Add a method to the arcpy.mp.ArcGISProject() object that will close the project and release locks held by a script. But it was marked as "will not be addressed." The explanation was "Locks on a project file can be eliminated by either closing the Python shell (vs the script editor) or by calling del on the appropriate variables. The method has little value when run in a script outside of the application and also inside the application."

0 Kudos
RhettZufelt
MVP Notable Contributor

Not where I can test, but I have overcome file locking issues like this before using *.bat files.

I create a python script that similar to:

import arcpy, os

modify = r"D:\path\to\batchfile\modify_aprx.bat"
open_aprx = r"D:\path\to\batchfile\open_aprx.bat"
aprx = r"D:\path\to\projectfile\filename.aprx"

os.system(modify )
os.system("start " + aprx)

The modify_aprx.bat file will have something similar to:

 Run my Python script
call "%PROGRAMFILES%\ArcGIS\Pro\bin\Python\Scripts\propy" "D:\path\to\script\modify_aprx.py"
@echo Finished

Where modify_aprx.py is your python script that does the work.

So, the python that is doing the work is running in the first system shell, and once it is done, it closes and deletes/removes all locks/links to the data.

Then, it should be 'free' to open after the first cmd closes.

R_

 

 

 

0 Kudos