How to pass default version value in Python script tool using saveACopy method?

1027
6
Jump to solution
09-07-2021 05:43 PM
JoeBryant1
Occasional Contributor II

I've created a new script tool for saving down MXDs to previous release versions as explained here.

I'm using ArcMap 10.7.1. I'd like this tool to also save down MXDs higher than my current release to my current version (i.e. save 10.8 MXDs to 10.7). I am under the impression that this is supported (https://desktop.arcgis.com/en/arcmap/10.7/map/working-with-arcmap/saving-a-map.htm).

According to the saveACopy method documentation, passing the default value for the version parameter will save MXDs at your current release version. And the version parameter explanation states: (The default value is None).

However, I cannot figure out how to pass the default value using my script tool. I've tried version = str(), version = None, version = "None", and version = "". All of these result in a ValueError: Invalid value for version: '' (choices are: ['10.1', '10.0', '8.3', '10.5', '10.4', '10.6', '9.0', '10.3', '9.2', '9.3']).

I've also tried just leaving off the optional version parameter. The script tool will run, but when I attempt to open the new MXD, it has not been saved down and tells me that the MXD needs to be saved down using Save A Copy.

JoeBryant1_0-1631061513753.png

Here's my current script:

 

import arcpy, sys, os, string

mxdList = string.split(arcpy.GetParameterAsText(0), ";")
outloc = arcpy.GetParameterAsText(1)
version = arcpy.GetParameterAsText(2)

suffix = "_"+ version.replace(".", "")

for item in mxdList:
item = item.strip('\'')
mxd = arcpy.mapping.MapDocument(item)
base = os.path.basename(item)
baseName = os.path.splitext(base)[0]
if version:
base = os.path.splitext(base)[0] + suffix + os.path.splitext(base)[1]
mxd.saveACopy(outloc + os.sep + base, version)
arcpy.AddMessage(os.path.basename(item) + " has been converted")
else:
mxd.saveACopy(outloc + os.sep + baseName + "_107.mxd")
arcpy.AddMessage(os.path.basename(item) + " has been converted")

Tags (3)
0 Kudos
1 Solution

Accepted Solutions
DanPatterson
MVP Esteemed Contributor

From further down the list it shows that you should be able to specify the value eg "10.6" for version 10.6 If that isn't working, try ....saveACopy(....., version="10.6")

saveACopy (file_name, {version})
ParameterExplanationData Type
file_name

A string that includes the location and name of the output map document (.mxd).

String
version
 

A string that sets the output version number. The default value will use the current version.

  • 10.6 —Version 10.6
  • 10.5 —Version 10.5
  • 10.4 —Version 10.4
  • 10.3 —Version 10.3
  • 10.1 —Version 10.1/10.2
  • 10.0 —Version 10.0
  • 9.3 —Version 9.3
  • 9.2 —Version 9.2
  • 9.0 —Version 9.0/9.1
  • 8.3 —Version 8.3

(The default value is None)


... sort of retired...

View solution in original post

0 Kudos
6 Replies
DanPatterson
MVP Esteemed Contributor

From further down the list it shows that you should be able to specify the value eg "10.6" for version 10.6 If that isn't working, try ....saveACopy(....., version="10.6")

saveACopy (file_name, {version})
ParameterExplanationData Type
file_name

A string that includes the location and name of the output map document (.mxd).

String
version
 

A string that sets the output version number. The default value will use the current version.

  • 10.6 —Version 10.6
  • 10.5 —Version 10.5
  • 10.4 —Version 10.4
  • 10.3 —Version 10.3
  • 10.1 —Version 10.1/10.2
  • 10.0 —Version 10.0
  • 9.3 —Version 9.3
  • 9.2 —Version 9.2
  • 9.0 —Version 9.0/9.1
  • 8.3 —Version 8.3

(The default value is None)


... sort of retired...
0 Kudos
JoeBryant1
Occasional Contributor II

Yes, selecting '10.6' works and allows me and my staff to open a 10.8 MXD in 10.7.1.

BUT, I would like to give staff the option to save the MXD at their current version (10.7) and loose as little functionality as possible.

0 Kudos
JeffK
by MVP Regular Contributor
MVP Regular Contributor

Seeing that it is trying to find the 'default' (10.7) by searching the list for any default, none, or '' value you tried when you have coded an else block to handle the default (_107.mxd) tells me that your conditional check on version is not doing what you think it should be doing.

'if version' is not the same than checking for 'if version is not None'.  Here's a pretty goos SO thread discussing the difference: if a vs. if a is not none 

Try this:

if version != '' or version is not None:

Secondly, I think you would only be able to convert the list of versions that your current arcpy version is able to do. Meaning, at 10.7 you have 10.6 and earlier. You'll have to upgrade to 10.8 in order for you to save to earlier versions from 10.8, unless ESRI is also updating versions of arcpy to include forward compatibility, but I don't think that is happening.

JoeBryant1
Occasional Contributor II

Thanks for your suggestions, Jeff. I'm going to reply to your post in two parts.

Your second assumption is (luckily) not correct; I have tested and confirmed that I can use the script to save 10.8 MXDs down to 10.6 and below, and open them in my installed version of 10.7.1. I've also seen reference to this 'hack' elsewhere on Geonet /Stack Exchange in the past.

One thing I do notice that might be a concern: when using a 'blank' MXD as the input to the script, the resultant MXD gets reduced in size to only 6 KB. The version being saved to does not seem to matter. For reference, the blank 10.8 MXD I was provided is 20 KB. Creating a blank 10.7 MXD in my own environment for testing purposes results in an MXD file size of 288 KB (!).  Both of these come out the other side of this script tool at 6 KB, no matter the output version.

0 Kudos
JoeBryant1
Occasional Contributor II

Second part of my reply, regarding the conditional check:

I read up on "if a:" on SO before, but your link did give me good additional info - thanks!

In this case, either works, as both will catch the None object that is passed as the default version value. I tested, and the default value for the saveACopy method is in fact None, and not an empty string. So while "if version is not None:" is more precise, it also implies I need to create an "if else version:" condition to catch any other exemptions before my final "else:".

But this did help me figure out my answer. The 'default' version parameter None was being passed when I left the optional version parameter field in my script tool blank. But I suspect that when the default is passed, the saveACopy method does not detect your installed version and remove functionality to save the MXD at that version level; instead it just uses the Save As function and updates the file name. This is indicated by the fact that new MXD grows in length by 1 KB (proportional to the longer file name?) instead of being reduced to 6 KB like the others. And I am not able to open the new MXD in 10.7 (i.e. it is still saved as a 10.8 document.)

So, Dan's answer is what I will have to use in this case. I'll just need to update the tool documentation to explain this to my colleagues who will want to save at their current version. 

0 Kudos
JeffK
by MVP Regular Contributor
MVP Regular Contributor

No worries, Though I'd ask what other possible values could come from the parameter (GetParameterAsText returns String) that you would have to check for if the only types possible are a string or None?  I don't know what default values you have set for the tool, but if its free text and the user decides to pass in 1007 (or any value that is not in the version list) the if version: will result in true and since '1007' is not valid in the available version list, the SaveACopy method will fail. Maybe the better and more explicit option would be (if the values are not set in the tool parameters) is to check against the available list:

if version in ['10.1', '10.0', '8.3', '10.5', '10.4', '10.6', '9.0', '10.3', '9.2', '9.3']:

 

SaveACopy is not just renaming the mxd- file size can be a false positive.  SaveACopy is a wrapper for an ArcObject method, I'd venture to say there is a lot more going on to create the document through the multiple Class inheritance and instantiations, interface mappings and within the actual ArcObject IMapDoucument Save/ Save As method process, if that is what SaveACopy is ultimately pointing to. Doing a little test for None on some mxd's, the SaveACopy process complained on some layers that it couldn't connect to, so its in fact touching items within the document. Interestingly, mxd's created using this method also crashed more often when the mxd was opened.

If there is no version conversion needed for mxds that are the current version, you could use the shutil.copy() method as an alternative to SaveACopy, which was incredibly faster and didn't crash on the mxds that crashed using SaveACopy.

I adapted this from your code for testing, changing the list of mxd's to a directory but you can revert back to fit your tool.  This can be ran as standalone or in a script tool if you set the default paths for the parameters.

mxdDir = arcpy.GetParameterAsText(0)
if mxdDir == '' or not mxdDir:
    mxdDir = r'dir of mxds'

outloc = arcpy.GetParameterAsText(1)
if outloc == '' or not outloc:
    outloc = r'path to out location'

version = arcpy.GetParameterAsText(2)
if version == '' or not version:
    version = '10.7'


suffix = "_" + version.replace(".", "")
env.workspace = mxdDir
mxds = arcpy.ListFiles("*.mxd")

for item in mxds:
    mxd = arcpy.mapping.MapDocument(os.path.join(mxdDir, item))
    base = mxdDir + suffix + item

    if version in ['10.1', '10.0', '8.3', '10.5', '10.4', '10.6', '9.0', '10.3', '9.2', '9.3']:
        mxd.saveACopy(outloc + os.sep + base, version)
        arcpy.AddMessage(item + " has been converted")
    else:
        shutil.copy(os.path.join(mxdDir, item), outloc + os.sep + item + "_107.mxd")
        arcpy.AddMessage(item + " has been converted")

 

0 Kudos