Execute Python 2 Code via Python 3

13591
28
Jump to solution
12-26-2019 11:58 AM
WilliamCraft
MVP Regular Contributor

I am trying to wrap some Python 2 code into Python 3 but having trouble getting the process to work correctly.  From ArcGIS Pro, I'm running a custom GP tool with the following code as its script.  My goal is to run my Python 2 code (stored in a separate script) against a series of MXDs in order to list the data source for each layer or table.  In my case, doing it this way yields no results.  The code runs in about 2 seconds and then terminates.  Any ideas?  

PYTHON 3 SCRIPT (WRAPPER)

import subprocess, os, winreg, sys, arcpy

try:
   arcpy.AddMessage("Finding Python 2.7 installation directory...")
   hKey = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE,    "SOFTWARE\\WOW6432Node\\Python\\PythonCore\\2.7\\InstallPath")
   result = winreg.QueryValueEx(hKey, "")[0]
except:
   arcpy.AddWarning("Python 2.7 installation directory was not found.")
   arcpy.AddError("Script failed.")
   sys.exit()

if os.path.exists(result + "\\python.exe"):
   arcpy.AddMessage("Launching Python 2.7 executable...")
   CREATE_NO_WINDOW = 0x8000000
   process = subprocess.Popen([result + "\\python.exe", "C:\\temp\\python\\ListMXDDataSources.py"],    stdout=subprocess.PIPE, stderr=subprocess.PIPE, creationflags = CREATE_NO_WINDOW, shell=True, stdin=None)
   stdout, stderr = process.communicate()
   arcpy.AddMessage('{}'.format(stdout.decode("utf-8")))
   arcpy.AddWarning('{}'.format(stderr.decode("utf-8")))

PYTHON 2 SCRIPT

import arcpy, glob

rootDirectory = 'C:/temp'
fileExtension = '.mxd'

def main():
   for f in glob.glob(rootDirectory + '/*' + fileExtension):
      mxd = arcpy.mapping.MapDocument(f)
      for df in arcpy.mapping.ListDataFrames(mxd, ''):
         for lyr in arcpy.mapping.ListLayers(mxd, '', df):
            if not lyr.isGroupLayer:
               if lyr.isRasterLayer:
                  print "Raster Layer, {}".format(lyr)
               elif lyr.isFeatureLayer:
                  print "Feature Layer, {}, {}".format(lyr, lyr.serviceProperties)
               else:
                  print "Layer, {}".format(lyr)
         for tbl in arcpy.mapping.ListTableViews(mxd, '', df):
            print "Table, {}".format(tbl.dataSource)

if __name__ == '__main__':
   main()

Tags (1)
28 Replies
WilliamCraft
MVP Regular Contributor

I tried it with a newly-created, simple MXD containing a feature class from a FGDB and a basemap.  I also tried this on another computer, both having the same version of ArcGIS Pro 2.4; one computer had ArcGIS Desktop 10.6.1 and the other had 10.7.1.  Same result on both machines.  I'm so confused.  

0 Kudos
WilliamCraft
MVP Regular Contributor

In the Python 2 script, I added an os.startfile(f) line of code to launch the 10.6 MXD interactively just to see what issues may arise.  The following errors are found when taking this approach:

I have tried deleting my Normal.mxt but that only eliminates the first error shown above.  I can open this map document just fine by double clicking on it from Windows Explorer.  

0 Kudos
JoshuaBixby
MVP Esteemed Contributor

I was able to use os.startfile() from both a Python 2 (ArcMap Python) and Python 3 (Pro Python) command prompt to open multiple MXDs in ArcMap.  I say this just to say it isn't an issue with os.startfile(), so resolving these errors might be a good step in resolving your larger issue.

WilliamCraft
MVP Regular Contributor

This may sound silly, but could you create a basic 10.6.1 or 10.7.1 MXD with just a basemap layer and post it here?  I'd like to download it and try that MXD with my script since none of the MXDs I create on my end seem to work.  

0 Kudos
JoshuaBixby
MVP Esteemed Contributor

Created in 10.7.1.

WilliamCraft
MVP Regular Contributor

Thanks for doing this.  It's amazing that it still yields the same error even with just this MXD in play.  I can open the MXD just fine by myself.  Something in my environment (on both computers) must be in play that I'm not realizing.  Thanks for your time in trying to help me.  

0 Kudos
WilliamCraft
MVP Regular Contributor

In the end, Josh Kalov's answer about copying the entire os.environ was what resolved my arcpy.mapping issues.  I wish I could give a correct answer to several people for their help along the way, especially to Joshua Bixby for hanging in there with me for so long, but I can only mark one answer as correct unfortunately.  Thank you to everyone for their help.  

curtvprice
MVP Esteemed Contributor

I wish I could give a correct answer to several people for their help along the way,

#meta

This thread is another of those geonet success stories where you not only get the answer to do this thing, you also get some useful background in the thread.

I think you tagged the right one and in the right way!  Helpfuls are thanks enough and are also very useful to me when I read a thread as they 'underline' the most useful information to learn in a thread, when one wants to learn why the correct answer solved the problem!

AlfredBaldenweck
MVP Regular Contributor

Necrobumping this a bit.

I was able to get it to work using JoshKalov's solution, but by updating the PYTHONPATH, not the PATH.

(PATH gives the error seen in this post: Solved: Re: Execute Python 2 Code via Python 3 - Esri Community)

Here's my code:

import arcpy
import subprocess 

'''3.X Code'''
# Code
# Code

'''Run 2.7'''
# The path to your Python 2.7 executable.
cmdPath= r"C:\Python27\ArcGIS10.8\python.exe"
# The file you're trying to execute.
pyPath = r"U:\...\ReplaceDS_Arcmap2_7.py"

# Switch from P3 to P2.7.
python2_env = os.environ.copy()
python2_env.update({"PYTHONPATH": r"C:\Python27\ArcGIS10.8", 
                    'SYSTEMROOT': 'C:\Windows'})
# Run the file.
subprocess.run([cmdPath, pyPath], 
               env=python2_env, 
               shell= True,  
               stdout=subprocess.PIPE, 
               stderr=subprocess.PIPE, 
               universal_newlines=True)

Hopefully this helps someone out in the future!

0 Kudos