Execute Python 2 Code via Python 3

13596
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 think I figured out how to get past this issue too, thanks to your comment, the information from Curtis and Joshua, and some online investigation into the error code from the screenshot above.  I added the following bold text to the environment parameter of my popen line:

process = subprocess.Popen(result + "\\python.exe C:\\temp\\python\\ListMXDDataSources.py", stdout=subprocess.PIPE, stderr=subprocess.PIPE, creationflags = CREATE_NO_WINDOW, shell=True, env={'PATH': result, 'SYSTEMROOT': 'C:\windows'}

Below is where things currently stand when I run my code as of now.  I think I'm getting much closer now.  Thank you to everyone.  

0 Kudos
JoshKalov
New Contributor III

You have already set the PATH in env so this may not be your issue, but I have gotten a python2 call from python3 to work by doing a os.environ.copy() first before updating the path.

replica_sync_command = f"C:\\Python27\\ArcGIS10.4\\python.exe c:\\syncReplica_python2.py"
python2_env = os.environ.copy()
python2_env.update({"PATH": "C:\\Python27\\ArcGIS10.4"})
run_sync = subprocess.run(replica_sync_command.split(), env=python2_env, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)‍‍‍‍‍‍‍‍‍‍‍‍
diaconori
New Contributor III

Gives me a [WinError 2] message...

replica_sync_command = r'"C:\Python27\ArcGIS10.5\python.exe" "C:\Users\n1mdno\OneDrive - Aalborg Kommune\Dokumenter\aak-gis-tools\Utility\Georeferencing\PDF to TIF\pdf_to_tif_mxd.py" {0}'.format(
str([is_wrapped_pdf, wrapped_pdf_input, wrapped_situation_plan_page_number,
wrapped_floor_plan_page_number,
is_separate_pdf, separate_pdf_situation_plan,
separate_situation_plan_page_number, separate_pdf_floor_plan,
separate_pdf_floor_plan_page_number]))
python2_env = os.environ.copy()
python2_env.update({"PATH": r"C:\Python27\ArcGIS10.5\python.exe"})
run_sync = subprocess.run(replica_sync_command.split(), env=python2_env, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, universal_newlines=True)

 

0 Kudos
by Anonymous User
Not applicable

This is a longshot but would something similar work for running a python 3 script from python 2?

0 Kudos
Josh-R
by
New Contributor III

This works! I was able to run a python 2 script via a bat file within a subprocess.call() inside a python 3 script using this method. Thank you!

0 Kudos
JoshuaBixby
MVP Esteemed Contributor

William Craft‌, how exactly are you executing your Python 3 script?  I just took the original code you posted when you first opened this thread and it runs fine for me with some test MXDs:

(arcgispro-py3) C:\Program Files\ArcGIS\Pro\bin\Python\envs\arcgispro-py3>python D:\tmp\ListWrapper.py
Finding Python 2.7 installation directory...
Launching Python 2.7 executable...
Layer, wwf_terr_biome_type_smooth

WARNING:

(arcgispro-py3) C:\Program Files\ArcGIS\Pro\bin\Python\envs\arcgispro-py3>
WilliamCraft
MVP Regular Contributor

I'm running it from ArcGIS Pro's catalog view via a custom toolbox/toolset.  There seems to be an issue with referencing the map document file when creating the MXD object.  Are you running the code within the Python window in ArcGIS Pro?  

0 Kudos
JoshuaBixby
MVP Esteemed Contributor

I ran the code from the "Python Command Prompt" shortcut that is created when Pro is installed.  That shortcut just takes care of activating the correct/default Pro Python environment.  If you run your code from that command prompt, does it generate an error?

WilliamCraft
MVP Regular Contributor

Doing it the way you suggested still yields the same error for me: "RuntimeError: Object: CreateObject cannot open map document".  Looks like maybe our environments are different enough where it'll run for you but not me.  I am curious why my environment prevents the MXD object from being created.  Thanks for looking into this a bit more.  Much appreciated.  

0 Kudos
JoshuaBixby
MVP Esteemed Contributor

The RuntimeError you are now experiencing might be caused by a problematic MXD, not a Python 2/3 environment issue.  Are you getting the RuntimeError with any/all MXDs?  Can you try just a single MXD in a directory.