Subject: Marine Geospatial Ecology Tools (MGET) help
Text archives
From: | "Jason Roberts" <> |
---|---|
To: | <> |
Cc: | <> |
Subject: | RE: [mget-help] Issue with the "Create Lines from Vector Component Rasters" tool in ArcGIS 10.2 |
Date: | Tue, 11 Mar 2014 10:22:54 -0400 |
Dear Caroline,
Thanks for your interest in MGET. The problem here is that ESRI's ArcGIS
Python library (arcgisscripting, wrapped by arcpy) is doing something that I
did not anticipate. MGET uses this library to retrieve the extent of
datasets--in this case, of your input TIF files. The library returns a
space-delimited string listing the four coordinates defining the extent.
What I did not expect is that it would ever return numbers containing a
comma for the decimal place instead of a period.
This probably happens because on your operating system, it is traditional to
use commas instead of periods. In the United States, where ArcGIS was
developed, it is traditional to use periods. Neither tradition is better
than the other, of course, but as a programmer, I expected that the ArcGIS
programmers would pick one tradition for their application programming
interface (API) and use it consistently no matter how the operating system
was configured. (Because they were based in the U.S., I expected they would
pick a period.) By allowing the operating system to determine how floating
point numbers are represented in their API (and not documenting this!) they
make applications such as MGET vulnerable to differences in representation,
and require them to handle all such differences...
Anyway, I have patched MGET to handle this situation. The patched file is
attached. To apply it to your system:
1. Close all ArcGIS programs.
2. Save the attached file to C:\Python27\lib\site-packages\GeoEco\ArcGIS.py,
overwriting the file that is there. (Note: do not accidentally overwrite the
file mentioned in the original traceback,
C:\Python27\lib\site-packages\GeoEco\Datasets\ArcGIS.py. That is the wrong
file. MGET contains several files named ArcGIS.py, each in a different
directory. Sorry for any confusion.)
3. Restart ArcGIS again and retry the MGET tool. Please let me know the
outcome.
Best regards,
Jason
-----Original Message-----
From:
[mailto:]
Sent: Tuesday, March 11, 2014 5:45 AM
To:
Subject: [mget-help] Issue with the "Create Lines from Vector Component
Rasters" tool in ArcGIS 10.2
Dear Mister,
I'm having trouble using the "Create Lines from Vector Component Rasters"
tool in ArcGIS 10.2. MGET version I am using is : 0.8a53.
Problem encountered is that my wind raster bounding boxes are encoded with a
comma instead of a point.
It seems to be the origin of the problem, as the dialog box shows:
Executing: ArcGISLinesFromVectorComponentRasters
GLO-BLENDED_WIND_L4-OBS_FULL_TIME_SERIE_1385632487733_eastward_wind_20070321
-000000.tif
GLO-BLENDED_WIND_L4-OBS_FULL_TIME_SERIE_1385632487733_northward_wind_2007032
1-000000.tif
C:\Users\guest906\Desktop\Test_vent\erery.shp 2000 false Start Time: Tue Mar
11 10:40:58 2014 Running script ArcGISLinesFromVectorComponentRasters...
Creating lines in C:\Users\guest906\Desktop\Test_vent\erery.shp from vector
component rasters
GLO-BLENDED_WIND_L4-OBS_FULL_TIME_SERIE_1385632487733_eastward_wind_20070321
-000000.tif
and
GLO-BLENDED_WIND_L4-OBS_FULL_TIME_SERIE_1385632487733_northward_wind_2007032
1-000000.tif.
ValueError: invalid literal for float(): 18,75
Traceback (most recent call last):
File "C:\Program
Files\GeoEco\ArcGISToolbox\Scripts\ArcGISLinesFromVectorComponentRasters.py"
,
line 5, in <module>
ExecuteMethodFromCommandLineAsArcGISTool('GeoEco.SpatialAnalysis.Lines',
'ArcGISLines', 'FromVectorComponentRasters')
File "C:\Python27\lib\site-packages\GeoEco\ArcGISScripts.py", line 210, in
ExecuteMethodFromCommandLineAsArcGISTool
exec sourceCode in globals(), locals()
File "<string>", line 1, in <module>
File "C:\Python27\lib\site-packages\GeoEco\SpatialAnalysis\Lines.py", line
158, in FromVectorComponentRasters
Lines.ShapefileFromVectorComponentGrids(xGrid, yGrid, lines,
scaleFactor, uniformLength, overwriteExisting=overwriteExisting)
File "C:\Python27\lib\site-packages\GeoEco\SpatialAnalysis\Lines.py", line
49, in ShapefileFromVectorComponentGrids
if xGrid.Shape != yGrid.Shape:
File "C:\Python27\lib\site-packages\GeoEco\Datasets\__init__.py", line
2621, in _GetShape
return self.GetLazyPropertyValue('Shape')
File "C:\Python27\lib\site-packages\GeoEco\Datasets\__init__.py", line
160, in GetLazyPropertyValue
value = self._GetLazyPropertyPhysicalValue(name)
File "C:\Python27\lib\site-packages\GeoEco\Datasets\ArcGIS.py", line 1403,
in _GetLazyPropertyPhysicalValue
self.SetLazyPropertyValue('CornerCoords', (float(d.Extent.split()[1]) +
d.MeanCellHeight / 2.0, float(d.Extent.split()[0]) + d.MeanCellWidth / 2.0))
ValueError: invalid literal for float(): 18,75
Failed to execute (ArcGISLinesFromVectorComponentRasters).
Failed at Tue Mar 11 10:40:58 2014 (Elapsed Time: 0,22 seconds)
Do you have any idea of what could be done to solve this problem?
Many thanks,
Caroline Quod
Geomatic Engineer
# ArcGIS.py - Provides utility functions for interacting with the ESRI ArcGIS
# software package.
#
# Copyright (C) 2007 Jason J. Roberts
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License (available in the file LICENSE.TXT)
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
USA.
import datetime
import inspect
import logging
import new
import os
import platform
import re
import sys
import types
import weakref
from GeoEco.Dependencies import Dependency, PythonModuleDependency,
SoftwareNotInstalledError
from GeoEco.DynamicDocString import DynamicDocString
from GeoEco.Exceptions import GeoEcoError
from GeoEco.Logging import Logger
from GeoEco.Internationalization import _, UnicodeToUserPreferredEncoding,
UserPreferredEncodingToUnicode
from GeoEco.Metadata import ClassMetadata, MethodMetadata, TypeMetadata
from GeoEco.Types import DateTimeTypeMetadata
# Private variables global to this module. Initially, I wanted to declare
these
# as class attributes of the GeoprocessorManager class. But when I did that,
# their reference counts were never decreased to 0 by Python when the module
was
# unloaded. This prevented the ArcGIS geoprocessor COM Automation object from
# being released properly, which caused calls to its SetParameterAsText method
# to not work as intended. After very careful experimentation, I determined
that
# the variables could be declared as module globals or as attributes of an
"old-
# style" class and be released properly. I elected to declare them as module
# globals. I could not change the GeoprocessorManager to an old-style class
# because I wanted it to have properties, which are only available on "new-
# style" classes.
_Geoprocessor = None
_WrappedGeoprocessor = None
# Public classes and functions exported by this module
class GeoprocessorManager(object):
__doc__ = DynamicDocString()
_ArcGISMajorVersion = None
_ArcGISMinorVersion = None
_ArcGISServicePack = None
@classmethod
def GetGeoprocessor(cls):
# Try to return a weak reference to the geoprocessor, so that the
caller
# cannot accidentally hold on to a strong reference and thereby
prevent
# the geoprocessor from being released properly when the module
unloads.
#
# First try to return a weak reference, so that the caller cannot
# accidentally hold on to a strong reference and thereby prevent the
# geoprocessor from being released properly when the module unloads.
# If the geoprocessor is the object returned by
arcgisscripting.create()
# then a weak reference cannot be created to it because it does not
have
# a __weakref__ member. In this case we just return the object itself.
if globals()['_Geoprocessor'] is not None:
try:
return weakref.proxy(globals()['_Geoprocessor'])
except:
pass
return globals()['_Geoprocessor']
return None
@classmethod
def SetGeoprocessor(cls, geoprocessor):
cls.__doc__.Obj.ValidatePropertyAssignment()
# If the caller provided a geoprocessor, use it.
if geoprocessor is not None:
try:
globals()['_Geoprocessor'] = geoprocessor
globals()['_WrappedGeoprocessor'] =
_ArcGISObjectWrapper(geoprocessor, u'Geoprocessor')
except:
globals()['_WrappedGeoprocessor'] = None
globals()['_Geoprocessor'] = None
raise
Logger.Debug(_(u'GeoEco will now use ArcGIS Geoprocessor object
0x%08X for ArcGIS operations.'), id(globals()['_Geoprocessor']))
# If they provided None, release our geoprocessor.
elif globals()['_Geoprocessor'] is not None:
Logger.Debug(_(u'GeoEco is releasing its reference to ArcGIS
Geoprocessor object 0x%08X and will no longer use it for ArcGIS
operations.'), id(globals()['_Geoprocessor']))
globals()['_WrappedGeoprocessor'] = None
globals()['_Geoprocessor'] = None
Geoprocessor = property(GetGeoprocessor, SetGeoprocessor,
doc=DynamicDocString())
@classmethod
def GetWrappedGeoprocessor(cls):
# For safety, return a weak reference to the geoprocessor wrapper, so
# that the caller cannot accidentally hold on to a strong reference
and
# thereby prevent the wrapper (and enclosed geoprocessor) from being
# released properly when the module unloads.
if globals()['_WrappedGeoprocessor'] is not None:
return weakref.proxy(globals()['_WrappedGeoprocessor'])
return None
WrappedGeoprocessor = property(GetWrappedGeoprocessor,
doc=DynamicDocString())
@classmethod
def GetGeoprocessorIsCOMObject(cls):
if not sys.modules.has_key('win32com.client'):
return False
if isinstance(cls.GetGeoprocessor(),
sys.modules['win32com.client'].CDispatch):
return True
return False
GeoprocessorIsCOMObject = property(GetGeoprocessorIsCOMObject,
doc=DynamicDocString())
@classmethod
def GetArcGISMajorVersion(cls):
if GeoprocessorManager._ArcGISMajorVersion is None:
cls._GetArcGISVersionNumbers()
return GeoprocessorManager._ArcGISMajorVersion
ArcGISMajorVersion = property(GetArcGISMajorVersion,
doc=DynamicDocString())
@classmethod
def GetArcGISMinorVersion(cls):
if GeoprocessorManager._ArcGISMajorVersion is None:
cls._GetArcGISVersionNumbers()
return GeoprocessorManager._ArcGISMinorVersion
ArcGISMinorVersion = property(GetArcGISMinorVersion,
doc=DynamicDocString())
@classmethod
def GetArcGISServicePack(cls):
if GeoprocessorManager._ArcGISMajorVersion is None:
cls._GetArcGISVersionNumbers()
return GeoprocessorManager._ArcGISServicePack
ArcGISServicePack = property(GetArcGISServicePack, doc=DynamicDocString())
@classmethod
def InitializeGeoprocessor(cls, forceCOMInstantiation=False,
forcePythonInstantiation=False):
# Validate input arguments.
if forceCOMInstantiation and forcePythonInstantiation:
Logger.RaiseException(ValueError(_(u'forceCOMInstantiation and
forcePythonInstantiation cannot both be True. Only one may be True.')))
# If this is ArcGIS 9.3.1 SP1 or later (a.k.a. 9.3 SP3),
# ignore forceCOMInstantiation. We only need that option
# for tools that call the SetValue method of geoprocessor
# cursors and pass None to instruct ArcGIS to set the field to
# NULL. Until ArcGIS 9.3.1 SP1, ArcGIS would raise an
# exception if you tried it, but you could work around it by
# instantiating the geoprocessor with COM.
if forceCOMInstantiation:
major = cls.GetArcGISMajorVersion()
minor = cls.GetArcGISMinorVersion()
servicePack = cls.GetArcGISServicePack()
if major > 9 or major == 9 and minor > 3 or major == 9 and minor
== 3 and servicePack >= 3:
forceCOMInstantiation = False
# If the geoprocessor has already been instantiated, return
# immediately, unless the caller required a specific method
# and the other method was used.
if cls.GetGeoprocessor() is not None:
if cls.GetGeoprocessorIsCOMObject() and forcePythonInstantiation:
Logger.RaiseException(ValueError(_(u'The ArcGIS geoprocessor
cannot be instantiated using the Python arcgisscripting module because it was
already instantiated using COM Automation.')))
if not cls.GetGeoprocessorIsCOMObject() and forceCOMInstantiation:
Logger.RaiseException(ValueError(_(u'The ArcGIS geoprocessor
cannot be instantiated using COM Automation because it was already
instantiated using the Python arcgisscripting module.')))
return
# Look up the version of ArcGIS that is installed on this
# machine.
major = cls.GetArcGISMajorVersion()
minor = cls.GetArcGISMinorVersion()
servicePack = cls.GetArcGISServicePack()
if major is None:
Logger.RaiseException(SoftwareNotInstalledError(_(u'The ArcGIS
geoprocessor cannot be instantiated because ArcGIS does not appear to be
installed.')))
# Instantiate the geoprocessor, trying the methods that are
# appropriate for the version of ArcGIS that is installed.
if major == 9 and minor == 1:
if forcePythonInstantiation:
Logger.RaiseException(ValueError(_(u'The ArcGIS geoprocessor
cannot be instantiated using the Python arcgisscripting module because ArcGIS
9.1 is installed and it does not include the arcgisscripting module. Please
upgrade to ArcGIS 9.2 or later and try again.')))
Logger.Debug(_(u'Attempting to instantiate the ArcGIS
geoprocessor using COM Automation because that is the only supported
instantiation method for ArcGIS 9.1...'))
realGeoprocessor, errorMessage = cls._InstantiateCOMGeoprocessor()
if realGeoprocessor is None:
Logger.RaiseException(RuntimeError(_(u'Failed to instantiate
the ArcGIS geoprocessor using COM Automation. Either ArcGIS is not installed,
the license server is not accessible, or there is a problem with your
installation or license. Error details: %s') % errorMessage))
cls.SetGeoprocessor(realGeoprocessor)
elif major == 9 and minor == 2:
cls._InstantiateGeoprocessorForArc92OrLater(major, minor, 2, 4,
forceCOMInstantiation, forcePythonInstantiation)
elif major == 9 and minor >= 3:
cls._InstantiateGeoprocessorForArc92OrLater(major, minor, 2, 5,
forceCOMInstantiation, forcePythonInstantiation)
elif major == 10 and minor == 0:
cls._InstantiateGeoprocessorForArc92OrLater(major, minor, 2, 6,
forceCOMInstantiation, forcePythonInstantiation)
elif major >= 10:
cls._InstantiateGeoprocessorForArc92OrLater(major, minor, 2, 7,
forceCOMInstantiation, forcePythonInstantiation)
else:
Logger.RaiseException(SoftwareNotInstalledError(_(u'The ArcGIS
geoprocessor cannot be instantiated because ArcGIS %i.%i is installed and
this tool is only capable of instantiating the geoprocessor if ArcGIS 9.1 or
later is installed. Please upgrade to ArcGIS 9.1 or later and try again') %
(major, minor)))
# We successfully instantiated the geoprocessor. As described
# in ticket #470, we need to work around an incompatibility
# between ArcGIS and Python.
#
# When Python code sets the PATH environment variable (e.g.
# os.environ['PATH'] = x), it screws up ArcGIS in a subtle
# way. A subsequent call to gp.Describe(<some
# raster>).DataType will return 'File' rather than
# 'RasterDataset'. When I ran ArcCatalog.exe 9.3.1 SP1 under
# the debugger, I noticed a difference in the DLLs that
# gp.Describe loaded, depending whether or not the Python code
# set the PATH. It did not matter what the PATH was set to,
# just that it was set at all (even set to what it currently
# was).
#
# To work around this, call gp.Describe on a raster that comes
# with GeoEco. This will cause the DLLs to be loaded, assuming
# that PATH has not been set from Python already (which is
# unlikely because GeoEco tools always initialize the
# geoprocessor very early).
cls.GetWrappedGeoprocessor().Describe(os.path.join(os.path.dirname(__file__),
'ArcGISToolbox', 'Rasters', 'dummyint'))
# TODO:
#
# Unfortunately, it is not sufficient to just call gp.Describe
# as shown above. That does cause the DLLs that are apparently
# required to be loaded, but only temporarily. If ArcCatalog
# sits idle for a while it unloads the DLLs. To work around
# that, explicitly call win32 LoadLibrary on the DLLs that
# appear to be required. This will leak Windows module handles
# for each one and cause it to remain loaded.
## import win32api
## win32api.LoadLibrary('GDALRasterDB.DLL')
## win32api.LoadLibrary('SDCPlugin.DLL')
## win32api.LoadLibrary('ISORes.DLL')
## win32api.LoadLibrary('cso.DLL')
## win32api.LoadLibrary('ShapefileFDB.DLL')
## win32api.LoadLibrary('CoverageFDB.DLL')
## win32api.LoadLibrary('ScalarReference.DLL')
## win32api.LoadLibrary('GpTinFunctionFactories.DLL')
## win32api.LoadLibrary('ArcGISDomain.DLL')
## win32api.LoadLibrary('GpCoreFunctionFactories.DLL')
## win32api.LoadLibrary('XMLSupport.DLL')
@classmethod
def _InstantiateGeoprocessorForArc92OrLater(cls, arcMajor, arcMinor,
pyMajor, pyMinor, forceCOMInstantiation, forcePythonInstantiation):
if forcePythonInstantiation and not (sys.version_info[0] == pyMajor
and sys.version_info[1] == pyMinor):
Logger.RaiseException(ValueError(_(u'The ArcGIS geoprocessor
cannot be instantiated using the Python arcgisscripting module because this
script is executing under Python %(pyMajor1)i.%(pyMinor1)i and the
arcgisscripting module from ArcGIS %(arcMajor)i.%(arcMinor)i can only be used
with Python %(pyMajor2)i.%(pyMinor2)i.') % {u'pyMajor1': sys.version_info[0],
u'pyMinor1': sys.version_info[1], u'arcMajor': arcMajor, u'arcMinor':
arcMinor, u'pyMajor2': pyMajor, u'pyMinor2': pyMinor}))
errorMessage1 = None
if not forceCOMInstantiation and (sys.version_info[0] == pyMajor and
sys.version_info[1] == pyMinor):
Logger.Debug(_(u'Attempting to instantiate the ArcGIS
geoprocessor using the arcgisscripting module...'))
realGeoprocessor, errorMessage1 =
cls._InstantiatePythonGeoprocessor()
if realGeoprocessor is not None:
cls.SetGeoprocessor(realGeoprocessor)
return
if forcePythonInstantiation:
Logger.RaiseException(RuntimeError(_(u'Failed to instantiate
the ArcGIS geoprocessor using the Python arcgisscripting module. Most likely
ArcGIS is not installed, the license server is not accessible, or there is a
problem with your installation or license. Error details: %s') %
errorMessage1))
else:
Logger.Debug(_(u'Failed to instantiate the ArcGIS
geoprocessor using the Python arcgisscripting module. %s') % errorMessage1)
Logger.Debug(_(u'Attempting to instantiate the ArcGIS geoprocessor
using COM Automation...'))
realGeoprocessor, errorMessage2 = cls._InstantiateCOMGeoprocessor()
if realGeoprocessor is not None:
cls.SetGeoprocessor(realGeoprocessor)
return
Logger.Debug(_(u'Failed to instantiate the ArcGIS geoprocessor using
COM automation. %s') % errorMessage2)
if errorMessage1 is not None:
Logger.RaiseException(RuntimeError(_(u'Failed to instantiate the
ArcGIS geoprocessor using the Python arcgisscripting module and using COM
Automation. Most likely ArcGIS is not installed, the license server is not
accessible, or there is a problem with your installation or license. If you
believe that none of those are the problem, please contact the author of this
tool for assistance. If you believe that none of those are the problem,
please contact the author of this tool for assistance. Error details: %s %s')
% (errorMessage1, errorMessage2)))
else:
if sys.version_info[0] == pyMajor and sys.version_info[1] ==
pyMinor:
Logger.Debug(_(u'Attempting to instantiate the ArcGIS
geoprocessor using the arcgisscripting module, simply for the purpose of
reporting an error message...'))
realGeoprocessor, errorMessage1 =
cls._InstantiatePythonGeoprocessor()
if realGeoprocessor is not None:
cls.SetGeoprocessor(realGeoprocessor)
Logger.RaiseException(RuntimeError(_(u'Failed to instantiate the
ArcGIS geoprocessor using COM Automation. (Due ArcGIS bug NIM010734, this
tool is required to instantiate the geoprocessor with COM Automation rather
than the arcgisscripting Python module.) %s') % errorMessage2))
@classmethod
def _InstantiateCOMGeoprocessor(cls):
try:
import pythoncom
except Exception, e:
if isinstance(e, AttributeError) and str(e).find("'NoneType'
object has no attribute 'platform'") >= 0:
return None, _(u'The pythoncom module from the "Python for
Windows Extensions" package (also known as "pywin32") could not be imported
due to an incompatibility between recent releases of pywin32 and ArcGIS. You
may be able to work around this problem temporarily by restarting ArcGIS and
running this tool again (do not run any other tools before running this one).
For a more permanent solution, uninstall your existing copy of pywin32 and
install build 212 instead. Finally, please see
http://code.env.duke.edu/projects/mget/ticket/386 for the current status of
this problem.')
return None, _(u'The "Python for Windows extensions" Python
package (also known as "pywin32") does not appear to be properly installed
for this version of Python (%(major)s.%(minor)s) because the Python statement
"import pythoncom" raised %(e)s: %(msg)s.') % {u'major': sys.version_info[0],
u'minor': sys.version_info[1], u'e': e.__class__.__name__, u'msg': unicode(e)}
Logger.Debug(_(u'Imported the pythoncom Python module.'))
try:
import win32com.client
except Exception, e:
return None, _(u'The "Python for Windows extensions" Python
package (also known as "pywin32") does not appear to be properly installed
for this version of Python (%(major)s.%(minor)s) because the Python statement
"import win32com.client" raised %(e)s: %(msg)s.') % {u'major':
sys.version_info[0], u'minor': sys.version_info[1], u'e':
e.__class__.__name__, u'msg': unicode(e)}
Logger.Debug(_(u'Imported the win32com.client Python module.'))
progID = 'esriGeoprocessing.GPDispatch'
try:
realGeoprocessor = win32com.client.Dispatch(progID)
except pythoncom.com_error, (hr, msg, exc, arg):
from GeoEco.COM import FormatCOMError
return None, _(u'ArcGIS may not be installed, the license server
may not be accessible, or there may be problem with the installation or
license. If you believe that none of those are the problem, please contact
the author of this tool for assistance. Error details: The "%(progid)s" COM
Automation object could not be instantiated because the Python statement
"win32com.client.Dispatch(\'%(progid)s\')" raised %(msg)s.') % {u'progid':
progID, u'msg': FormatCOMError(hr, msg, exc, arg)}
except Exception, e:
return None, _(u'ArcGIS may not be installed, the license server
may not be accessible, or there may be problem with the installation or
license. If you believe that none of those are the problem, please contact
the author of this tool for assistance. The "%(progid)s" COM Automation
object could not be instantiated because the Python statement
"win32com.client.Dispatch(\'%(progid)s\')" raised %(e)s: %(msg)s.') %
{u'progid': progID, u'e': e.__class__.__name__, u'msg': unicode(e)}
Logger.Debug(_(u'Instantiated ArcGIS geoprocessor object 0x%08X using
COM Automation.'), id(realGeoprocessor))
return realGeoprocessor, None
@classmethod
def _InstantiatePythonGeoprocessor(cls):
try:
import arcgisscripting
except Exception, e:
return None, _(u'The Python statement "import arcgisscripting"
raised %(e)s: %(msg)s.') % {u'e': e.__class__.__name__, u'msg': unicode(e)}
Logger.Debug(_(u'Imported the arcgisscripting Python module.'))
try:
realGeoprocessor = arcgisscripting.create() # NOTE: DO NOT
change this to arcgisscripting.create(9.3)!
except Exception, e:
return None, _(u'The Python statement "arcgisscripting.create()"
raised %(e)s: %(msg)s.') % {u'e': e.__class__.__name__, u'msg': unicode(e)}
Logger.Debug(_(u'Instantiated ArcGIS geoprocessor object 0x%08X using
arcgisscripting.create().'), id(realGeoprocessor))
return realGeoprocessor, None
@classmethod
def _GetArcGISVersionNumbers(cls):
# If we're running on Windows, get the ArcGIS version number from
# the Windows registry.
if sys.platform.lower() == u'win32':
Logger.Debug(_(u'Retrieving the ArcGIS version numbers from the
Windows Registry.'))
# First import the win32api and win32con modules.
d = PythonModuleDependency(importName='win32api',
displayName=_(u'Python for Windows extensions (pywin32)'),
alternateURL=u'http://sourceforge.net/projects/pywin32')
d.Initialize();
import win32api
d = PythonModuleDependency(importName='win32con',
displayName=_(u'Python for Windows extensions (pywin32)'),
alternateURL=u'http://sourceforge.net/projects/pywin32')
d.Initialize();
import win32con
# Read the registry values that contain the version numbers.
try:
hkey = None
try:
try:
subkey = 'Desktop10.2'
hkey =
win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\ESRI\\' + subkey)
(realVersionValue, realVersionType) =
win32api.RegQueryValueEx(hkey, 'RealVersion')
except:
try:
subkey = 'Desktop10.1'
hkey =
win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\ESRI\\' + subkey)
(realVersionValue, realVersionType) =
win32api.RegQueryValueEx(hkey, 'RealVersion')
except:
try:
subkey = 'Desktop10.0'
hkey =
win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\ESRI\\' + subkey)
(realVersionValue, realVersionType) =
win32api.RegQueryValueEx(hkey, 'RealVersion')
except:
subkey = 'ArcInfo\\Desktop\\8.0'
hkey =
win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\ESRI\\' + subkey)
(realVersionValue, realVersionType) =
win32api.RegQueryValueEx(hkey, 'RealVersion')
if not isinstance(realVersionValue, basestring) or not
re.match('^[0-9]+\.[0-9]+(\.[0-9])?$', realVersionValue.strip()):
raise ValueError(_(u'The RealVersion value of the
HKEY_LOCAL_MACHINE\\SOFTWARE\\ESRI\\ArcInfo\\Desktop\\8.0 registry key is not
a REG_SZ, or it is not formatted properly.'))
GeoprocessorManager._ArcGISMajorVersion =
int(realVersionValue.strip().split('.')[0])
GeoprocessorManager._ArcGISMinorVersion =
int(realVersionValue.strip().split('.')[1])
spNumberValue = None
try:
(spNumberValue, spNumberType) =
win32api.RegQueryValueEx(hkey, 'SPNumber')
except:
pass
if spNumberValue is not None:
if not isinstance(spNumberValue, basestring) or
len(spNumberValue.strip()) > 0 and not re.match('^[0-9]+$',
spNumberValue.strip()):
raise ValueError(_(u'The SPNumber value of the
HKEY_LOCAL_MACHINE\\SOFTWARE\\ESRI\\%s registry key is not a REG_SZ, or it is
not formatted properly.') % subkey)
if len(spNumberValue.strip()) > 0:
GeoprocessorManager._ArcGISServicePack =
int(spNumberValue.strip())
else:
GeoprocessorManager._ArcGISServicePack = 0
finally:
try:
if hkey is not None:
win32api.RegCloseKey(hkey)
except:
pass
except Exception, e:
GeoprocessorManager._ArcGISMajorVersion = None
GeoprocessorManager._ArcGISMinorVersion = None
GeoprocessorManager._ArcGISServicePack = None
Logger.Debug(_(u'Failed to retrieve the ArcGIS version
numbers from the Windows Registry. ArcGIS must not be installed. Python
reported %s: %s'), e.__class__.__name__, unicode(e))
# If we're on a non-Windows platform, all we can try to do is
# import the arcgisscripting module. If it contains a class
# called ExecuteError, it is ArcGIS 9.3. If not, it is ArcGIS
# 9.2. Note that this code is experimental; we have not yet
# tried to port GeoEco to non-Windows platforms. Also this
# code does not know how to determine the service pack that is
# installed, if any.
else:
raise NotImplementedError(_(u'At this time, GeoEco is only
supported on 32-bit Microsoft Windows.'))
Logger.Debug(_(u'Importing the arcgisscripting Python module to
determine if ArcGIS is installed on this non-Windows operating system...'))
try:
import arcgisscripting
if 'ExecuteError' in arcgisscripting.__dict__:
GeoprocessorManager._ArcGISMajorVersion = 9
GeoprocessorManager._ArcGISMinorVersion = 3
GeoprocessorManager._ArcGISServicePack = 0
Logger.Debug(_(u'Imported the arcgisscripting Python
module and found the ExecuteError class within it. ArcGIS 9.3 or later is
installed. We do not presently know how to determine if a service pack is
installed, so we will assume that no service pack is installed.'))
else:
GeoprocessorManager._ArcGISMajorVersion = 9
GeoprocessorManager._ArcGISMinorVersion = 2
GeoprocessorManager._ArcGISServicePack = 0
Logger.Debug(_(u'Imported the arcgisscripting Python
module but did not find the ExecuteError class within it. ArcGIS 9.2 is
installed. We do not presently know how to determine if a service pack is
installed, so we will assume that no service pack is installed.'))
except Exception, e:
GeoprocessorManager._ArcGISMajorVersion = None
GeoprocessorManager._ArcGISMinorVersion = None
GeoprocessorManager._ArcGISServicePack = None
Logger.Debug(_(u'The arcgisscripting Python module could not
be imported (Python raised %s: %s). ArcGIS is not installed.'),
e.__class__.__name__, unicode(e))
@classmethod
def RefreshCatalog(cls, directory):
cls.__doc__.Obj.ValidateMethodInvocation()
gp = cls.GetWrappedGeoprocessor()
if gp is not None:
gp.RefreshCatalog(directory)
Logger.Debug(_(u'Refreshed the ArcGIS catalog for directory %s'),
directory)
@classmethod
def ArcGISObjectExists(cls, path, correctTypes, typeDisplayName):
cls.__doc__.Obj.ValidateMethodInvocation()
gp = cls.GetWrappedGeoprocessor()
if gp is None:
Logger.RaiseException(RuntimeError(_(u'The ArcGIS geoprocessor
must be initialized before this tool may be executed. Please call
GeoprocessorManager.InitializeGeoprocessor or
GeoprocessorManager.SetGeoprocessor before executing this tool.')))
exists = gp.Exists(path)
if not exists and u'shapefile' in correctTypes and not
path.lower().endswith('.shp') and os.path.isdir(os.path.dirname(path)):
exists = gp.Exists(path + u'.shp')
if exists:
path = path + u'.shp'
isCorrectType = False
if exists:
correctTypes = map(unicode.lower, correctTypes)
d = gp.Describe(path)
isCorrectType = d is not None and d.DataType.lower() in
correctTypes
isCorrectType = isCorrectType or (u'rasterdataset' in
correctTypes and os.path.isfile(path) and path.lower().endswith('.img'))
# Seemingly randomly, gp.Describe does not work correctly with .img files.
if not exists:
Logger.Debug(_(u'The %(type)s %(path)s does not exist.') %
{u'type': typeDisplayName, u'path': path})
else:
if isCorrectType:
Logger.Debug(_(u'The %(type)s %(path)s exists.') % {u'type':
typeDisplayName, u'path': path})
else:
Logger.Debug(_(u'%(path)s exists but it is a %(actual)s, not
a %(type)s.') % {u'type': typeDisplayName, u'path': path, u'actual':
d.DataType})
return (exists, isCorrectType)
@classmethod
def DeleteArcGISObject(cls, path, correctTypes, typeDisplayName):
cls.__doc__.Obj.ValidateMethodInvocation()
exists, isCorrectType = cls.ArcGISObjectExists(path, correctTypes,
typeDisplayName)
if not exists:
Logger.Info(_('The %(type)s %(path)s will not be deleted because
it does not exist.') % {u'type': typeDisplayName, u'path': path})
return
if not isCorrectType:
Logger.RaiseException(ValueError(_('%(path)s exists but cannot be
deleted because it is not a %(type)s.') % {u'type': typeDisplayName, u'path':
path}))
try:
gp = cls.GetWrappedGeoprocessor()
gp.Delete_Management(path)
except:
Logger.LogExceptionAsError(_(u'Could not delete %(type)s
%(path)s.') % {u'type': typeDisplayName, u'path': path})
raise
Logger.Info(_('Deleted %(type)s %(path)s.') % {u'type':
typeDisplayName, u'path': path})
@classmethod
def CopyArcGISObject(cls, source, destination, overwriteExisting,
correctTypes, typeDisplayName):
cls.__doc__.Obj.ValidateMethodInvocation()
exists, isCorrectType = cls.ArcGISObjectExists(source, correctTypes,
typeDisplayName)
if not exists:
Logger.RaiseException(ValueError(_('The %(type)s %(path)s cannot
be copied because it does not exist.') % {u'type': typeDisplayName, u'path':
source}))
if not isCorrectType:
Logger.RaiseException(ValueError(_('%(path)s cannot be copied
because it is not a %(type)s.') % {u'type': typeDisplayName, u'path':
source}))
try:
if overwriteExisting:
oldLogInfoAsDebug = Logger.GetLogInfoAsDebug()
Logger.SetLogInfoAsDebug(True)
try:
cls.DeleteArcGISObject(destination, correctTypes,
typeDisplayName)
finally:
Logger.SetLogInfoAsDebug(oldLogInfoAsDebug)
else:
exists, isCorrectType = cls.ArcGISObjectExists(destination,
correctTypes, typeDisplayName)
if exists:
Logger.RaiseException(ValueError(_('%(path)s already
exists.') % {u'path': destination}))
gp = cls.GetWrappedGeoprocessor()
Logger.Info(_('Copying %(type)s %(source)s to %(destination)s.')
% {u'type': typeDisplayName, u'source': source, u'destination': destination})
if u'featureclass' in correctTypes or u'shapefile' in
correctTypes or u'featurelayer' in correctTypes:
gp.CopyFeatures_management(source, destination)
else:
gp.Copy_Management(source, destination)
except:
Logger.LogExceptionAsError(_(u'Could not copy %(type)s %(source)s
to %(destination)s.') % {u'type': typeDisplayName, u'source': source,
u'destination': destination})
raise
@classmethod
def MoveArcGISObject(cls, source, destination, overwriteExisting,
correctTypes, typeDisplayName):
cls.__doc__.Obj.ValidateMethodInvocation()
exists, isCorrectType = cls.ArcGISObjectExists(source, correctTypes,
typeDisplayName)
if not exists:
Logger.RaiseException(ValueError(_('The %(type)s %(path)s cannot
be moved because it does not exist.') % {u'type': typeDisplayName, u'path':
source}))
if not isCorrectType:
Logger.RaiseException(ValueError(_('%(path)s cannot be moved
because it is not a %(type)s.') % {u'type': typeDisplayName, u'path':
source}))
try:
if overwriteExisting:
oldLogInfoAsDebug = Logger.GetLogInfoAsDebug()
Logger.SetLogInfoAsDebug(True)
try:
cls.DeleteArcGISObject(destination, correctTypes,
typeDisplayName)
finally:
Logger.SetLogInfoAsDebug(oldLogInfoAsDebug)
else:
exists, isCorrectType = cls.ArcGISObjectExists(destination,
correctTypes, typeDisplayName)
if exists:
Logger.RaiseException(ValueError(_('%(path)s already
exists.') % {u'path': destination}))
gp = cls.GetWrappedGeoprocessor()
Logger.Info(_('Moving %(type)s %(source)s to %(destination)s.') %
{u'type': typeDisplayName, u'source': source, u'destination': destination})
if u'featureclass' in correctTypes or u'shapefile' in
correctTypes or u'featurelayer' in correctTypes:
gp.CopyFeatures_management(source, destination)
else:
gp.Copy_Management(source, destination)
gp.Delete_Management(source)
except:
Logger.LogExceptionAsError(_(u'Could not move %(type)s %(source)s
to %(destination)s.') % {u'type': typeDisplayName, u'source': source,
u'destination': destination})
raise
@classmethod
def GetUniqueLayerName(cls):
gp = cls.GetWrappedGeoprocessor()
if gp is None:
Logger.RaiseException(RuntimeError(_(u'The ArcGIS geoprocessor
must be initialized before this tool may be executed. Please call
GeoprocessorManager.InitializeGeoprocessor or
GeoprocessorManager.SetGeoprocessor before executing this tool.')))
import random
name = u'TempLayer%08X' % random.randint(0, 2147483647)
while gp.Exists(name):
name = u'TempLayer%08X' % random.randint(0, 2147483647)
return name
class ArcGISDependency(Dependency):
__doc__ = DynamicDocString()
def __init__(self, minimumMajorVersion, minimumMinorVersion=None,
minimumServicePack=None, requiresCOMInstantiation=False,
requiresPythonInstantiation=False):
self.SetVersion(minimumMajorVersion, minimumMinorVersion,
minimumServicePack)
assert not (requiresCOMInstantiation and
requiresPythonInstantiation), u'requiresCOMInstantiation and
requiresPythonInstantiation cannot both be True'
self.RequiresCOMInstantiation = requiresCOMInstantiation
self.RequiresPythonInstantiation = requiresPythonInstantiation
def SetVersion(self, minimumMajorVersion, minimumMinorVersion=None,
minimumServicePack=None):
assert isinstance(minimumMajorVersion, types.IntType),
u'minimumMajorVersion must be an integer.'
assert isinstance(minimumMinorVersion, (types.IntType,
types.NoneType)), 'minimumMinorVersion must be an integer, or None.'
assert isinstance(minimumServicePack, (types.IntType,
types.NoneType)), u'minimumServicePack must be an integer, or None.'
assert minimumMajorVersion is not None and minimumMinorVersion is
None and minimumServicePack is None or minimumMajorVersion is not None and
minimumMinorVersion is not None and minimumServicePack is None or
minimumMajorVersion is not None and minimumMinorVersion is not None and
minimumServicePack is not None, u'If you specify a minimumMinorVersion you
must also specify a minimumMajorVersion. If you specify a minimumServicePack
you must also specify a minimumMajorVersion and minimumMinorVersion.'
assert minimumMinorVersion is None or minimumMinorVersion >= 0, u'If
minimumMinorVersion is not None it must be >= 0.'
assert minimumServicePack is None or minimumServicePack >= 0, u'If
minimumServicePack is not None it must be >= 0.'
assert minimumMajorVersion > 9 or minimumMajorVersion == 9 and
minimumMinorVersion is not None and minimumMinorVersion >= 1, u'GeoEco can
only run on ArcGIS 9.1 or later. Even if your code can run on prior versions,
GeoEco\'s ArcGIS utility functions cannot. Please adjust your
ArcGISDependency to 9.1 or later.'
if minimumMinorVersion is None:
minimumMinorVersion = 0
if minimumServicePack is None:
minimumServicePack = 0
self._MinimumMajorVersion = minimumMajorVersion
self._MinimumMinorVersion = minimumMinorVersion
self._MinimumServicePack = minimumServicePack
def _GetMinimumMajorVersion(self):
return self._MinimumMajorVersion
MinimumMajorVersion = property(_GetMinimumMajorVersion,
doc=DynamicDocString())
def _GetMinimumMinorVersion(self):
return self._MinimumMinorVersion
MinimumMinorVersion = property(_GetMinimumMinorVersion,
doc=DynamicDocString())
def _GetMinimumServicePack(self):
return self._MinimumServicePack
MinimumServicePack = property(_GetMinimumServicePack,
doc=DynamicDocString())
def _GetMinimumServicePackString(self):
if self._MinimumServicePack > 0:
return _(u' Service Pack %i') % self._MinimumServicePack
else:
return u''
MinimumServicePackString = property(_GetMinimumServicePackString,
doc=DynamicDocString())
def _SetRequiresCOMInstantiation(self, value):
assert isinstance(value, types.BooleanType),
u'RequiresCOMInstantiation must be a boolean'
self._RequiresCOMInstantiation = value
def _GetRequiresCOMInstantiation(self):
return self._RequiresCOMInstantiation
RequiresCOMInstantiation = property(_GetRequiresCOMInstantiation,
_SetRequiresCOMInstantiation, doc=DynamicDocString())
def _SetRequiresPythonInstantiation(self, value):
assert isinstance(value, types.BooleanType),
u'RequiresPythonInstantiation must be a boolean'
self._RequiresPythonInstantiation = value
def _GetRequiresPythonInstantiation(self):
return self._RequiresPythonInstantiation
RequiresPythonInstantiation = property(_GetRequiresPythonInstantiation,
_SetRequiresPythonInstantiation, doc=DynamicDocString())
_LoggedInstalledVersion = False
def GetResultCacheKey(self):
if self.RequiresCOMInstantiation:
return u'ArcGISDependency:' + unicode(self._MinimumMajorVersion)
+ u',' + unicode(self._MinimumMinorVersion) + u',' +
unicode(self._MinimumServicePack) + u' using COM Automation'
if self.RequiresPythonInstantiation:
return u'ArcGISDependency:' + unicode(self._MinimumMajorVersion)
+ u',' + unicode(self._MinimumMinorVersion) + u',' +
unicode(self._MinimumServicePack) + u' using arcgisscripting'
return u'ArcGISDependency:' + unicode(self._MinimumMajorVersion) +
u',' + unicode(self._MinimumMinorVersion) + u',' +
unicode(self._MinimumServicePack)
def Initialize(self):
# If this is ArcGIS 9.3.1 SP1 or later (a.k.a. 9.3 SP3),
# ignore RequiresCOMInstantiation. We only need that option
# for tools that call the SetValue method of geoprocessor
# cursors and pass None to instruct ArcGIS to set the field to
# NULL. Until ArcGIS 9.3.1 SP1, ArcGIS would raise an
# exception if you tried it, but you could work around it by
# instantiating the geoprocessor with COM.
major = GeoprocessorManager.GetArcGISMajorVersion()
minor = GeoprocessorManager.GetArcGISMinorVersion()
sp = GeoprocessorManager.GetArcGISServicePack()
requiresCOMInstantiation = self.RequiresCOMInstantiation
if major > 9 or major == 9 and minor > 3 or major == 9 and minor == 3
and sp >= 3:
requiresCOMInstantiation = False
if requiresCOMInstantiation:
Logger.Debug(_(u'Checking software dependency: ArcGIS version
%i.%i%s or later, with the geoprocessor instantiated using Microsoft COM
Automation') % (self.MinimumMajorVersion, self.MinimumMinorVersion,
self.MinimumServicePackString))
elif self.RequiresPythonInstantiation:
Logger.Debug(_(u'Checking software dependency: ArcGIS version
%i.%i%s or later, with the geoprocessor instantiated using the Python
arcgisscripting module') % (self.MinimumMajorVersion,
self.MinimumMinorVersion, self.MinimumServicePackString))
else:
Logger.Debug(_(u'Checking software dependency: ArcGIS version
%i.%i%s or later') % (self.MinimumMajorVersion, self.MinimumMinorVersion,
self.MinimumServicePackString))
# Check the ArcGIS version numbers.
if major is None or minor is None or sp is None:
Logger.RaiseException(SoftwareNotInstalledError(_(u'This tool
requires ArcGIS %i.%i%s or a later version, but ArcGIS is not installed.
Please install a compatible version of ArcGIS and try again.') %
(self.MinimumMajorVersion, self.MinimumMinorVersion,
self.MinimumServicePackString)))
if not ArcGISDependency._LoggedInstalledVersion:
if sp > 0:
servicePackString = _(u' Service Pack %i') %
GeoprocessorManager.GetArcGISServicePack()
else:
servicePackString = u''
Logger.Debug(_(u'ArcGIS %i.%i%s is installed.'), major, minor,
servicePackString)
ArcGISDependency._LoggedInstalledVersion = True
if self.MinimumMajorVersion > major or self.MinimumMajorVersion ==
major and self.MinimumMinorVersion > minor or self.MinimumMajorVersion ==
major and self.MinimumMinorVersion == minor and self.MinimumServicePack > sp:
if sp > 0:
servicePackString = _(u' Service Pack %i') %
GeoprocessorManager.GetArcGISServicePack()
else:
servicePackString = u''
Logger.RaiseException(SoftwareNotInstalledError(_(u'This tool
requires ArcGIS %i.%i%s or a later version, but version %s.%s%s is installed.
Please upgrade your ArcGIS installation to a compatible version and try
again.') % (self.MinimumMajorVersion, self.MinimumMinorVersion,
self.MinimumServicePackString, major, minor, servicePackString)))
# If the geoprocessor has already been instantiated and this
# tool requires that it be instantiated with a specific
# method, report an error if it has already been instantiated
# with the other method. Otherwise just return.
if GeoprocessorManager.GetWrappedGeoprocessor() is not None:
if requiresCOMInstantiation and not
GeoprocessorManager.GetGeoprocessorIsCOMObject():
Logger.RaiseException(RuntimeError(_(u'This tool requires
that the ArcGIS geoprocessor be instantiated using Microsoft COM Automation
(via the win32com.client.Dispatch function) but the geoprocessor was already
instantiated using the Python arcgisscripting module. Please contact the
author of this tool for assistance.')))
if self.RequiresPythonInstantiation and
GeoprocessorManager.GetGeoprocessorIsCOMObject():
if major == 9 and minor == 2 and not (sys.version_info[0] ==
2 and sys.version_info[1] == 4):
Logger.RaiseException(RuntimeError(_(u'This tool requires
that the ArcGIS geoprocessor be instantiated using the Python arcgisscripting
module but the geoprocessor was already instantiated using Microsoft COM
Automation (via the win32com.client.Dispatch function) because the ArcGIS 9.2
arcgisscripting module can only be used with Python 2.4. Please try to run
this tool again using Python 2.4.')))
if major == 9 and minor == 3 and not (sys.version_info[0] ==
2 and sys.version_info[1] == 5):
Logger.RaiseException(RuntimeError(_(u'This tool requires
that the ArcGIS geoprocessor be instantiated using the Python arcgisscripting
module but the geoprocessor was already instantiated using Microsoft COM
Automation (via the win32com.client.Dispatch function) because the ArcGIS 9.3
arcgisscripting module can only be used with Python 2.5. Please try to run
this tool again using Python 2.5.')))
if major == 10 and not (sys.version_info[0] == 2 and
sys.version_info[1] == 6):
Logger.RaiseException(RuntimeError(_(u'This tool requires
that the ArcGIS geoprocessor be instantiated using the Python arcgisscripting
module but the geoprocessor was already instantiated using Microsoft COM
Automation (via the win32com.client.Dispatch function) because the ArcGIS 10
arcgisscripting module can only be used with Python 2.6. Please try to run
this tool again using Python 2.6.')))
Logger.RaiseException(RuntimeError(_(u'This tool requires
that the ArcGIS geoprocessor be instantiated using the Python arcgisscripting
module but the geoprocessor was already instantiated using Microsoft COM
Automation (via the win32com.client.Dispatch function). Please contact the
author of this tool for assistance.')))
return
# Initialize the geoprocessor object.
GeoprocessorManager.InitializeGeoprocessor(forceCOMInstantiation=requiresCOMInstantiation,
forcePythonInstantiation=self.RequiresPythonInstantiation)
def GetConstraintDescriptionStrings(self):
if self.MinimumMajorVersion == 9 and self.MinimumMinorVersion == 3
and self.MinimumServicePack >= 2:
if self.MinimumServicePack == 2:
return [u'ArcGIS 9.3.1 or later']
return [u'ArcGIS 9.3.1 Service Pack %i or later' %
(self.MinimumServicePack - 2,)]
if self.MinimumServicePack > 0:
return [u'ArcGIS %i.%i Service Pack %i or later' %
(self.MinimumMajorVersion, self.MinimumMinorVersion, self.MinimumServicePack)]
return [u'ArcGIS %i.%i or later' % (self.MinimumMajorVersion,
self.MinimumMinorVersion)]
class ArcGISProductDependency(Dependency):
__doc__ = DynamicDocString()
def __init__(self, minimumProductLevel):
self.MinimumProductLevel = minimumProductLevel
def _SetMinimumProductLevel(self, value):
assert isinstance(value, types.UnicodeType), u'MinimumProductLevel
must be a Unicode string'
self._MinimumProductLevel = value
def _GetMinimumProductLevel(self):
return self._MinimumProductLevel
MinimumProductLevel = property(_GetMinimumProductLevel,
_SetMinimumProductLevel, doc=DynamicDocString())
_ProductStatus = {}
def GetResultCacheKey(self):
return u'ArcGISProductDependency:' + self._MinimumProductLevel
def Initialize(self):
Logger.Debug(_(u'Checking software dependency: ArcGIS product level
\"%s\".') % self.MinimumProductLevel)
# Obtain the geoprocessor. If we can't get it, it means the method
that
# declared this dependency did not first declare an ArcGISDependency.
gp = GeoprocessorManager.GetWrappedGeoprocessor()
assert gp is not None, u'An ArcGISDependency must be declared before
an ArcGISProductDependency is declared. Please add an ArcGISDependency to the
method metadata for this method.'
# If our product status dictionary does not have an entry for this
# product level, query ArcGIS for its availability.
if not
ArcGISProductDependency._ProductStatus.has_key(self.MinimumProductLevel):
ArcGISProductDependency._ProductStatus[self.MinimumProductLevel]
= gp.CheckProduct(self.MinimumProductLevel)
# Check the product status.
if
ArcGISProductDependency._ProductStatus.has_key(self.MinimumProductLevel):
if
ArcGISProductDependency._ProductStatus[self.MinimumProductLevel].lower() !=
u'available' and
ArcGISProductDependency._ProductStatus[self.MinimumProductLevel].lower() !=
u'alreadyinitialized':
Logger.RaiseException(SoftwareNotInstalledError(_(u'This tool
requires ArcGIS product license level \"%(level)s\" or higher. The ArcGIS
geoprocessor reported the following status for that license level:
\"%(status)s\". Please verify that you possess an ArcGIS product license of a
sufficient level. If you use an ArcGIS license server, verify that this
computer can properly communicate with it.') % {u'level':
self.MinimumProductLevel, u'status' :
ArcGISProductDependency._ProductStatus[self.MinimumProductLevel]}))
else:
Logger.RaiseException(SoftwareNotInstalledError(_(u'This tool
requires ArcGIS product license level \"%(level)s\" or higher. The ArcGIS
geoprocessor failed to report the status of that license level. Please verify
that you possess an ArcGIS product license of a sufficient level. If you use
an ArcGIS license server, verify that this computer can properly communicate
with it.') % {u'level': self.MinimumProductLevel}))
def GetConstraintDescriptionStrings(self):
return [u'ArcGIS product level of "%s" or higher' %
self.MinimumProductLevel]
class ArcGISExtensionDependency(Dependency):
__doc__ = DynamicDocString()
def __init__(self, extensionCode):
self.ExtensionCode = extensionCode
def _SetExtensionCode(self, value):
assert isinstance(value, types.UnicodeType), u'ExtensionCode must be
a Unicode string'
self._ExtensionCode = value
def _GetExtensionCode(self):
return self._ExtensionCode
ExtensionCode = property(_GetExtensionCode, _SetExtensionCode,
doc=DynamicDocString())
def GetResultCacheKey(self):
return u'ArcGISExtensionDependency:' + self._ExtensionCode
def Initialize(self):
Logger.Debug(_(u'Checking software dependency: ArcGIS \"%s\"
extension.') % self.ExtensionCode)
# Obtain the geoprocessor. If we can't get it, it means the method
that
# declared this dependency did not first declare an ArcGISDependency.
gp = GeoprocessorManager.GetWrappedGeoprocessor()
assert gp is not None, u'An ArcGISDependency must be declared before
an ArcGISExtensionDependency is declared. Please add an ArcGISDependency to
the method metadata for this method.'
# It appears that the geoprocessor does not maintain a reference count
# on checked out extensions. Thus, you can call CheckOutExtension
# multiple times for the same extension, but if you call
# CheckInExtension just once, the extension is no longer checked out.
# As a result, if we checked out an extension in a previous call we
# have no guarantee that it is still checked out, because the caller
# could have checked it in. To mitigate this, we always check out the
# extension every time we're called. This seems to have no ill
effects.
# It does not cause multiple licenses to be taken from the license
# server, and it does not yield an excessive performance hit (the
# CheckOutExtension call returns relatively quickly).
#
# We also never check in the extension, because we don't know if this
# would foul up the caller (he may assume the geoprocessor is
reference-
# counting the extensions, when it really is not...)
status = gp.CheckOutExtension(self.ExtensionCode)
if status is None:
Logger.RaiseException(SoftwareNotInstalledError(_(u'This tool
requires the ArcGIS \"%(extension)s\" extension. The ArcGIS geoprocessor
failed to report the status of the license for that extension. Please verify
that you possess a license for that extension and that the extension is
installed. If you use an ArcGIS license server, verify that this computer can
properly communicate with it.') % {u'extension': self.ExtensionCode}))
elif status.lower() != u'checkedout':
Logger.RaiseException(SoftwareNotInstalledError(_(u'This tool
requires the ArcGIS \"%(extension)s\" extension. The ArcGIS geoprocessor
reported the following status for that license level: \"%(status)s\". Please
verify that you possess a license for that extension and that the extension
is installed. If you use an ArcGIS license server, verify that this computer
can properly communicate with it.') % {u'extension': self.ExtensionCode,
u'status' :
ArcGISProductDependency._ProductStatus[self.MinimumProductLevel]}))
def GetConstraintDescriptionStrings(self):
return [u'ArcGIS "%s" extension' % self.ExtensionCode]
class ArcGISError(GeoEcoError):
__doc__ = DynamicDocString()
def ValidateMethodMetadataForExposureAsArcGISTool(moduleName, className,
methodName):
# Validate the class and method metadata.
assert sys.modules.has_key(moduleName), u'Module %s must be imported
before ValidateMethodMetadataForExposureAsArcGISTool is invoked on that
module.' % moduleName
assert sys.modules[moduleName].__dict__.has_key(className) and
issubclass(sys.modules[moduleName].__dict__[className], object), u'Module %s
must contain a class named %s, and the class must derive from object.' %
(moduleName, className)
cls = sys.modules[moduleName].__dict__[className]
assert isinstance(cls.__doc__, DynamicDocString) and
isinstance(cls.__doc__.Obj, ClassMetadata), u'The __doc__ attribute of class
%s must be an instance of DynamicDocString, and that Obj property of that
instance must be an instance of ClassMetadata.' % className
assert hasattr(cls, methodName) and inspect.ismethod(getattr(cls,
methodName)), u'Class %s must contain an instance method or classmethod named
%s.' % (className, methodName)
assert isinstance(getattr(cls, methodName).__doc__, DynamicDocString)
and isinstance(getattr(cls, methodName).__doc__.Obj, MethodMetadata), u'The
__doc__ attribute of method %s of class %s must be an instance of
DynamicDocString, and that Obj property of that instance must be an instance
of MethodMetadata.' % (methodName, className)
methodMetadata = getattr(cls, methodName).__doc__.Obj
assert methodMetadata.IsInstanceMethod or
methodMetadata.IsClassMethod, u'Method %s of class %s must be an instance
method or a classmethod.' % (methodName, className)
assert methodMetadata.IsExposedAsArcGISTool,
u'%s.%s.__doc__.Obj.IsExposedAsArcGISTool must be true.' % (className,
methodName)
assert isinstance(methodMetadata.ArcGISDisplayName,
types.UnicodeType), u'%s.%s.__doc__.Obj.ArcGISDisplayName must be a unicode
string.' % (className, methodName)
assert '_' not in className and '_' not in methodName, u'In order for
method %s of class %s to be exposed as an ArcGIS tool, neither the method
name nor the class name may contain an underscore.' % (methodName, className)
# Validate the metadata for the method's arguments.
(args, varargs, varkw, defaults) = inspect.getargspec(getattr(cls,
methodName))
assert varargs is None, u'%s.%s cannot include a varargs argument
because this method is designated for exposure as an ArcGIS tool (ArcGIS
tools do not support varargs arguments). Please remove the *%s argument.'
(className, methodName, varargs)
assert varkw is None, u'%s.%s cannot include a varkw argument because
this method is designated for exposure as an ArcGIS tool (ArcGIS tools do not
support varkw arguments). Please remove the **%s argument.' (className,
methodName, varkw)
assert len(methodMetadata.Arguments) == len(args),
u'%s.%s.__doc__.Obj.Arguments must contain exactly one element for each
argument to %s.%s. %s.%s.__doc__.Obj.Arguments contains %i elements, but %i
elements were expected.' % (className, methodName, className, methodName,
className, methodName, len(methodMetadata.Arguments), len(args))
for i in range(1, len(args)): # Skip the self or cls argument
assert methodMetadata.Arguments[i].Name == args[i],
u'%s.%s.__doc__.Obj.Arguments[%i].Name must match the name of argument %i of
%s.%s (where 0 is the first argument).' % (className, methodName, i, i,
className, methodName)
assert isinstance(methodMetadata.Arguments[i].Type,
TypeMetadata), u'%s.%s.__doc__.Obj.Arguments[%i].Type must be an instance of
GeoEco.Metadata.TypeMetadata.' % (className, methodName, i)
if methodMetadata.Arguments[i].ArcGISDisplayName is not None:
assert
isinstance(methodMetadata.Arguments[i].ArcGISDisplayName, types.UnicodeType),
u'%s.%s.__doc__.Obj.Arguments[%i].ArcGISDisplayName must be a unicode
string.' % (className, methodName, i)
assert
methodMetadata.Arguments[i].Type.CanBeArcGISInputParameter,
u'%s.%s.__doc__.Obj.Arguments[%i].Type.CanBeArcGISInputParameter must be
True' % (className, methodName, i)
assert
methodMetadata.Arguments[i].InitializeToArcGISGeoprocessorVariable is None,
u'Argument %i of %s.%s cannot have a value for ArcGISDisplayName when
InitializeToArcGISGeoprocessorVariable is True. Either the argument can have
an ArcGISDisplayName, in which case the argument is exposed as an ArcGIS
parameter, or it can have InitializeToArcGISGeoprocessorVariable set to True,
in which case the argument is not exposed in ArcGIS but is initialized to a
geoprocessor variable.' % (i, className, methodName)
if methodMetadata.Arguments[i].ArcGISParameterDependencies is
not None:
for param in
methodMetadata.Arguments[i].ArcGISParameterDependencies:
assert param != methodMetadata.Arguments[i].Name,
u'%s.%s.__doc__.Obj.Arguments[%i].ArcGISParameterDependencies must not
declare that this argument has a dependency on itself.' % (className,
methodName, i)
assert param in args,
u'%s.%s.__doc__.Obj.Arguments[%i].ArcGISParameterDependencies must declare
dependencies on existing arguments. The argument \'%s\' does not exist.' %
(className, methodName, i, param)
else:
assert methodMetadata.Arguments[i].HasDefault or
methodMetadata.Arguments[i].InitializeToArcGISGeoprocessorVariable is not
None, u'Argument %i of %s.%s must have a default value, or its metadata must
specify that it should be initialized to an ArcGIS geoprocessor variable,
because the method is designated for exposure as an ArcGIS tool but the
argument itself is not (its ArcGISDisplayName is None).' % (i, className,
methodName)
# Validate the metadata for the method's results.
for i in range(len(methodMetadata.Results)):
assert isinstance(methodMetadata.Results[i].Type, TypeMetadata),
u'%s.%s.__doc__.Obj.Results[%i].Type must be an instance of
GeoEco.Metadata.TypeMetadata.' % (className, methodName, i)
if methodMetadata.Results[i].ArcGISDisplayName is not None:
assert
isinstance(methodMetadata.Results[i].ArcGISDisplayName, types.UnicodeType),
u'%s.%s.__doc__.Obj.Results[%i].ArcGISDisplayName must be a unicode string.'
% (className, methodName, i)
assert
methodMetadata.Results[i].Type.CanBeArcGISOutputParameter,
u'%s.%s.__doc__.Obj.Results[%i].Type.CanBeArcGISOutputParameter must be True'
% (className, methodName, i)
if methodMetadata.Results[i].ArcGISParameterDependencies is
not None:
for param in
methodMetadata.Results[i].ArcGISParameterDependencies:
assert param in args,
u'%s.%s.__doc__.Obj.Results[%i].ArcGISParameterDependencies must declare
dependencies on existing arguments. The argument \'%s\' does not exist.' %
(className, methodName, i, param)
class _ArcGISObjectWrapper(object):
def __init__(self, obj, name=None):
assert isinstance(name, (types.UnicodeType, types.NoneType)), u'The
name argument must be a unicode string, or None.'
if name is not None:
self._Name = name
else:
self._Name = u'<unknown>'
self._Object = obj
self._WrappedMethods = {}
def _LogDebug(self, format, *args, **kwargs):
try:
logging.getLogger(u'GeoEco.ArcGIS').debug(format, *args, **kwargs)
except:
pass
def _LogInfo(self, format, *args, **kwargs):
try:
logging.getLogger(u'GeoEco.ArcGIS').info(format, *args, **kwargs)
except:
pass
def _LogWarning(self, format, *args, **kwargs):
try:
logging.getLogger(u'GeoEco.ArcGIS').warning(format, *args,
**kwargs)
except:
pass
def _LogError(self, format, *args, **kwargs):
try:
logging.getLogger(u'GeoEco.ArcGIS').error(format, *args, **kwargs)
except:
pass
def __getattr__(self, name):
assert isinstance(name, basestring), u'name must be a string.'
# If the caller is asking for a private attribute (the name starts
with
# an underscore), he wants an attribute of the wrapper class instance,
# not of the wrapped object. In this case, we must use the object
# class's implementation of __getattr__.
if isinstance(name, types.StringType):
name = unicode(name)
if name.startswith(u'_'):
return object.__getattribute__(self, name)
# The caller is asking for a data attribute or a method of the wrapped
# object. If we already built a wrapper method for the specified name,
# it means the caller asked for it before and we determined that it
was
# a method. Return the wrapped method to the caller now.
if self._WrappedMethods.has_key(name.lower()):
return new.instancemethod(self._WrappedMethods[name.lower()],
self, _ArcGISObjectWrapper)
# Retrieve the attribute from the wrapped object.
try:
# If we imported pythoncom successfully, get the value and
# catch com_error. Raise com_error as ArcGISError.
#
# Note: call raise, rather than Logger.RaiseException.
# This is so the caller can swallow the exception, if
# needed. Python's hasattr function works by calling
# getattr and seeing if it raises an exception. If we call
# Logger.RaiseException, we will break this behavior
# because we'll cause error messages to be reported. We
# leave it to the caller to call
# Logger.LogExceptionAsError, if needed.
if sys.modules.has_key('pythoncom'):
try:
value = getattr(self._Object, name)
except sys.modules['pythoncom'].com_error, (hr, msg, exc,
arg):
from GeoEco.COM import FormatCOMError
raise ArcGISError(_(u'Failed to get the value of the %s
attribute of ArcGIS %s object 0x%08X. This may result from a problem with
your inputs or it may indicate a programming mistake in this tool or ArcGIS
itself. Please check your inputs and try again. Also review any preceding
error messages and the detailed error information that appears at the end of
this message. If you suspect a programming mistake in this tool or ArcGIS,
please contact the author of this tool for assistance. Detailed error
information: The following exception was raised when the property retrieved:
%s') % (name, self._Name, id(self._Object), FormatCOMError(hr, msg, exc,
arg)))
# If we did not import pythoncom, set the value and allow the
outer
# exception handler to catch any errors.
else:
try:
value = getattr(self._Object, name)
except AttributeError, e:
# ArcGIS 10 seems to randomly fail with AttributeError:
DescribeData: Method SpatialReference does not exist.
# If we failed to retrieve SpatialReference, try again
once.
if name == 'SpatialReference':
value = getattr(self._Object, name)
else:
raise
# If we catch ArcGISError here, it is the com_error we just caught.
# Reraise it.
except ArcGISError:
raise
# If we catch some other exception, raise it as ArcGISError.
#
# Note: call raise, rather than Logger.RaiseException. This is
# so the caller can swallow the exception, if needed. Python's
# hasattr function works by calling getattr and seeing if it
# raises an exception. If we call Logger.RaiseException, we
# will break this behavior because we'll cause error messages
# to be reported. We leave it to the caller to call
# Logger.LogExceptionAsError, if needed.
except Exception, e:
raise ArcGISError(_(u'Failed to get the value of the %s attribute
of ArcGIS %s object 0x%08X. This may result from a problem with your inputs
or it may indicate a programming mistake in this tool or ArcGIS itself.
Please check your inputs and try again. Also review any preceding error
messages and the detailed error information that appears at the end of this
message. If you suspect a programming mistake in this tool or ArcGIS, please
contact the author of this tool for assistance. Detailed error information:
The following exception was raised when the property retrieved: %s: %s') %
(name, self._Name, id(self._Object), e.__class__.__name__, unicode(e)))
# If it is a method, create a wrapper, add it to our dictionary of
# wrapped methods, and return the wrapper.
#
# Note: for ArcGIS 10.1, geoprocessing tools are no longer
# returned as methods or functions. Instead they are instances
# of <type 'geoprocessing Tool object'>, which are callable
# like methods.
if isinstance(value, (types.MethodType, types.BuiltinFunctionType,
types.BuiltinMethodType)) or (GeoprocessorManager.GetArcGISMajorVersion() ==
10 and GeoprocessorManager.GetArcGISMinorVersion() >= 1 or
GeoprocessorManager.GetArcGISMajorVersion() > 10) and isinstance(value,
type(getattr(GeoprocessorManager.GetGeoprocessor(), 'Delete_management'))):
# Write the methods's definition.
#
# If we obtained the geoprocessor object through COM Automation,
the
# object is a Python class with normal methods, and we can obtain
# their signatures through inspect.getargspec.
#
# If we obtained the geoprocessor object through
# arcgisscripting.create(), the object is not a class, but it has
# attributes that are "builtin" functions. These functions cannot
be
# inspected so we cannot determine their signatures. In this case,
# we just assume the signature is func(self, *args). This should
# work fine because our callers will not be passing in neither
named
# formal parameters nor keyword dictionaries.
if isinstance(value, types.MethodType):
(args, varargs, varkw, defaults) = inspect.getargspec(value)
sourceCode = 'def %s%s:\n' % (str(name),
inspect.formatargspec(args, varargs, varkw, defaults))
else:
sourceCode = 'def %s(self, *args):\n' % str(name)
# Write the method's body.
sourceCode = sourceCode + ' return
self._InvokeMethod(self._Object.%s)\n' % name
# Compile the method.
_locals = {}
exec sourceCode in globals(), _locals
# Add it to our dictionary of wrapped methods.
self._WrappedMethods[name.lower()] = _locals[name]
# Return it to the caller.
return new.instancemethod(_locals[name], self,
_ArcGISObjectWrapper)
# Log the returned attribute value.
try:
self._LogDebug(_(u'ArcGIS %s object 0x%08X: Get %s returned %s')
% (self._Name, id(self._Object), name, repr(value)))
except:
self._LogDebug(_(u'ArcGIS %s object 0x%08X: Get %s returned %s')
% (self._Name, id(self._Object), name, type(value))) # In ArcGIS 10.2,
repr(value) fails (with TypeError: bad argument type for built-in operation)
when value is a geoprocessing tool like gp.CreateSpatialReference_management.
Try again using type(value)
# The returned value is a property. Convert it from the geoprocessor's
# preferred type to the type we prefer.
value = self._FromGeoprocessorPreferredType(value, name)
# Special case: If the geoprocessor was created with
# arcgisscripting.create(), and we're retrieving a field of a row of a
# cursor, and that field is supposed to be a date, parse a datetime
from
# the string returned by the geoprocessor.
nameLower = name.lower()
if (self._Name == u'Row' or self._Name == u'ReadOnlyRow') and
nameLower != u'getvalue' and nameLower != u'setvalue' and nameLower !=
u'isnull' and nameLower != u'setnull' and not
GeoprocessorManager.GetGeoprocessorIsCOMObject():
fieldDataType = None
if self._FieldTypesDict.has_key(nameLower):
fieldDataType = self._FieldTypesDict[nameLower]
else:
try:
fieldDataType =
GeoprocessorManager.GetWrappedGeoprocessor().ListFields(self._Table,
nameLower).Next().Type.lower()
except:
pass
self._FieldTypesDict[nameLower] = fieldDataType
if fieldDataType == u'date':
value = DateTimeTypeMetadata.ParseDatetimeFromString(value)
# Special case: The Extent property of the Describe object is
# string containing a space-delimited list of the four
# coordinates of the sides of a bounding box. The coordinates
# are floating point numbers. An MGET user reported to
# mget-help that ArcGIS 10.2 apparently will return numbers
# using a comma as the decimal point rather than a period,
# probably on a French operating system or version of ArcGIS.
# It resulted in this failure:
#
# Traceback (most recent call last):
# File "C:\Program
Files\GeoEco\ArcGISToolbox\Scripts\ArcGISLinesFromVectorComponentRasters.py",
line 5, in <module>
#
ExecuteMethodFromCommandLineAsArcGISTool('GeoEco.SpatialAnalysis.Lines',
'ArcGISLines', 'FromVectorComponentRasters')
# ...
# File "C:\Python27\lib\site-packages\GeoEco\Datasets\ArcGIS.py",
line 1403, in _GetLazyPropertyPhysicalValue
# self.SetLazyPropertyValue('CornerCoords',
(float(d.Extent.split()[1]) + d.MeanCellHeight / 2.0,
float(d.Extent.split()[0]) + d.MeanCellWidth / 2.0))
# ValueError: invalid literal for float(): 18,75
#
# So, if the caller is asking for the Extent property of the
# Describe object, replace commas with periods before
# returning it.
if self._Name.lower() == u'describe' and nameLower == u'extent' and
isinstance(value, basestring):
value = value.replace(',', '.')
# Return the attribute value.
return value
def __setattr__(self, name, value):
assert isinstance(name, basestring), u'name must be a string.'
# If the caller is asking for a private attribute (the name starts
with
# an underscore), he wants to set an attribute of the wrapper class
# instance, not of the wrapped object. In this case, we must use the
# object class's implementation of __setattr__.
if isinstance(name, types.StringType):
name = unicode(name)
if name.startswith(u'_'):
return object.__setattr__(self, name, value)
# The caller wants to set an attribute of the wrapped object. Convert
# the value from our preferred type to that preferred by the
# geoprocessor.
valueIsNone = value is None
value = self._ToGeoprocessorPreferredType(value)
# Set the attribute.
try:
# If we imported pythoncom successfully, set the value and
# catch com_error. Raise com_error as ArcGISError. Note:
# call raise, rather than Logger.RaiseException. This is
# so the caller can swallow the exception, if needed.
if sys.modules.has_key('pythoncom'):
try:
# ArcGIS sometimes accepts None, sometimes rejects
# it but will accept an empty string instead. I
# cannot determine a consistent pattern. We try ''
# first. If that fails, try None.
try:
setattr(self._Object, name, value)
except:
if valueIsNone and value == '':
setattr(self._Object, name, None)
else:
raise
except sys.modules['pythoncom'].com_error, (hr, msg, exc,
arg):
from GeoEco.COM import FormatCOMError
raise ArcGISError(_(u'Failed to set the %s property of
ArcGIS %s object 0x%08X to %s. This may result from a problem with your
inputs or it may indicate a programming mistake in this tool or ArcGIS
itself. Please check your inputs and try again. Also review any preceding
error messages and the detailed error information that appears at the end of
this message. If you suspect a programming mistake in this tool or ArcGIS,
please contact the author of this tool for assistance. Detailed error
information: The following exception was raised when the property was
assigned: %s') % (name, self._Name, id(self._Object), repr(value),
FormatCOMError(hr, msg, exc, arg)))
# If we did not import pythoncom, set the value and allow the
outer
# exception handler to catch any errors.
else:
setattr(self._Object, name, value)
# If we catch ArcGISError here, it is the com_error we just caught.
# Reraise it.
except ArcGISError:
raise
# If we catch some other exception, raise it as ArcGISError.
# Note: call raise, rather than Logger.RaiseException. This is
# so the caller can swallow the exception, if needed.
except Exception, e:
raise ArcGISError(_(u'Failed to set the %s property of ArcGIS %s
object 0x%08X to %s. This may result from a problem with your inputs or it
may indicate a programming mistake in this tool or ArcGIS itself. Please
check your inputs and try again. Also review any preceding error messages and
the detailed error information that appears at the end of this message. If
you suspect a programming mistake in this tool or ArcGIS, please contact the
author of this tool for assistance. Detailed error information: The following
exception was raised when the property was assigned: %s: %s') % (name,
self._Name, id(self._Object), repr(value), e.__class__.__name__, unicode(e)))
# Log the set value.
self._LogDebug(_(u'ArcGIS %s object 0x%08X: Set %s to %s') %
(self._Name, id(self._Object), name, repr(value)))
def _InvokeMethod(self, method):
# Convert the arguments from the types we prefer to those preferred
# by the geoprocessor.
(_args, _varargs, _varkw, _locals) =
inspect.getargvalues(inspect.currentframe().f_back)
del _args[0]
for argName in _args:
_locals[argName] =
self._ToGeoprocessorPreferredType(_locals[argName])
if hasattr(method, 'Name') and isinstance(method.Name, basestring)
and len(method.Name) > 0:
if hasattr(method, 'Toolbox') and hasattr(method.Toolbox,
'Alias') and isinstance(method.Toolbox.Alias, basestring) and
len(method.Toolbox.Alias) > 0:
methodName = method.Name + '_' + method.Toolbox.Alias
else:
methodName = method.Name
else:
methodName = method.__name__
if _varargs is not None:
# Hack: In ArcGIS 9.3.1 SP1, ESRI finally fixed NIM010734,
# in which the SetValue method of a Row object obtained
# from a cursor opened with the arcgisscripting
# geoprocessor would not accept None in order to set the
# field to a database NULL value. So, if this is the
# SetValue method of a Row object and the second parameter
# is None, leave it as none.
#
# In all other circumstances, do the normal behavior:
# allow self._ToGeoprocessorPreferredType to translate all
# Nones to empty strings, when the arcgisscripting
# geoprocessor is used.
if self._Name == 'Row' and methodName.lower() == 'setvalue' and
len(_locals[_varargs]) == 2 and _locals[_varargs][1] is None:
_locals[_varargs] =
(self._ToGeoprocessorPreferredType(_locals[_varargs][0]), None)
else:
_locals[_varargs] =
self._ToGeoprocessorPreferredType(_locals[_varargs])
# Build the source code needed to invoke the method.
sourceCode = 'self._Object.%s(' % methodName
for argName in _args:
if not sourceCode.endswith('('):
sourceCode = sourceCode + ', '
sourceCode = sourceCode + '%s=_locals[\'%s\']' % (argName,
argName)
if _varargs is not None:
if not sourceCode.endswith('('):
sourceCode = sourceCode + ', '
sourceCode = sourceCode + '*_locals[\'%s\'] ' % _varargs
sourceCode = sourceCode + ')'
# Before invoking the method, check whether it is a Spatial
# Analyst tool, which is indicated by it ending in "_sa". If
# it is, create a temp directory and set the ScratchWorkspace
# to it.
#
# We do this because some Spatial Analyst tools, particularly
# the Map Algebra tools, create temporary ArcInfo binary grids
# as part of their processing, but they do not delete them
# upon completion. These will accumulate in the user's TEMP
# directory unless a ScratchWorkspace has been set. Once
# several thousand exist, the Spatial Analyst tools will stop
# working (ArcCatalog or ArcMap will crash) until they are
# deleted.
#
# Users typically encounter this only after running several
# thousand Spatial Analyst tools without logging off. Windows
# deletes the contents of the TEMP directory at logoff.
# Nonetheless, certain batch jobs, such as converting
# thousands of HDFs to rasters, are common scenarios for
# GeoEco users so we must protect them from this problem.
try:
tempDir = None
scratchDir = None
if self._Name == u'Geoprocessor' and methodName.endswith('_sa'):
scratchDir = self.ScratchWorkspace
from GeoEco.DataManagement.Directories import
TemporaryDirectory
tempDir = TemporaryDirectory()
self.ScratchWorkspace = tempDir.Path
# Invoke the method.
self._LogDebug(_(u'ArcGIS %s object 0x%08X: Invoking %s%s...') %
(self._Name, id(self._Object), methodName, inspect.formatargvalues(_args,
_varargs, _varkw, _locals)))
try:
# If we imported pythoncom successfully, invoke the method
# and catch com_error. Raise com_error as ArcGISError.
# Note: call raise, rather than Logger.RaiseException.
# This is so the caller can swallow the exception, if
# needed.
if sys.modules.has_key('pythoncom'):
try:
value = eval(sourceCode, globals(), locals())
except sys.modules['pythoncom'].com_error, (hr, msg, exc,
arg):
self._LogReturnedGeoprocessingMessages(methodName)
from GeoEco.COM import FormatCOMError
if self._Name == u'Geoprocessor' and
methodName.lower() not in _ArcGISObjectWrapper._NonGeoprocessingToolMethods:
raise ArcGISError(_(u'The ArcGIS %(tool)s
geoprocessing tool failed when given the parameters %(params)s and reported
%(error)s') % {u'tool': methodName, u'params': inspect.formatargvalues(_args,
_varargs, _varkw, _locals), u'error': FormatCOMError(hr, msg, exc, arg)})
else:
raise ArcGISError(_(u'The %(func)s function of
the ArcGIS %(obj)s object failed when given the parameters %(params)s and
reported %(error)s') % {u'func': methodName, u'obj': self._Name, u'params':
inspect.formatargvalues(_args, _varargs, _varkw, _locals), u'error':
FormatCOMError(hr, msg, exc, arg)})
# If we did not import pythoncom, invoke the method and allow
the
# outer exception handler to catch any errors.
else:
value = eval(sourceCode, globals(), locals())
# If we catch ArcGISError here, it is the com_error we just
caught.
# Reraise it.
except ArcGISError:
raise
# If we catch some other exception, raise it as ArcGISError.
# Note: call raise, rather than Logger.RaiseException. This is
# so the caller can swallow the exception, if needed.
except Exception, e:
self._LogReturnedGeoprocessingMessages(methodName)
if self._Name == u'Geoprocessor' and methodName.lower() not
in _ArcGISObjectWrapper._NonGeoprocessingToolMethods:
raise ArcGISError(_(u'The ArcGIS %(tool)s geoprocessing
tool failed when given the parameters %(params)s and reported %(error)s:
%(msg)s') % {u'tool': methodName, u'params': inspect.formatargvalues(_args,
_varargs, _varkw, _locals), u'error': e.__class__.__name__, u'msg':
unicode(e)})
else:
raise ArcGISError(_(u'The %(func)s function of the ArcGIS
%(obj)s object failed when given the parameters %(params)s and reported
%(error)s') % {u'func': methodName, u'obj': self._Name, u'params':
inspect.formatargvalues(_args, _varargs, _varkw, _locals), u'error':
e.__class__.__name__, u'msg': unicode(e)})
# The method executed successfully. Log any geoprocessing
messages it
# generated.
self._LogReturnedGeoprocessingMessages(methodName)
# Log the returned value.
self._LogDebug(_(u'ArcGIS %s object 0x%08X: %s returned %s') %
(self._Name, id(self._Object), methodName, repr(value)))
# If we created a temporary directory to manage the rasters
# leaked by the Spatial Analyst tools, delete it now.
finally:
if tempDir is not None:
try:
del tempDir
except:
pass
self.ScratchWorkspace = scratchDir
# Convert the returned value from the geoprocessor's preferred type to
# the type we prefer.
value = self._FromGeoprocessorPreferredType(value, methodName,
*(tuple(map(_locals.get, _args)) + _locals[_varargs]))
# Special case: If the geoprocessor was created with
# arcgisscripting.create(), and we're retrieving a field of a row of a
# cursor, and that field is supposed to be a date, parse a datetime
from
# the string returned by the geoprocessor.
if not GeoprocessorManager.GetGeoprocessorIsCOMObject() and value is
not None:
methodName = methodName.lower()
if self._Name == u'Geoprocessor' and (methodName ==
u'searchcursor' or methodName == u'insertcursor' or methodName ==
u'updatecursor'):
if len(_args) > 0:
value._Table = _locals[_args[0]]
else:
value._Table = _locals[_varargs][0]
value._FieldTypesDict = {}
elif (self._Name == u'SearchCursor' or self._Name ==
u'UpdateCursor') and methodName == u'next' or self._Name == u'InsertCursor'
and methodName == u'newrow':
value._Table = self._Table
value._FieldTypesDict = self._FieldTypesDict
elif (self._Name == u'Row' or self._Name == u'ReadOnlyRow') and
methodName == u'getvalue':
if len(_args) > 0:
field = _locals[_args[0]].lower()
else:
field = _locals[_varargs][0].lower()
fieldDataType = None
if self._FieldTypesDict.has_key(field):
fieldDataType = self._FieldTypesDict[field]
else:
try:
fieldDataType =
GeoprocessorManager.GetWrappedGeoprocessor().ListFields(self._Table,
field).Next().Type.lower()
except:
pass
self._FieldTypesDict[field] = fieldDataType
if fieldDataType == u'date':
value =
DateTimeTypeMetadata.ParseDatetimeFromString(value)
# Return the returned value.
return value
_NonGeoprocessingToolMethods = {
'adderror' : None,
'addmessage' : None,
'addreturnmessage' : None,
'addtoolbox' : None,
'addwarning' : None,
'checkextension' : None,
'checkinextension' : None,
'checkoutextension' : None,
'checkproduct' : None,
'clearenvironment' : None,
'command' : None,
'copyparameter' : None,
'createobject' : None,
'createrandomvaluegenerator' : None,
'createscratchname' : None,
'createuniquename' : None,
'describe' : None,
'exists' : None,
'getmessage' : None,
'getmessages' : None,
'getparameter' : None,
'getparameterastext' : None,
'getparametercount' : None,
'getparametervalue' : None,
'getreturncode' : None,
'getseverity' : None,
'getsystemenvironment' : None,
'insertcursor' : None,
'issynchronous' : None,
'listdatasets' : None,
'listenvironments' : None,
'listfeatureclasses' : None,
'listfields' : None,
'listindexes' : None,
'listrasters' : None,
'listtables' : None,
'listtoolboxes' : None,
'listtools' : None,
'listworkspaces' : None,
'loadsettings' : None,
'parsefieldname' : None,
'parsetablename' : None,
'productinfo' : None,
'qualifyfieldname' : None,
'qualifytablename' : None,
'refreshcatalog' : None,
'removetoolbox' : None,
'resetenvironments' : None,
'savesettings' : None,
'searchcursor' : None,
'setparameter' : None,
'setparameterastext' : None,
'setproduct' : None,
'testschemalock' : None,
'updatecursor' : None,
'usage' : None,
'validatefieldname' : None,
'validatetablename' : None
}
def _LogReturnedGeoprocessingMessages(self, methodName):
# Only log the messages returned by the geoprocessor if the
# invoked method appears to be a geoprocessing tool. The other
# methods of the geoprocessor, the ones that are not
# geoprocessing tools, do not report any messages. If the
# geoprocessor object was created with
# arcgisscripting.create(), it will not clear out the message
# queue when one of these non-geoprocessing-tool methods is
# called. If the messages queue is examined again, it will
# have the same messages as before. For example, if
# SingleOutputMapAlgebra_sa is called, followed by
# RefreshCatalog, the messages from SingleOutputMapAlgebra_sa
# will still be in the queue following the call to
# RefreshCatalog. We must avoid logging these again, as if
# they were reported by RefreshCatalog. See ticket #132.
#
# This behavior of the geoprocessor is a change introduced in
# ArcGIS 9.2 and only seems to occur if the geoprocessor was
# created with arcgisscripting.create(). But we do the same
# logic in all circumstances. This probably yields a minor
# performance gain when calling non-geoprocessing-tool methods
# of the geoprocessor.
if self._Name == u'Geoprocessor' and not
_ArcGISObjectWrapper._NonGeoprocessingToolMethods.has_key(methodName.lower()):
i = 0
try:
geoprocessor = GeoprocessorManager.GetGeoprocessor()
if geoprocessor is not None:
try:
while i < geoprocessor.MessageCount:
sev = geoprocessor.GetSeverity(i)
if sev == 0:
self._LogInfo(geoprocessor.GetMessage(i))
elif sev == 1:
self._LogWarning(geoprocessor.GetMessage(i))
else:
self._LogError(geoprocessor.GetMessage(i))
i += 1
finally:
del geoprocessor
except:
pass
def _ToGeoprocessorPreferredType(self, value):
# Process every item in lists and tuples.
if isinstance(value, types.ListType):
return self._ToGeoprocessorPreferredTypeList(value)
if isinstance(value, types.TupleType):
l = list(value)
l = self._ToGeoprocessorPreferredTypeList(l)
return tuple(l)
# When the geoprocessor is obtained through arcgisscripting.create(),
it
# expects 8-bit strings.
geoprocessorIsCOMObject =
GeoprocessorManager.GetGeoprocessorIsCOMObject()
if not geoprocessorIsCOMObject and isinstance(value,
types.UnicodeType):
return UnicodeToUserPreferredEncoding(value)
# When the geoprocessor is obtained through COM Automation, it expects
# dates as pywintypes.TimeType instances. When it is obtained through
# arcgisscripting.create(), it expects strings.
if isinstance(value, datetime.datetime):
if geoprocessorIsCOMObject:
import pywintypes
return pywintypes.Time((value.year, value.month, value.day,
value.hour, value.minute, value.second, 0, 0, 0))
else:
return value.strftime('%Y-%m-%d %H:%M:%S')
elif isinstance(value, datetime.date):
if geoprocessorIsCOMObject:
import pywintypes
return pywintypes.Time((value.year, value.month, value.day,
0, 0, 0, 0, 0, 0))
else:
return value.strftime('%Y-%m-%d 00:00:00')
# When the geoprocessor is obtained through arcgisscripting.create(),
it
# expects integers rather than booleans.
#
# NOTE: This is commented out beacuse it seems the geoprocessor will
# accept booleans, even though it returns integers.
## if not geoprocessorIsCOMObject and isinstance(value,
types.BooleanType):
## return int(value)
# Under some scenarios, the geoprocessor does not like to set
# attributes to None (see, for example, Trac Ticket #505). But
# it seems to usually allow setting attributes to an empty
# string in place of None.
if isinstance(value, types.NoneType):
return ''
# If the value is wrapped with a _ArcGISObjectWrapper, return the
# wrapped object.
if isinstance(value, _ArcGISObjectWrapper):
return value._Object
# The value is fine as it is. Just return it.
return value
def _ToGeoprocessorPreferredTypeList(self, value):
for i in range(len(value)):
value[i] = self._ToGeoprocessorPreferredType(value[i])
return value
def _FromGeoprocessorPreferredType(self, value, name, *args):
# Process every item in lists and tuples.
if isinstance(value, types.ListType):
return self._FromGeoprocessorPreferredTypeList(value)
if isinstance(value, types.TupleType):
l = list(value)
l = self._FromGeoprocessorPreferredTypeList(l)
return tuple(l)
# When the geoprocessor is obtained through arcgisscripting.create(),
it
# returns 8-bit strings, but if we obtain it through COM Automation,
it
# returns Unicode strings. We always prefer Unicode, so ensure it is
in
# Unicode.
if isinstance(value, types.StringType):
return UserPreferredEncodingToUnicode(value)
# When the geoprocessor is obtained through COM Automation, it
# returns dates as pywintypes.TimeType instances. We prefer
# datetime.datetime instances.
if not sys.modules.has_key('pywintypes'):
try:
import pywintypes # It is not really necessary to do
this, but because I'm fixing this right before MGET 0.7 is released, I'm
being extra careful.
except:
pass
if sys.modules.has_key('pywintypes') and isinstance(value,
sys.modules['pywintypes'].TimeType):
return datetime.datetime(value.year, value.month, value.day,
value.hour, value.minute, value.second, value.msec)
# If it is a class instance, wrap it in _ArcGISObjectWrapper.
if not isinstance(value, (types.BooleanType, types.FloatType,
types.IntType, types.ListType, types.LongType, types.NoneType, basestring,
datetime.datetime)):
wrap = False
objName = self._LookupReturnedObjectName(name, *args)
try:
if objName is not None or isinstance(value,
types.InstanceType) or inspect.getmodule(type(value)) !=
sys.modules[u'__builtin__']: # Shouldn't raise an exception, but I'm
suspicious of inspect.getmodule
wrap = True
except:
pass
if wrap:
return _ArcGISObjectWrapper(value, objName)
# The value is fine as it is. Just return it.
return value
def _FromGeoprocessorPreferredTypeList(self, value):
for i in range(len(value)):
value[i] = self._FromGeoprocessorPreferredType(value[i],
u'<unknown>')
return value
def _LookupReturnedObjectName(self, name, *args):
_Name = self._Name.lower()
name = name.lower()
if not _ArcGISObjectWrapper._NameMap.has_key(_Name):
return None
if not isinstance(_ArcGISObjectWrapper._NameMap[_Name],
types.DictType):
return _ArcGISObjectWrapper._NameMap[_Name]
if not _ArcGISObjectWrapper._NameMap[_Name].has_key(name):
return None
if not isinstance(_ArcGISObjectWrapper._NameMap[_Name][name],
types.DictType):
return _ArcGISObjectWrapper._NameMap[_Name][name]
d = _ArcGISObjectWrapper._NameMap[_Name][name]
for arg in args:
if isinstance(arg, basestring):
arg = unicode(arg).lower()
if not d.has_key(arg):
return None
if not isinstance(d[arg], types.DictType):
return d[arg]
d = d[arg]
return None
_NameMap = {
u'geoprocessor' : {
u'createobject' : {
u'spatialreference' : u'SpatialReference',
u'valuetable' : u'ValueTable',
u'fieldinfo' : u'FieldInfo',
u'array' : u'Array',
u'point' : u'Point',
u'fieldmappings' : u'FieldMappings',
u'fieldmap' : u'FieldMap',
u'field' : u'Field'},
u'describe' : u'Describe',
u'listfields' : u'Fields',
u'listindexes' : u'Indexes',
u'listrasters' : u'Enumeration',
u'listtables' : u'Enumeration',
u'listworkspaces' : u'Enumeration',
u'listdatasets' : u'Enumeration',
u'listfeatureclasses' : u'Enumeration',
u'listenvironments' : u'Enumeration',
u'listtoolboxes' : u'Enumeration',
u'listtools' : u'Enumeration',
u'insertcursor' : u'InsertCursor',
u'searchcursor' : u'SearchCursor',
u'updatecursor' : u'UpdateCursor'},
u'spatialreference' : None,
u'valuetable' : None,
u'fieldinfo' : { u'getfield' : u'Field'},
u'array' : None, # Some methods return objects but we
can't tell what they are from the method signatures.
u'point' : None,
u'fieldmappings' : { u'fields' : u'Fields', u'getfieldmap' :
u'FieldMap'},
u'fieldmap' : { u'outputfield' : u'Field'},
u'field' : None,
u'fields' : { u'next' : u'Field'},
u'indexes' : { u'next' : u'Index' },
u'index' : { u'fields' : u'Fields' },
u'searchcursor' : { u'next' : u'ReadOnlyRow' },
u'insertcursor' : { u'newrow' : u'Row' },
u'updatecursor' : { u'next' : u'Row' },
u'readonlyrow' : { u'shape' : u'Geometry', u'GetValue' : { u'shape' :
u'Geometry' } },
u'row' : { u'shape' : u'Geometry', u'GetValue' : { u'shape' :
u'Geometry' } },
u'geometry': { u'getpart' : u'Point or Array' }, #
Geometry.GetPart returns either Point or Array, depending on what type of
feature it is.
u'describe' : {
u'fieldinfo' : u'FieldInfo',
u'fields' : u'Fields',
u'indexes' : u'Indexes',
u'spatialreference' : u'SpatialReference',
u'fidset' : u'FIDSet',
u'connectionproperties' : u'PropertySet',
u'tolerances' : u'PropertySet'},
u'fidset' : None,
u'PropertySet' : None}
###############################################################################
# Metadata: module
###############################################################################
from GeoEco.Metadata import *
from GeoEco.Types import *
AddModuleMetadata(shortDescription=_(u'Provides utility functions for
interacting with the ESRI ArcGIS software package.'))
###############################################################################
# Metadata: GeoprocessorManager class
###############################################################################
AddClassMetadata(GeoprocessorManager,
shortDescription=_(u'Manages the instance of the ArcGIS geoprocessor
object used whenever any GeoEco function needs to invoke ArcGIS tools.'),
isExposedAsCOMServer=True,
comIID=u'{3DAAF9BD-2C7F-4A0B-8AB1-8975103F3E78}',
comCLSID=u'{6E4B25C1-0E1D-496B-A661-AC75ADCB24C8}')
# Public properties
AddPropertyMetadata(GeoprocessorManager.Geoprocessor,
typeMetadata=AnyObjectTypeMetadata(canBeNone=True),
shortDescription=_(u'The ArcGIS geoprocessor object used whenever any
GeoEco function needs to invoke ArcGIS tools.'),
longDescription=_(
u"""This property is a singleton; all Python modules running in the same
instance of the Python interpreter share the same value for this property.
This
property remains empty until it is explicitly set, or the
InitializeGeoprocessor
method is explicitly invoked, or a GeoEco function that has a dependency on
ArcGIS is invoked (in which case it will invoke InitializeGeoprocessor).
If you want to invoke GeoEco functions from your own ArcGIS geoprocessing
script
and you have already obtained a geoprocessor object, you should set this
property to that object before invoking any other GeoEco functions. Failing to
do so will cause GeoEco to allocate its own geoprocessor object, which can
yield
unpredictable results. (As far as I can tell, the ArcGIS tools still work
correctly, but log messages may not end up in the ArcGIS GUIs.)
If your geoprocessing script has not yet obtained the geoprocessor object, you
may allow the GeoEco functions to obtain one when they first need it and then
retrieve it by getting the value of this property.
If you want to invoke GeoEco functions from something that is not a
"geoprocessing script" (a program that does not invoke any ArcGIS
geoprocessing tools directly), then you should ignore this property and
allow the GeoEco functions to obtain and use their own geoprocessor object.
See the documentation for InitializeGeoprocessor for more information about
this
property.
*Note to GeoEco developers:* Generally, GeoEco functions should *not* use this
property; they should use WrappedGeoprocessor instead. That property
implements
a wrapper around the geoprocessor that logs debug messages every time the
geoprocessor is invoked."""),
isExposedToPythonCallers=True,
isExposedByCOM=True)
AddPropertyMetadata(GeoprocessorManager.WrappedGeoprocessor,
typeMetadata=AnyObjectTypeMetadata(canBeNone=True),
shortDescription=_(u'The Geoprocessor property, wrapped by a class that
logs messages whenever the geoprocessor is accessed.'),
longDescription=_(
u"""This property is a singleton; all Python modules running in the same
instance of the Python interpreter share the same value for this property. It
is
initialized whenever the Geoprocessor property is initialized; see the
documentation for that property for more information.
This property is actually a wrapper class around the ArcGIS geoprocessor
object.
The wrapper exports the same interface as the wrapped object but logs a debug
message every time a method is invoked or a property is accessed. By default,
these debug messages are discarded by the GeoEco logging infrastructure. You
can
enable them by initializing the Logger class with a custom configuration file
or by editing the default configuration file. See the Logger class
documentation
for more information.
All GeoEco functions use WrappedGeoprocessor to access the geoprocessor,
rather
than the Geoprocessor property, so that debug messages are reported whenever
any
function accesses the geoprocessor. External callers are welcome to use
WrappedGeoprocessor as well, but they should consider using Geoprocessor
instead, to completely eliminate the chance that a bug in the wrapper would
affect their code."""),
isExposedToPythonCallers=True,
isExposedByCOM=True)
AddPropertyMetadata(GeoprocessorManager.GeoprocessorIsCOMObject,
typeMetadata=BooleanTypeMetadata(),
shortDescription=_(u'True if the object returned by the Geoprocessor
property is a COM Automation object. False if it is some other kind of object
(such as the object returned by arcgisscripting.create()).'),
isExposedToPythonCallers=True,
isExposedByCOM=True)
AddPropertyMetadata(GeoprocessorManager.ArcGISMajorVersion,
typeMetadata=IntegerTypeMetadata(canBeNone=True),
shortDescription=_(u'The major version number for ArcGIS, if it is
installed on the machine.'),
longDescription=_(u'This property is empty if ArcGIS is not installed on
the machine.'),
isExposedToPythonCallers=True,
isExposedByCOM=True)
AddPropertyMetadata(GeoprocessorManager.ArcGISMinorVersion,
typeMetadata=IntegerTypeMetadata(canBeNone=True),
shortDescription=_(u'The minor version number for ArcGIS, if it is
installed on the machine.'),
longDescription=_(u'This property is empty if ArcGIS is not installed on
the machine.'),
isExposedToPythonCallers=True,
isExposedByCOM=True)
AddPropertyMetadata(GeoprocessorManager.ArcGISServicePack,
typeMetadata=IntegerTypeMetadata(canBeNone=True),
shortDescription=_(u'The service pack number for ArcGIS, if it is
installed on the machine.'),
longDescription=_(u'This property is empty if ArcGIS is not installed on
the machine.'),
isExposedToPythonCallers=True,
isExposedByCOM=True)
# Public method: GeoprocessorManager.GetGeoprocessor
AddMethodMetadata(GeoprocessorManager.GetGeoprocessor,
shortDescription=_(u'Returns the value of the Geoprocessor property.'),
isExposedToPythonCallers=True)
AddArgumentMetadata(GeoprocessorManager.GetGeoprocessor, u'cls',
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=GeoprocessorManager),
description=_(u'%s class or an instance of it.') %
GeoprocessorManager.__name__)
AddResultMetadata(GeoprocessorManager.GetGeoprocessor, u'geoprocessor',
typeMetadata=AnyObjectTypeMetadata(canBeNone=True),
description=_(u'The value of the Geoprocessor property.'))
# Public method: GeoprocessorManager.SetGeoprocessor
AddMethodMetadata(GeoprocessorManager.SetGeoprocessor,
shortDescription=_(u'Sets the value of the Geoprocessor property.'),
isExposedToPythonCallers=True)
AddArgumentMetadata(GeoprocessorManager.SetGeoprocessor, u'cls',
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=GeoprocessorManager),
description=_(u'%s class or an instance of it.') %
GeoprocessorManager.__name__)
AddArgumentMetadata(GeoprocessorManager.SetGeoprocessor, u'geoprocessor',
typeMetadata=AnyObjectTypeMetadata(),
description=_(u'The ArcGIS geoprocessor object obtained from COM
Automation or the arcgisscripting Python module. See the documentation for
the Geoprocessor property for more information.'))
# Public method: GeoprocessorManager.GetWrappedGeoprocessor
AddMethodMetadata(GeoprocessorManager.GetWrappedGeoprocessor,
shortDescription=_(u'Returns the value of the WrappedGeoprocessor
property.'),
isExposedToPythonCallers=True)
AddArgumentMetadata(GeoprocessorManager.GetWrappedGeoprocessor, u'cls',
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=GeoprocessorManager),
description=_(u'%s class or an instance of it.') %
GeoprocessorManager.__name__)
AddResultMetadata(GeoprocessorManager.GetWrappedGeoprocessor, u'geoprocessor',
typeMetadata=AnyObjectTypeMetadata(canBeNone=True),
description=_(u'The value of the WrappedGeoprocessor property.'))
# Public method: GeoprocessorManager.GetArcGISMajorVersion
AddMethodMetadata(GeoprocessorManager.GetArcGISMajorVersion,
shortDescription=_(u'Returns the value of the ArcGISMajorVersion
property.'),
isExposedToPythonCallers=True)
AddArgumentMetadata(GeoprocessorManager.GetArcGISMajorVersion, u'cls',
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=GeoprocessorManager),
description=_(u'%s class or an instance of it.') %
GeoprocessorManager.__name__)
AddResultMetadata(GeoprocessorManager.GetArcGISMajorVersion, u'majorVersion',
typeMetadata=IntegerTypeMetadata(canBeNone=True),
description=_(u'The value of the ArcGISMajorVersion property.'))
# Public method: GeoprocessorManager.GetArcGISMinorVersion
AddMethodMetadata(GeoprocessorManager.GetArcGISMinorVersion,
shortDescription=_(u'Returns the value of the ArcGISMinorVersion
property.'),
isExposedToPythonCallers=True)
AddArgumentMetadata(GeoprocessorManager.GetArcGISMinorVersion, u'cls',
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=GeoprocessorManager),
description=_(u'%s class or an instance of it.') %
GeoprocessorManager.__name__)
AddResultMetadata(GeoprocessorManager.GetArcGISMinorVersion, u'minorVersion',
typeMetadata=IntegerTypeMetadata(canBeNone=True),
description=_(u'The value of the ArcGISMinorVersion property.'))
# Public method: GeoprocessorManager.GetArcGISServicePack
AddMethodMetadata(GeoprocessorManager.GetArcGISServicePack,
shortDescription=_(u'Returns the value of the ArcGISServicePack
property.'),
isExposedToPythonCallers=True)
AddArgumentMetadata(GeoprocessorManager.GetArcGISServicePack, u'cls',
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=GeoprocessorManager),
description=_(u'%s class or an instance of it.') %
GeoprocessorManager.__name__)
AddResultMetadata(GeoprocessorManager.GetArcGISServicePack, u'servicePack',
typeMetadata=IntegerTypeMetadata(canBeNone=True),
description=_(u'The value of the ArcGISMinorVersion property.'))
# Public method: GeoprocessorManager.InitializeGeoprocessor
AddMethodMetadata(GeoprocessorManager.InitializeGeoprocessor,
shortDescription=_(u'Initializes the Geoprocessor property with a new
ArcGIS geoprocessor object.'),
longDescription=_(
u"""If you want to use GeoEco's GeoprocessorManager to instantiate the
geoprocessor, you should either explicitly invoke this method or call
a GeoEco function that requires ArcGIS; the GeoEco function will
invoke this method on your behalf.
If you do not want to use GeoEco's GeoprocessorManager to instantiate
the geoprocessor, you should instantiate it yourself and call
GeoprocessorManager.SetGeoprocessor. GeoEco will cache a reference to
your geoprocessor and not allocate its own instance.
If the Geoprocessor property has already been initialized with a
geoprocessor object and forceCOMInstantiation and
forcePythonInstantiation are both False, this method does nothing. If
either forceCOMInstantiation or forcePythonInstantiation are True,
this method will raise a RuntimeError if the geoprocessor was
previously instantiated with the opposite method.
You should only pass True for forceCOMInstantiation or
forcePythonInstantiation if you plan to perform geoprocessing
operations that truly require one type of geoprocessor or the other.
If both are False, this method will automatically select the best
technique, as follows:
* If ArcGIS 9.1 is installed, COM Automation will always be used.
* If ArcGIS 9.2 is installed, arcgisscripting will be used if the
script is executing under Python 2.4. Otherwise COM Automation will
be used.
* If ArcGIS 9.3 is installed, arcgisscripting will be used if the
script is executing under Python 2.5. Otherwise COM Automation will
be used.
IMPORTANT NOTE: If arcgisscripting is used to instantiate the
geoprocessor, the arcgisscripting.create function will always be
called without any parameters, regardless of which version of ArcGIS
is installed. This means that, even if ArcGIS 9.3 or later is
installed, the instantiated geoprocessor will always use the inteface
from ArcGIS 9.2."""),
isExposedToPythonCallers=True,
isExposedByCOM=True)
AddArgumentMetadata(GeoprocessorManager.InitializeGeoprocessor, u'cls',
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=GeoprocessorManager),
description=_(u'%s class or an instance of it.') %
GeoprocessorManager.__name__)
AddArgumentMetadata(GeoprocessorManager.InitializeGeoprocessor,
u'forceCOMInstantiation',
typeMetadata=BooleanTypeMetadata(),
description=_(
u"""If True, the geoprocessor will be instantiated with Microsoft COM
Automation, regardless of what version of ArcGIS is installed. The
win32com.client.Dispatch function from the "Python for Windows
extensions" Python package (also known as "pywin32") will be used to
perform the instantiation."""))
AddArgumentMetadata(GeoprocessorManager.InitializeGeoprocessor,
u'forcePythonInstantiation',
typeMetadata=BooleanTypeMetadata(),
description=_(
u"""If True, the geoprocessor will be instantiated by calling the
create function in the arcgisscripting Python module, regardless of
which version of ArcGIS is installed."""))
# Public method: GeoprocessorManager.RefreshCatalog
AddMethodMetadata(GeoprocessorManager.RefreshCatalog,
shortDescription=_(u'Refreshes the ArcGIS catalog\'s cached view of the
specified directory.'),
longDescription=_(
u"""The ArcGIS geoprocessing system interacts with the file system through the
ArcGIS catalog, a cached view of the files and directories on the computer. It
is important that the catalog be "refreshed" after any changes are made to
files
or directories. Otherwise the ArcGIS geoprocessor will not know about the
changes and operate off an obsolete view of the file system, ultimately
causing
subsequent geoprocessing operations to fail.
Most GeoEco methods automatically refresh the ArcGIS catalog when it is
necessary to do so. Some methods allow you to explictly control whether the
refresh occurs. In general, you should always allow the catalog to be
refreshed.
The main scenario in which it is appropriate to prevent it is when you are
making many consecutive changes inside a directory and do not want to incur
the
performance hit of refreshing the catalog after each change. In that scenario,
you can use this method to refresh the catalog's view of that directory when
you
are done.
If the GeoprocessorManager class is not holding an instance of the ArcGIS
geoprocessor, then this parameter is ignored. It will be holding one under the
following circumstances:
* Your code invokes a method of some class that has a dependency on ArcGIS and
internally uses the geoprocessor to do whatever work it needs to do. In
this,
scenario, that method will cause
GeoprocessorManager.InitializeGeoprocessor() to
be called. This is the most common scenario.
* Your code explicitly initializes the geoprocessor by calling
GeoprocessorManager.InitializeGeoprocessor().
* Your code provides the GeoprocessorManager with a geoprocessor instance by
calling GeoprocessorManager.SetGeoprocessor()."""),
isExposedToPythonCallers=True,
isExposedByCOM=True)
AddArgumentMetadata(GeoprocessorManager.RefreshCatalog, u'cls',
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=GeoprocessorManager),
description=_(u'%s class or an instance of it.') %
GeoprocessorManager.__name__)
AddArgumentMetadata(GeoprocessorManager.RefreshCatalog, u'directory',
typeMetadata=DirectoryTypeMetadata(mustExist=True),
description=_(
u"""Parent directory of the files or directories that have changed. For
example,
if you added three files to C:\\Data, you should pass C:\\Data as this
parameter. If you just created C:\\Data, then you need to pass C:\\ for this
parameter."""))
# Public method: GeoprocessorManager.ArcGISObjectExists
AddMethodMetadata(GeoprocessorManager.ArcGISObjectExists,
shortDescription=_(u'Tests that a given path to an ArcGIS object exists
and that the object is of a given type.'),
longDescription=_(
u"""This method uses the ArcGIS geoprocessor's Exists and Describe
functions to check the existence and type of the object."""),
isExposedToPythonCallers=True,
isExposedByCOM=True)
AddArgumentMetadata(GeoprocessorManager.ArcGISObjectExists, u'cls',
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=GeoprocessorManager),
description=_(u'%s class or an instance of it.') %
GeoprocessorManager.__name__)
AddArgumentMetadata(GeoprocessorManager.ArcGISObjectExists, u'path',
typeMetadata=UnicodeStringTypeMetadata(),
description=_(u'Path to the object (e.g. a file, directory, raster,
shapefile, table, etc.).'))
AddArgumentMetadata(GeoprocessorManager.ArcGISObjectExists, u'correctTypes',
typeMetadata=ListTypeMetadata(elementType=UnicodeStringTypeMetadata()),
description=_(
u"""List of data types that the object is expected to be, chosen from
the possible values of the DataType property of the object returned by
the geoprocessor's Describe function. Please see the ArcGIS
geoprocessing documentation for the possible data type strings."""))
AddArgumentMetadata(GeoprocessorManager.ArcGISObjectExists,
u'typeDisplayName',
typeMetadata=UnicodeStringTypeMetadata(),
description=_(
u"""Name of the expected data type of the object to display in logging
messages. This is usually a more generic name than the entries that
appear in correctTypes. For example, if the object is expected to be
some kind of table, correctTypes may contain five or ten possible
values, while typeDisplayName might simply be "table"."""))
AddResultMetadata(GeoprocessorManager.ArcGISObjectExists, u'exists',
typeMetadata=BooleanTypeMetadata(),
description=_(u'True if the geoprocessor\'s Exists function reports that
the specified path exists.'))
AddResultMetadata(GeoprocessorManager.ArcGISObjectExists, u'isCorrectType',
typeMetadata=BooleanTypeMetadata(),
description=_(u'True if the geoprocessor\'s Describe function reports
that the specified path is one of the types of objects specified by
correctTypes.'))
# Public method: GeoprocessorManager.DeleteArcGISObject
AddMethodMetadata(GeoprocessorManager.DeleteArcGISObject,
shortDescription=_(u'Deletes the specified ArcGIS object, if it exists.'),
longDescription=_(
u"""If the object does not exist, no error will be raised. If the
object exists but the geoprocessor's Describe function reports that it
is not one of the types specified by the correctTypes parameter, a
ValueError will be raised. If it exists and is one of the correct
types, it will be deleted with the geoprocessor's Delete_management
function."""),
isExposedToPythonCallers=True,
isExposedByCOM=True)
CopyArgumentMetadata(GeoprocessorManager.ArcGISObjectExists, u'cls',
GeoprocessorManager.DeleteArcGISObject, u'cls')
CopyArgumentMetadata(GeoprocessorManager.ArcGISObjectExists, u'path',
GeoprocessorManager.DeleteArcGISObject, u'path')
CopyArgumentMetadata(GeoprocessorManager.ArcGISObjectExists, u'correctTypes',
GeoprocessorManager.DeleteArcGISObject, u'correctTypes')
CopyArgumentMetadata(GeoprocessorManager.ArcGISObjectExists,
u'typeDisplayName', GeoprocessorManager.DeleteArcGISObject,
u'typeDisplayName')
# Public method: GeoprocessorManager.CopyArcGISObject
AddMethodMetadata(GeoprocessorManager.CopyArcGISObject,
shortDescription=_(u'Copies the specified ArcGIS object.'),
longDescription=_(
u"""A ValueError will be raised if the source object does not exist or
the geoprocessor's Describe function reports that it is not one of the
types specified by the correctTypes parameter. A ValueError will also
be raised if the destination object exists but overwriteExisting is
False or if the object is not one of the correct types. If the
destination object exists and is a correct type, it will be deleted
with the geoprocessor's Delete_management function prior to making the
copy. The source object will be copied with the geoprocessor's
CopyFeatures_management (if the source object is a feature class,
shapefile, or feature layer) or the Copy_management function (if the
source object is some other type)."""),
isExposedToPythonCallers=True,
isExposedByCOM=True)
CopyArgumentMetadata(GeoprocessorManager.ArcGISObjectExists, u'cls',
GeoprocessorManager.CopyArcGISObject, u'cls')
AddArgumentMetadata(GeoprocessorManager.CopyArcGISObject, u'source',
typeMetadata=UnicodeStringTypeMetadata(),
description=_(u'Path to the object to copy (e.g. a file, directory,
raster, shapefile, table, etc.).'))
AddArgumentMetadata(GeoprocessorManager.CopyArcGISObject, u'destination',
typeMetadata=UnicodeStringTypeMetadata(),
description=_(u'Path to the copy to create.'))
AddArgumentMetadata(GeoprocessorManager.CopyArcGISObject,
u'overwriteExisting',
typeMetadata=BooleanTypeMetadata(),
description=_(u'If True, the destination object will be overwritten.'))
CopyArgumentMetadata(GeoprocessorManager.ArcGISObjectExists, u'correctTypes',
GeoprocessorManager.CopyArcGISObject, u'correctTypes')
CopyArgumentMetadata(GeoprocessorManager.ArcGISObjectExists,
u'typeDisplayName', GeoprocessorManager.CopyArcGISObject, u'typeDisplayName')
# Public method: GeoprocessorManager.MoveArcGISObject
AddMethodMetadata(GeoprocessorManager.MoveArcGISObject,
shortDescription=_(u'Movies the specified ArcGIS object.'),
longDescription=_(
u"""A ValueError will be raised if the source object does not exist or
the geoprocessor's Describe function reports that it is not one of the
types specified by the correctTypes parameter. A ValueError will also
be raised if the destination object exists but overwriteExisting is
False or if the object is not one of the correct types. If the
destination object exists and is a correct type, it will be deleted
with the geoprocessor's Delete_management function prior to making the
copy. The source object will be copied with the geoprocessor's
CopyFeatures_management (if the source object is a feature class,
shapefile, or feature layer) or the Copy_management function (if the
source object is some other type), and then deleted with the
Delete_management function."""),
isExposedToPythonCallers=True,
isExposedByCOM=True)
CopyArgumentMetadata(GeoprocessorManager.ArcGISObjectExists, u'cls',
GeoprocessorManager.MoveArcGISObject, u'cls')
AddArgumentMetadata(GeoprocessorManager.MoveArcGISObject, u'source',
typeMetadata=UnicodeStringTypeMetadata(),
description=_(u'Path to the object to move (e.g. a file, directory,
raster, shapefile, table, etc.).'))
AddArgumentMetadata(GeoprocessorManager.MoveArcGISObject, u'destination',
typeMetadata=UnicodeStringTypeMetadata(),
description=_(u'New path for the object.'))
CopyArgumentMetadata(GeoprocessorManager.CopyArcGISObject,
u'overwriteExisting', GeoprocessorManager.MoveArcGISObject,
u'overwriteExisting')
CopyArgumentMetadata(GeoprocessorManager.ArcGISObjectExists, u'correctTypes',
GeoprocessorManager.MoveArcGISObject, u'correctTypes')
CopyArgumentMetadata(GeoprocessorManager.ArcGISObjectExists,
u'typeDisplayName', GeoprocessorManager.MoveArcGISObject, u'typeDisplayName')
# Public method: GeoprocessorManager.GetUniqueLayerName
AddMethodMetadata(GeoprocessorManager.GetUniqueLayerName,
shortDescription=_(u'Returns a randomly generated string that may be used
as the name of a new geoprocessing layer.'),
longDescription=_(
u"""This function loops through random names until it finds one for
which the geoprocessors Exists function returns False."""),
isExposedToPythonCallers=True,
isExposedByCOM=True)
CopyArgumentMetadata(GeoprocessorManager.ArcGISObjectExists, u'cls',
GeoprocessorManager.GetUniqueLayerName, u'cls')
AddResultMetadata(GeoprocessorManager.GetUniqueLayerName, u'name',
typeMetadata=UnicodeStringTypeMetadata(),
description=_(u'Randomly generated string that may be used as the name of
a geoprocessing layer.'))
###############################################################################
# Names exported by this module
###############################################################################
__all__ = ['GeoprocessorManager',
'ArcGISDependency',
'ArcGISProductDependency',
'ArcGISExtensionDependency',
'ArcGISError',
'ValidateMethodMetadataForExposureAsArcGISTool']
Thanks for your interest in MGET. The problem here is that ESRI's ArcGIS
Python library (arcgisscripting, wrapped by arcpy) is doing something that I
did not anticipate. MGET uses this library to retrieve the extent of
datasets--in this case, of your input TIF files. The library returns a
space-delimited string listing the four coordinates defining the extent.
What I did not expect is that it would ever return numbers containing a
comma for the decimal place instead of a period.
This probably happens because on your operating system, it is traditional to
use commas instead of periods. In the United States, where ArcGIS was
developed, it is traditional to use periods. Neither tradition is better
than the other, of course, but as a programmer, I expected that the ArcGIS
programmers would pick one tradition for their application programming
interface (API) and use it consistently no matter how the operating system
was configured. (Because they were based in the U.S., I expected they would
pick a period.) By allowing the operating system to determine how floating
point numbers are represented in their API (and not documenting this!) they
make applications such as MGET vulnerable to differences in representation,
and require them to handle all such differences...
Anyway, I have patched MGET to handle this situation. The patched file is
attached. To apply it to your system:
1. Close all ArcGIS programs.
2. Save the attached file to C:\Python27\lib\site-packages\GeoEco\ArcGIS.py,
overwriting the file that is there. (Note: do not accidentally overwrite the
file mentioned in the original traceback,
C:\Python27\lib\site-packages\GeoEco\Datasets\ArcGIS.py. That is the wrong
file. MGET contains several files named ArcGIS.py, each in a different
directory. Sorry for any confusion.)
3. Restart ArcGIS again and retry the MGET tool. Please let me know the
outcome.
Best regards,
Jason
-----Original Message-----
From:
[mailto:]
Sent: Tuesday, March 11, 2014 5:45 AM
To:
Subject: [mget-help] Issue with the "Create Lines from Vector Component
Rasters" tool in ArcGIS 10.2
Dear Mister,
I'm having trouble using the "Create Lines from Vector Component Rasters"
tool in ArcGIS 10.2. MGET version I am using is : 0.8a53.
Problem encountered is that my wind raster bounding boxes are encoded with a
comma instead of a point.
It seems to be the origin of the problem, as the dialog box shows:
Executing: ArcGISLinesFromVectorComponentRasters
GLO-BLENDED_WIND_L4-OBS_FULL_TIME_SERIE_1385632487733_eastward_wind_20070321
-000000.tif
GLO-BLENDED_WIND_L4-OBS_FULL_TIME_SERIE_1385632487733_northward_wind_2007032
1-000000.tif
C:\Users\guest906\Desktop\Test_vent\erery.shp 2000 false Start Time: Tue Mar
11 10:40:58 2014 Running script ArcGISLinesFromVectorComponentRasters...
Creating lines in C:\Users\guest906\Desktop\Test_vent\erery.shp from vector
component rasters
GLO-BLENDED_WIND_L4-OBS_FULL_TIME_SERIE_1385632487733_eastward_wind_20070321
-000000.tif
and
GLO-BLENDED_WIND_L4-OBS_FULL_TIME_SERIE_1385632487733_northward_wind_2007032
1-000000.tif.
ValueError: invalid literal for float(): 18,75
Traceback (most recent call last):
File "C:\Program
Files\GeoEco\ArcGISToolbox\Scripts\ArcGISLinesFromVectorComponentRasters.py"
,
line 5, in <module>
ExecuteMethodFromCommandLineAsArcGISTool('GeoEco.SpatialAnalysis.Lines',
'ArcGISLines', 'FromVectorComponentRasters')
File "C:\Python27\lib\site-packages\GeoEco\ArcGISScripts.py", line 210, in
ExecuteMethodFromCommandLineAsArcGISTool
exec sourceCode in globals(), locals()
File "<string>", line 1, in <module>
File "C:\Python27\lib\site-packages\GeoEco\SpatialAnalysis\Lines.py", line
158, in FromVectorComponentRasters
Lines.ShapefileFromVectorComponentGrids(xGrid, yGrid, lines,
scaleFactor, uniformLength, overwriteExisting=overwriteExisting)
File "C:\Python27\lib\site-packages\GeoEco\SpatialAnalysis\Lines.py", line
49, in ShapefileFromVectorComponentGrids
if xGrid.Shape != yGrid.Shape:
File "C:\Python27\lib\site-packages\GeoEco\Datasets\__init__.py", line
2621, in _GetShape
return self.GetLazyPropertyValue('Shape')
File "C:\Python27\lib\site-packages\GeoEco\Datasets\__init__.py", line
160, in GetLazyPropertyValue
value = self._GetLazyPropertyPhysicalValue(name)
File "C:\Python27\lib\site-packages\GeoEco\Datasets\ArcGIS.py", line 1403,
in _GetLazyPropertyPhysicalValue
self.SetLazyPropertyValue('CornerCoords', (float(d.Extent.split()[1]) +
d.MeanCellHeight / 2.0, float(d.Extent.split()[0]) + d.MeanCellWidth / 2.0))
ValueError: invalid literal for float(): 18,75
Failed to execute (ArcGISLinesFromVectorComponentRasters).
Failed at Tue Mar 11 10:40:58 2014 (Elapsed Time: 0,22 seconds)
Do you have any idea of what could be done to solve this problem?
Many thanks,
Caroline Quod
Geomatic Engineer
# ArcGIS.py - Provides utility functions for interacting with the ESRI ArcGIS
# software package.
#
# Copyright (C) 2007 Jason J. Roberts
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License (available in the file LICENSE.TXT)
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
USA.
import datetime
import inspect
import logging
import new
import os
import platform
import re
import sys
import types
import weakref
from GeoEco.Dependencies import Dependency, PythonModuleDependency,
SoftwareNotInstalledError
from GeoEco.DynamicDocString import DynamicDocString
from GeoEco.Exceptions import GeoEcoError
from GeoEco.Logging import Logger
from GeoEco.Internationalization import _, UnicodeToUserPreferredEncoding,
UserPreferredEncodingToUnicode
from GeoEco.Metadata import ClassMetadata, MethodMetadata, TypeMetadata
from GeoEco.Types import DateTimeTypeMetadata
# Private variables global to this module. Initially, I wanted to declare
these
# as class attributes of the GeoprocessorManager class. But when I did that,
# their reference counts were never decreased to 0 by Python when the module
was
# unloaded. This prevented the ArcGIS geoprocessor COM Automation object from
# being released properly, which caused calls to its SetParameterAsText method
# to not work as intended. After very careful experimentation, I determined
that
# the variables could be declared as module globals or as attributes of an
"old-
# style" class and be released properly. I elected to declare them as module
# globals. I could not change the GeoprocessorManager to an old-style class
# because I wanted it to have properties, which are only available on "new-
# style" classes.
_Geoprocessor = None
_WrappedGeoprocessor = None
# Public classes and functions exported by this module
class GeoprocessorManager(object):
__doc__ = DynamicDocString()
_ArcGISMajorVersion = None
_ArcGISMinorVersion = None
_ArcGISServicePack = None
@classmethod
def GetGeoprocessor(cls):
# Try to return a weak reference to the geoprocessor, so that the
caller
# cannot accidentally hold on to a strong reference and thereby
prevent
# the geoprocessor from being released properly when the module
unloads.
#
# First try to return a weak reference, so that the caller cannot
# accidentally hold on to a strong reference and thereby prevent the
# geoprocessor from being released properly when the module unloads.
# If the geoprocessor is the object returned by
arcgisscripting.create()
# then a weak reference cannot be created to it because it does not
have
# a __weakref__ member. In this case we just return the object itself.
if globals()['_Geoprocessor'] is not None:
try:
return weakref.proxy(globals()['_Geoprocessor'])
except:
pass
return globals()['_Geoprocessor']
return None
@classmethod
def SetGeoprocessor(cls, geoprocessor):
cls.__doc__.Obj.ValidatePropertyAssignment()
# If the caller provided a geoprocessor, use it.
if geoprocessor is not None:
try:
globals()['_Geoprocessor'] = geoprocessor
globals()['_WrappedGeoprocessor'] =
_ArcGISObjectWrapper(geoprocessor, u'Geoprocessor')
except:
globals()['_WrappedGeoprocessor'] = None
globals()['_Geoprocessor'] = None
raise
Logger.Debug(_(u'GeoEco will now use ArcGIS Geoprocessor object
0x%08X for ArcGIS operations.'), id(globals()['_Geoprocessor']))
# If they provided None, release our geoprocessor.
elif globals()['_Geoprocessor'] is not None:
Logger.Debug(_(u'GeoEco is releasing its reference to ArcGIS
Geoprocessor object 0x%08X and will no longer use it for ArcGIS
operations.'), id(globals()['_Geoprocessor']))
globals()['_WrappedGeoprocessor'] = None
globals()['_Geoprocessor'] = None
Geoprocessor = property(GetGeoprocessor, SetGeoprocessor,
doc=DynamicDocString())
@classmethod
def GetWrappedGeoprocessor(cls):
# For safety, return a weak reference to the geoprocessor wrapper, so
# that the caller cannot accidentally hold on to a strong reference
and
# thereby prevent the wrapper (and enclosed geoprocessor) from being
# released properly when the module unloads.
if globals()['_WrappedGeoprocessor'] is not None:
return weakref.proxy(globals()['_WrappedGeoprocessor'])
return None
WrappedGeoprocessor = property(GetWrappedGeoprocessor,
doc=DynamicDocString())
@classmethod
def GetGeoprocessorIsCOMObject(cls):
if not sys.modules.has_key('win32com.client'):
return False
if isinstance(cls.GetGeoprocessor(),
sys.modules['win32com.client'].CDispatch):
return True
return False
GeoprocessorIsCOMObject = property(GetGeoprocessorIsCOMObject,
doc=DynamicDocString())
@classmethod
def GetArcGISMajorVersion(cls):
if GeoprocessorManager._ArcGISMajorVersion is None:
cls._GetArcGISVersionNumbers()
return GeoprocessorManager._ArcGISMajorVersion
ArcGISMajorVersion = property(GetArcGISMajorVersion,
doc=DynamicDocString())
@classmethod
def GetArcGISMinorVersion(cls):
if GeoprocessorManager._ArcGISMajorVersion is None:
cls._GetArcGISVersionNumbers()
return GeoprocessorManager._ArcGISMinorVersion
ArcGISMinorVersion = property(GetArcGISMinorVersion,
doc=DynamicDocString())
@classmethod
def GetArcGISServicePack(cls):
if GeoprocessorManager._ArcGISMajorVersion is None:
cls._GetArcGISVersionNumbers()
return GeoprocessorManager._ArcGISServicePack
ArcGISServicePack = property(GetArcGISServicePack, doc=DynamicDocString())
@classmethod
def InitializeGeoprocessor(cls, forceCOMInstantiation=False,
forcePythonInstantiation=False):
# Validate input arguments.
if forceCOMInstantiation and forcePythonInstantiation:
Logger.RaiseException(ValueError(_(u'forceCOMInstantiation and
forcePythonInstantiation cannot both be True. Only one may be True.')))
# If this is ArcGIS 9.3.1 SP1 or later (a.k.a. 9.3 SP3),
# ignore forceCOMInstantiation. We only need that option
# for tools that call the SetValue method of geoprocessor
# cursors and pass None to instruct ArcGIS to set the field to
# NULL. Until ArcGIS 9.3.1 SP1, ArcGIS would raise an
# exception if you tried it, but you could work around it by
# instantiating the geoprocessor with COM.
if forceCOMInstantiation:
major = cls.GetArcGISMajorVersion()
minor = cls.GetArcGISMinorVersion()
servicePack = cls.GetArcGISServicePack()
if major > 9 or major == 9 and minor > 3 or major == 9 and minor
== 3 and servicePack >= 3:
forceCOMInstantiation = False
# If the geoprocessor has already been instantiated, return
# immediately, unless the caller required a specific method
# and the other method was used.
if cls.GetGeoprocessor() is not None:
if cls.GetGeoprocessorIsCOMObject() and forcePythonInstantiation:
Logger.RaiseException(ValueError(_(u'The ArcGIS geoprocessor
cannot be instantiated using the Python arcgisscripting module because it was
already instantiated using COM Automation.')))
if not cls.GetGeoprocessorIsCOMObject() and forceCOMInstantiation:
Logger.RaiseException(ValueError(_(u'The ArcGIS geoprocessor
cannot be instantiated using COM Automation because it was already
instantiated using the Python arcgisscripting module.')))
return
# Look up the version of ArcGIS that is installed on this
# machine.
major = cls.GetArcGISMajorVersion()
minor = cls.GetArcGISMinorVersion()
servicePack = cls.GetArcGISServicePack()
if major is None:
Logger.RaiseException(SoftwareNotInstalledError(_(u'The ArcGIS
geoprocessor cannot be instantiated because ArcGIS does not appear to be
installed.')))
# Instantiate the geoprocessor, trying the methods that are
# appropriate for the version of ArcGIS that is installed.
if major == 9 and minor == 1:
if forcePythonInstantiation:
Logger.RaiseException(ValueError(_(u'The ArcGIS geoprocessor
cannot be instantiated using the Python arcgisscripting module because ArcGIS
9.1 is installed and it does not include the arcgisscripting module. Please
upgrade to ArcGIS 9.2 or later and try again.')))
Logger.Debug(_(u'Attempting to instantiate the ArcGIS
geoprocessor using COM Automation because that is the only supported
instantiation method for ArcGIS 9.1...'))
realGeoprocessor, errorMessage = cls._InstantiateCOMGeoprocessor()
if realGeoprocessor is None:
Logger.RaiseException(RuntimeError(_(u'Failed to instantiate
the ArcGIS geoprocessor using COM Automation. Either ArcGIS is not installed,
the license server is not accessible, or there is a problem with your
installation or license. Error details: %s') % errorMessage))
cls.SetGeoprocessor(realGeoprocessor)
elif major == 9 and minor == 2:
cls._InstantiateGeoprocessorForArc92OrLater(major, minor, 2, 4,
forceCOMInstantiation, forcePythonInstantiation)
elif major == 9 and minor >= 3:
cls._InstantiateGeoprocessorForArc92OrLater(major, minor, 2, 5,
forceCOMInstantiation, forcePythonInstantiation)
elif major == 10 and minor == 0:
cls._InstantiateGeoprocessorForArc92OrLater(major, minor, 2, 6,
forceCOMInstantiation, forcePythonInstantiation)
elif major >= 10:
cls._InstantiateGeoprocessorForArc92OrLater(major, minor, 2, 7,
forceCOMInstantiation, forcePythonInstantiation)
else:
Logger.RaiseException(SoftwareNotInstalledError(_(u'The ArcGIS
geoprocessor cannot be instantiated because ArcGIS %i.%i is installed and
this tool is only capable of instantiating the geoprocessor if ArcGIS 9.1 or
later is installed. Please upgrade to ArcGIS 9.1 or later and try again') %
(major, minor)))
# We successfully instantiated the geoprocessor. As described
# in ticket #470, we need to work around an incompatibility
# between ArcGIS and Python.
#
# When Python code sets the PATH environment variable (e.g.
# os.environ['PATH'] = x), it screws up ArcGIS in a subtle
# way. A subsequent call to gp.Describe(<some
# raster>).DataType will return 'File' rather than
# 'RasterDataset'. When I ran ArcCatalog.exe 9.3.1 SP1 under
# the debugger, I noticed a difference in the DLLs that
# gp.Describe loaded, depending whether or not the Python code
# set the PATH. It did not matter what the PATH was set to,
# just that it was set at all (even set to what it currently
# was).
#
# To work around this, call gp.Describe on a raster that comes
# with GeoEco. This will cause the DLLs to be loaded, assuming
# that PATH has not been set from Python already (which is
# unlikely because GeoEco tools always initialize the
# geoprocessor very early).
cls.GetWrappedGeoprocessor().Describe(os.path.join(os.path.dirname(__file__),
'ArcGISToolbox', 'Rasters', 'dummyint'))
# TODO:
#
# Unfortunately, it is not sufficient to just call gp.Describe
# as shown above. That does cause the DLLs that are apparently
# required to be loaded, but only temporarily. If ArcCatalog
# sits idle for a while it unloads the DLLs. To work around
# that, explicitly call win32 LoadLibrary on the DLLs that
# appear to be required. This will leak Windows module handles
# for each one and cause it to remain loaded.
## import win32api
## win32api.LoadLibrary('GDALRasterDB.DLL')
## win32api.LoadLibrary('SDCPlugin.DLL')
## win32api.LoadLibrary('ISORes.DLL')
## win32api.LoadLibrary('cso.DLL')
## win32api.LoadLibrary('ShapefileFDB.DLL')
## win32api.LoadLibrary('CoverageFDB.DLL')
## win32api.LoadLibrary('ScalarReference.DLL')
## win32api.LoadLibrary('GpTinFunctionFactories.DLL')
## win32api.LoadLibrary('ArcGISDomain.DLL')
## win32api.LoadLibrary('GpCoreFunctionFactories.DLL')
## win32api.LoadLibrary('XMLSupport.DLL')
@classmethod
def _InstantiateGeoprocessorForArc92OrLater(cls, arcMajor, arcMinor,
pyMajor, pyMinor, forceCOMInstantiation, forcePythonInstantiation):
if forcePythonInstantiation and not (sys.version_info[0] == pyMajor
and sys.version_info[1] == pyMinor):
Logger.RaiseException(ValueError(_(u'The ArcGIS geoprocessor
cannot be instantiated using the Python arcgisscripting module because this
script is executing under Python %(pyMajor1)i.%(pyMinor1)i and the
arcgisscripting module from ArcGIS %(arcMajor)i.%(arcMinor)i can only be used
with Python %(pyMajor2)i.%(pyMinor2)i.') % {u'pyMajor1': sys.version_info[0],
u'pyMinor1': sys.version_info[1], u'arcMajor': arcMajor, u'arcMinor':
arcMinor, u'pyMajor2': pyMajor, u'pyMinor2': pyMinor}))
errorMessage1 = None
if not forceCOMInstantiation and (sys.version_info[0] == pyMajor and
sys.version_info[1] == pyMinor):
Logger.Debug(_(u'Attempting to instantiate the ArcGIS
geoprocessor using the arcgisscripting module...'))
realGeoprocessor, errorMessage1 =
cls._InstantiatePythonGeoprocessor()
if realGeoprocessor is not None:
cls.SetGeoprocessor(realGeoprocessor)
return
if forcePythonInstantiation:
Logger.RaiseException(RuntimeError(_(u'Failed to instantiate
the ArcGIS geoprocessor using the Python arcgisscripting module. Most likely
ArcGIS is not installed, the license server is not accessible, or there is a
problem with your installation or license. Error details: %s') %
errorMessage1))
else:
Logger.Debug(_(u'Failed to instantiate the ArcGIS
geoprocessor using the Python arcgisscripting module. %s') % errorMessage1)
Logger.Debug(_(u'Attempting to instantiate the ArcGIS geoprocessor
using COM Automation...'))
realGeoprocessor, errorMessage2 = cls._InstantiateCOMGeoprocessor()
if realGeoprocessor is not None:
cls.SetGeoprocessor(realGeoprocessor)
return
Logger.Debug(_(u'Failed to instantiate the ArcGIS geoprocessor using
COM automation. %s') % errorMessage2)
if errorMessage1 is not None:
Logger.RaiseException(RuntimeError(_(u'Failed to instantiate the
ArcGIS geoprocessor using the Python arcgisscripting module and using COM
Automation. Most likely ArcGIS is not installed, the license server is not
accessible, or there is a problem with your installation or license. If you
believe that none of those are the problem, please contact the author of this
tool for assistance. If you believe that none of those are the problem,
please contact the author of this tool for assistance. Error details: %s %s')
% (errorMessage1, errorMessage2)))
else:
if sys.version_info[0] == pyMajor and sys.version_info[1] ==
pyMinor:
Logger.Debug(_(u'Attempting to instantiate the ArcGIS
geoprocessor using the arcgisscripting module, simply for the purpose of
reporting an error message...'))
realGeoprocessor, errorMessage1 =
cls._InstantiatePythonGeoprocessor()
if realGeoprocessor is not None:
cls.SetGeoprocessor(realGeoprocessor)
Logger.RaiseException(RuntimeError(_(u'Failed to instantiate the
ArcGIS geoprocessor using COM Automation. (Due ArcGIS bug NIM010734, this
tool is required to instantiate the geoprocessor with COM Automation rather
than the arcgisscripting Python module.) %s') % errorMessage2))
@classmethod
def _InstantiateCOMGeoprocessor(cls):
try:
import pythoncom
except Exception, e:
if isinstance(e, AttributeError) and str(e).find("'NoneType'
object has no attribute 'platform'") >= 0:
return None, _(u'The pythoncom module from the "Python for
Windows Extensions" package (also known as "pywin32") could not be imported
due to an incompatibility between recent releases of pywin32 and ArcGIS. You
may be able to work around this problem temporarily by restarting ArcGIS and
running this tool again (do not run any other tools before running this one).
For a more permanent solution, uninstall your existing copy of pywin32 and
install build 212 instead. Finally, please see
http://code.env.duke.edu/projects/mget/ticket/386 for the current status of
this problem.')
return None, _(u'The "Python for Windows extensions" Python
package (also known as "pywin32") does not appear to be properly installed
for this version of Python (%(major)s.%(minor)s) because the Python statement
"import pythoncom" raised %(e)s: %(msg)s.') % {u'major': sys.version_info[0],
u'minor': sys.version_info[1], u'e': e.__class__.__name__, u'msg': unicode(e)}
Logger.Debug(_(u'Imported the pythoncom Python module.'))
try:
import win32com.client
except Exception, e:
return None, _(u'The "Python for Windows extensions" Python
package (also known as "pywin32") does not appear to be properly installed
for this version of Python (%(major)s.%(minor)s) because the Python statement
"import win32com.client" raised %(e)s: %(msg)s.') % {u'major':
sys.version_info[0], u'minor': sys.version_info[1], u'e':
e.__class__.__name__, u'msg': unicode(e)}
Logger.Debug(_(u'Imported the win32com.client Python module.'))
progID = 'esriGeoprocessing.GPDispatch'
try:
realGeoprocessor = win32com.client.Dispatch(progID)
except pythoncom.com_error, (hr, msg, exc, arg):
from GeoEco.COM import FormatCOMError
return None, _(u'ArcGIS may not be installed, the license server
may not be accessible, or there may be problem with the installation or
license. If you believe that none of those are the problem, please contact
the author of this tool for assistance. Error details: The "%(progid)s" COM
Automation object could not be instantiated because the Python statement
"win32com.client.Dispatch(\'%(progid)s\')" raised %(msg)s.') % {u'progid':
progID, u'msg': FormatCOMError(hr, msg, exc, arg)}
except Exception, e:
return None, _(u'ArcGIS may not be installed, the license server
may not be accessible, or there may be problem with the installation or
license. If you believe that none of those are the problem, please contact
the author of this tool for assistance. The "%(progid)s" COM Automation
object could not be instantiated because the Python statement
"win32com.client.Dispatch(\'%(progid)s\')" raised %(e)s: %(msg)s.') %
{u'progid': progID, u'e': e.__class__.__name__, u'msg': unicode(e)}
Logger.Debug(_(u'Instantiated ArcGIS geoprocessor object 0x%08X using
COM Automation.'), id(realGeoprocessor))
return realGeoprocessor, None
@classmethod
def _InstantiatePythonGeoprocessor(cls):
try:
import arcgisscripting
except Exception, e:
return None, _(u'The Python statement "import arcgisscripting"
raised %(e)s: %(msg)s.') % {u'e': e.__class__.__name__, u'msg': unicode(e)}
Logger.Debug(_(u'Imported the arcgisscripting Python module.'))
try:
realGeoprocessor = arcgisscripting.create() # NOTE: DO NOT
change this to arcgisscripting.create(9.3)!
except Exception, e:
return None, _(u'The Python statement "arcgisscripting.create()"
raised %(e)s: %(msg)s.') % {u'e': e.__class__.__name__, u'msg': unicode(e)}
Logger.Debug(_(u'Instantiated ArcGIS geoprocessor object 0x%08X using
arcgisscripting.create().'), id(realGeoprocessor))
return realGeoprocessor, None
@classmethod
def _GetArcGISVersionNumbers(cls):
# If we're running on Windows, get the ArcGIS version number from
# the Windows registry.
if sys.platform.lower() == u'win32':
Logger.Debug(_(u'Retrieving the ArcGIS version numbers from the
Windows Registry.'))
# First import the win32api and win32con modules.
d = PythonModuleDependency(importName='win32api',
displayName=_(u'Python for Windows extensions (pywin32)'),
alternateURL=u'http://sourceforge.net/projects/pywin32')
d.Initialize();
import win32api
d = PythonModuleDependency(importName='win32con',
displayName=_(u'Python for Windows extensions (pywin32)'),
alternateURL=u'http://sourceforge.net/projects/pywin32')
d.Initialize();
import win32con
# Read the registry values that contain the version numbers.
try:
hkey = None
try:
try:
subkey = 'Desktop10.2'
hkey =
win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\ESRI\\' + subkey)
(realVersionValue, realVersionType) =
win32api.RegQueryValueEx(hkey, 'RealVersion')
except:
try:
subkey = 'Desktop10.1'
hkey =
win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\ESRI\\' + subkey)
(realVersionValue, realVersionType) =
win32api.RegQueryValueEx(hkey, 'RealVersion')
except:
try:
subkey = 'Desktop10.0'
hkey =
win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\ESRI\\' + subkey)
(realVersionValue, realVersionType) =
win32api.RegQueryValueEx(hkey, 'RealVersion')
except:
subkey = 'ArcInfo\\Desktop\\8.0'
hkey =
win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\ESRI\\' + subkey)
(realVersionValue, realVersionType) =
win32api.RegQueryValueEx(hkey, 'RealVersion')
if not isinstance(realVersionValue, basestring) or not
re.match('^[0-9]+\.[0-9]+(\.[0-9])?$', realVersionValue.strip()):
raise ValueError(_(u'The RealVersion value of the
HKEY_LOCAL_MACHINE\\SOFTWARE\\ESRI\\ArcInfo\\Desktop\\8.0 registry key is not
a REG_SZ, or it is not formatted properly.'))
GeoprocessorManager._ArcGISMajorVersion =
int(realVersionValue.strip().split('.')[0])
GeoprocessorManager._ArcGISMinorVersion =
int(realVersionValue.strip().split('.')[1])
spNumberValue = None
try:
(spNumberValue, spNumberType) =
win32api.RegQueryValueEx(hkey, 'SPNumber')
except:
pass
if spNumberValue is not None:
if not isinstance(spNumberValue, basestring) or
len(spNumberValue.strip()) > 0 and not re.match('^[0-9]+$',
spNumberValue.strip()):
raise ValueError(_(u'The SPNumber value of the
HKEY_LOCAL_MACHINE\\SOFTWARE\\ESRI\\%s registry key is not a REG_SZ, or it is
not formatted properly.') % subkey)
if len(spNumberValue.strip()) > 0:
GeoprocessorManager._ArcGISServicePack =
int(spNumberValue.strip())
else:
GeoprocessorManager._ArcGISServicePack = 0
finally:
try:
if hkey is not None:
win32api.RegCloseKey(hkey)
except:
pass
except Exception, e:
GeoprocessorManager._ArcGISMajorVersion = None
GeoprocessorManager._ArcGISMinorVersion = None
GeoprocessorManager._ArcGISServicePack = None
Logger.Debug(_(u'Failed to retrieve the ArcGIS version
numbers from the Windows Registry. ArcGIS must not be installed. Python
reported %s: %s'), e.__class__.__name__, unicode(e))
# If we're on a non-Windows platform, all we can try to do is
# import the arcgisscripting module. If it contains a class
# called ExecuteError, it is ArcGIS 9.3. If not, it is ArcGIS
# 9.2. Note that this code is experimental; we have not yet
# tried to port GeoEco to non-Windows platforms. Also this
# code does not know how to determine the service pack that is
# installed, if any.
else:
raise NotImplementedError(_(u'At this time, GeoEco is only
supported on 32-bit Microsoft Windows.'))
Logger.Debug(_(u'Importing the arcgisscripting Python module to
determine if ArcGIS is installed on this non-Windows operating system...'))
try:
import arcgisscripting
if 'ExecuteError' in arcgisscripting.__dict__:
GeoprocessorManager._ArcGISMajorVersion = 9
GeoprocessorManager._ArcGISMinorVersion = 3
GeoprocessorManager._ArcGISServicePack = 0
Logger.Debug(_(u'Imported the arcgisscripting Python
module and found the ExecuteError class within it. ArcGIS 9.3 or later is
installed. We do not presently know how to determine if a service pack is
installed, so we will assume that no service pack is installed.'))
else:
GeoprocessorManager._ArcGISMajorVersion = 9
GeoprocessorManager._ArcGISMinorVersion = 2
GeoprocessorManager._ArcGISServicePack = 0
Logger.Debug(_(u'Imported the arcgisscripting Python
module but did not find the ExecuteError class within it. ArcGIS 9.2 is
installed. We do not presently know how to determine if a service pack is
installed, so we will assume that no service pack is installed.'))
except Exception, e:
GeoprocessorManager._ArcGISMajorVersion = None
GeoprocessorManager._ArcGISMinorVersion = None
GeoprocessorManager._ArcGISServicePack = None
Logger.Debug(_(u'The arcgisscripting Python module could not
be imported (Python raised %s: %s). ArcGIS is not installed.'),
e.__class__.__name__, unicode(e))
@classmethod
def RefreshCatalog(cls, directory):
cls.__doc__.Obj.ValidateMethodInvocation()
gp = cls.GetWrappedGeoprocessor()
if gp is not None:
gp.RefreshCatalog(directory)
Logger.Debug(_(u'Refreshed the ArcGIS catalog for directory %s'),
directory)
@classmethod
def ArcGISObjectExists(cls, path, correctTypes, typeDisplayName):
cls.__doc__.Obj.ValidateMethodInvocation()
gp = cls.GetWrappedGeoprocessor()
if gp is None:
Logger.RaiseException(RuntimeError(_(u'The ArcGIS geoprocessor
must be initialized before this tool may be executed. Please call
GeoprocessorManager.InitializeGeoprocessor or
GeoprocessorManager.SetGeoprocessor before executing this tool.')))
exists = gp.Exists(path)
if not exists and u'shapefile' in correctTypes and not
path.lower().endswith('.shp') and os.path.isdir(os.path.dirname(path)):
exists = gp.Exists(path + u'.shp')
if exists:
path = path + u'.shp'
isCorrectType = False
if exists:
correctTypes = map(unicode.lower, correctTypes)
d = gp.Describe(path)
isCorrectType = d is not None and d.DataType.lower() in
correctTypes
isCorrectType = isCorrectType or (u'rasterdataset' in
correctTypes and os.path.isfile(path) and path.lower().endswith('.img'))
# Seemingly randomly, gp.Describe does not work correctly with .img files.
if not exists:
Logger.Debug(_(u'The %(type)s %(path)s does not exist.') %
{u'type': typeDisplayName, u'path': path})
else:
if isCorrectType:
Logger.Debug(_(u'The %(type)s %(path)s exists.') % {u'type':
typeDisplayName, u'path': path})
else:
Logger.Debug(_(u'%(path)s exists but it is a %(actual)s, not
a %(type)s.') % {u'type': typeDisplayName, u'path': path, u'actual':
d.DataType})
return (exists, isCorrectType)
@classmethod
def DeleteArcGISObject(cls, path, correctTypes, typeDisplayName):
cls.__doc__.Obj.ValidateMethodInvocation()
exists, isCorrectType = cls.ArcGISObjectExists(path, correctTypes,
typeDisplayName)
if not exists:
Logger.Info(_('The %(type)s %(path)s will not be deleted because
it does not exist.') % {u'type': typeDisplayName, u'path': path})
return
if not isCorrectType:
Logger.RaiseException(ValueError(_('%(path)s exists but cannot be
deleted because it is not a %(type)s.') % {u'type': typeDisplayName, u'path':
path}))
try:
gp = cls.GetWrappedGeoprocessor()
gp.Delete_Management(path)
except:
Logger.LogExceptionAsError(_(u'Could not delete %(type)s
%(path)s.') % {u'type': typeDisplayName, u'path': path})
raise
Logger.Info(_('Deleted %(type)s %(path)s.') % {u'type':
typeDisplayName, u'path': path})
@classmethod
def CopyArcGISObject(cls, source, destination, overwriteExisting,
correctTypes, typeDisplayName):
cls.__doc__.Obj.ValidateMethodInvocation()
exists, isCorrectType = cls.ArcGISObjectExists(source, correctTypes,
typeDisplayName)
if not exists:
Logger.RaiseException(ValueError(_('The %(type)s %(path)s cannot
be copied because it does not exist.') % {u'type': typeDisplayName, u'path':
source}))
if not isCorrectType:
Logger.RaiseException(ValueError(_('%(path)s cannot be copied
because it is not a %(type)s.') % {u'type': typeDisplayName, u'path':
source}))
try:
if overwriteExisting:
oldLogInfoAsDebug = Logger.GetLogInfoAsDebug()
Logger.SetLogInfoAsDebug(True)
try:
cls.DeleteArcGISObject(destination, correctTypes,
typeDisplayName)
finally:
Logger.SetLogInfoAsDebug(oldLogInfoAsDebug)
else:
exists, isCorrectType = cls.ArcGISObjectExists(destination,
correctTypes, typeDisplayName)
if exists:
Logger.RaiseException(ValueError(_('%(path)s already
exists.') % {u'path': destination}))
gp = cls.GetWrappedGeoprocessor()
Logger.Info(_('Copying %(type)s %(source)s to %(destination)s.')
% {u'type': typeDisplayName, u'source': source, u'destination': destination})
if u'featureclass' in correctTypes or u'shapefile' in
correctTypes or u'featurelayer' in correctTypes:
gp.CopyFeatures_management(source, destination)
else:
gp.Copy_Management(source, destination)
except:
Logger.LogExceptionAsError(_(u'Could not copy %(type)s %(source)s
to %(destination)s.') % {u'type': typeDisplayName, u'source': source,
u'destination': destination})
raise
@classmethod
def MoveArcGISObject(cls, source, destination, overwriteExisting,
correctTypes, typeDisplayName):
cls.__doc__.Obj.ValidateMethodInvocation()
exists, isCorrectType = cls.ArcGISObjectExists(source, correctTypes,
typeDisplayName)
if not exists:
Logger.RaiseException(ValueError(_('The %(type)s %(path)s cannot
be moved because it does not exist.') % {u'type': typeDisplayName, u'path':
source}))
if not isCorrectType:
Logger.RaiseException(ValueError(_('%(path)s cannot be moved
because it is not a %(type)s.') % {u'type': typeDisplayName, u'path':
source}))
try:
if overwriteExisting:
oldLogInfoAsDebug = Logger.GetLogInfoAsDebug()
Logger.SetLogInfoAsDebug(True)
try:
cls.DeleteArcGISObject(destination, correctTypes,
typeDisplayName)
finally:
Logger.SetLogInfoAsDebug(oldLogInfoAsDebug)
else:
exists, isCorrectType = cls.ArcGISObjectExists(destination,
correctTypes, typeDisplayName)
if exists:
Logger.RaiseException(ValueError(_('%(path)s already
exists.') % {u'path': destination}))
gp = cls.GetWrappedGeoprocessor()
Logger.Info(_('Moving %(type)s %(source)s to %(destination)s.') %
{u'type': typeDisplayName, u'source': source, u'destination': destination})
if u'featureclass' in correctTypes or u'shapefile' in
correctTypes or u'featurelayer' in correctTypes:
gp.CopyFeatures_management(source, destination)
else:
gp.Copy_Management(source, destination)
gp.Delete_Management(source)
except:
Logger.LogExceptionAsError(_(u'Could not move %(type)s %(source)s
to %(destination)s.') % {u'type': typeDisplayName, u'source': source,
u'destination': destination})
raise
@classmethod
def GetUniqueLayerName(cls):
gp = cls.GetWrappedGeoprocessor()
if gp is None:
Logger.RaiseException(RuntimeError(_(u'The ArcGIS geoprocessor
must be initialized before this tool may be executed. Please call
GeoprocessorManager.InitializeGeoprocessor or
GeoprocessorManager.SetGeoprocessor before executing this tool.')))
import random
name = u'TempLayer%08X' % random.randint(0, 2147483647)
while gp.Exists(name):
name = u'TempLayer%08X' % random.randint(0, 2147483647)
return name
class ArcGISDependency(Dependency):
__doc__ = DynamicDocString()
def __init__(self, minimumMajorVersion, minimumMinorVersion=None,
minimumServicePack=None, requiresCOMInstantiation=False,
requiresPythonInstantiation=False):
self.SetVersion(minimumMajorVersion, minimumMinorVersion,
minimumServicePack)
assert not (requiresCOMInstantiation and
requiresPythonInstantiation), u'requiresCOMInstantiation and
requiresPythonInstantiation cannot both be True'
self.RequiresCOMInstantiation = requiresCOMInstantiation
self.RequiresPythonInstantiation = requiresPythonInstantiation
def SetVersion(self, minimumMajorVersion, minimumMinorVersion=None,
minimumServicePack=None):
assert isinstance(minimumMajorVersion, types.IntType),
u'minimumMajorVersion must be an integer.'
assert isinstance(minimumMinorVersion, (types.IntType,
types.NoneType)), 'minimumMinorVersion must be an integer, or None.'
assert isinstance(minimumServicePack, (types.IntType,
types.NoneType)), u'minimumServicePack must be an integer, or None.'
assert minimumMajorVersion is not None and minimumMinorVersion is
None and minimumServicePack is None or minimumMajorVersion is not None and
minimumMinorVersion is not None and minimumServicePack is None or
minimumMajorVersion is not None and minimumMinorVersion is not None and
minimumServicePack is not None, u'If you specify a minimumMinorVersion you
must also specify a minimumMajorVersion. If you specify a minimumServicePack
you must also specify a minimumMajorVersion and minimumMinorVersion.'
assert minimumMinorVersion is None or minimumMinorVersion >= 0, u'If
minimumMinorVersion is not None it must be >= 0.'
assert minimumServicePack is None or minimumServicePack >= 0, u'If
minimumServicePack is not None it must be >= 0.'
assert minimumMajorVersion > 9 or minimumMajorVersion == 9 and
minimumMinorVersion is not None and minimumMinorVersion >= 1, u'GeoEco can
only run on ArcGIS 9.1 or later. Even if your code can run on prior versions,
GeoEco\'s ArcGIS utility functions cannot. Please adjust your
ArcGISDependency to 9.1 or later.'
if minimumMinorVersion is None:
minimumMinorVersion = 0
if minimumServicePack is None:
minimumServicePack = 0
self._MinimumMajorVersion = minimumMajorVersion
self._MinimumMinorVersion = minimumMinorVersion
self._MinimumServicePack = minimumServicePack
def _GetMinimumMajorVersion(self):
return self._MinimumMajorVersion
MinimumMajorVersion = property(_GetMinimumMajorVersion,
doc=DynamicDocString())
def _GetMinimumMinorVersion(self):
return self._MinimumMinorVersion
MinimumMinorVersion = property(_GetMinimumMinorVersion,
doc=DynamicDocString())
def _GetMinimumServicePack(self):
return self._MinimumServicePack
MinimumServicePack = property(_GetMinimumServicePack,
doc=DynamicDocString())
def _GetMinimumServicePackString(self):
if self._MinimumServicePack > 0:
return _(u' Service Pack %i') % self._MinimumServicePack
else:
return u''
MinimumServicePackString = property(_GetMinimumServicePackString,
doc=DynamicDocString())
def _SetRequiresCOMInstantiation(self, value):
assert isinstance(value, types.BooleanType),
u'RequiresCOMInstantiation must be a boolean'
self._RequiresCOMInstantiation = value
def _GetRequiresCOMInstantiation(self):
return self._RequiresCOMInstantiation
RequiresCOMInstantiation = property(_GetRequiresCOMInstantiation,
_SetRequiresCOMInstantiation, doc=DynamicDocString())
def _SetRequiresPythonInstantiation(self, value):
assert isinstance(value, types.BooleanType),
u'RequiresPythonInstantiation must be a boolean'
self._RequiresPythonInstantiation = value
def _GetRequiresPythonInstantiation(self):
return self._RequiresPythonInstantiation
RequiresPythonInstantiation = property(_GetRequiresPythonInstantiation,
_SetRequiresPythonInstantiation, doc=DynamicDocString())
_LoggedInstalledVersion = False
def GetResultCacheKey(self):
if self.RequiresCOMInstantiation:
return u'ArcGISDependency:' + unicode(self._MinimumMajorVersion)
+ u',' + unicode(self._MinimumMinorVersion) + u',' +
unicode(self._MinimumServicePack) + u' using COM Automation'
if self.RequiresPythonInstantiation:
return u'ArcGISDependency:' + unicode(self._MinimumMajorVersion)
+ u',' + unicode(self._MinimumMinorVersion) + u',' +
unicode(self._MinimumServicePack) + u' using arcgisscripting'
return u'ArcGISDependency:' + unicode(self._MinimumMajorVersion) +
u',' + unicode(self._MinimumMinorVersion) + u',' +
unicode(self._MinimumServicePack)
def Initialize(self):
# If this is ArcGIS 9.3.1 SP1 or later (a.k.a. 9.3 SP3),
# ignore RequiresCOMInstantiation. We only need that option
# for tools that call the SetValue method of geoprocessor
# cursors and pass None to instruct ArcGIS to set the field to
# NULL. Until ArcGIS 9.3.1 SP1, ArcGIS would raise an
# exception if you tried it, but you could work around it by
# instantiating the geoprocessor with COM.
major = GeoprocessorManager.GetArcGISMajorVersion()
minor = GeoprocessorManager.GetArcGISMinorVersion()
sp = GeoprocessorManager.GetArcGISServicePack()
requiresCOMInstantiation = self.RequiresCOMInstantiation
if major > 9 or major == 9 and minor > 3 or major == 9 and minor == 3
and sp >= 3:
requiresCOMInstantiation = False
if requiresCOMInstantiation:
Logger.Debug(_(u'Checking software dependency: ArcGIS version
%i.%i%s or later, with the geoprocessor instantiated using Microsoft COM
Automation') % (self.MinimumMajorVersion, self.MinimumMinorVersion,
self.MinimumServicePackString))
elif self.RequiresPythonInstantiation:
Logger.Debug(_(u'Checking software dependency: ArcGIS version
%i.%i%s or later, with the geoprocessor instantiated using the Python
arcgisscripting module') % (self.MinimumMajorVersion,
self.MinimumMinorVersion, self.MinimumServicePackString))
else:
Logger.Debug(_(u'Checking software dependency: ArcGIS version
%i.%i%s or later') % (self.MinimumMajorVersion, self.MinimumMinorVersion,
self.MinimumServicePackString))
# Check the ArcGIS version numbers.
if major is None or minor is None or sp is None:
Logger.RaiseException(SoftwareNotInstalledError(_(u'This tool
requires ArcGIS %i.%i%s or a later version, but ArcGIS is not installed.
Please install a compatible version of ArcGIS and try again.') %
(self.MinimumMajorVersion, self.MinimumMinorVersion,
self.MinimumServicePackString)))
if not ArcGISDependency._LoggedInstalledVersion:
if sp > 0:
servicePackString = _(u' Service Pack %i') %
GeoprocessorManager.GetArcGISServicePack()
else:
servicePackString = u''
Logger.Debug(_(u'ArcGIS %i.%i%s is installed.'), major, minor,
servicePackString)
ArcGISDependency._LoggedInstalledVersion = True
if self.MinimumMajorVersion > major or self.MinimumMajorVersion ==
major and self.MinimumMinorVersion > minor or self.MinimumMajorVersion ==
major and self.MinimumMinorVersion == minor and self.MinimumServicePack > sp:
if sp > 0:
servicePackString = _(u' Service Pack %i') %
GeoprocessorManager.GetArcGISServicePack()
else:
servicePackString = u''
Logger.RaiseException(SoftwareNotInstalledError(_(u'This tool
requires ArcGIS %i.%i%s or a later version, but version %s.%s%s is installed.
Please upgrade your ArcGIS installation to a compatible version and try
again.') % (self.MinimumMajorVersion, self.MinimumMinorVersion,
self.MinimumServicePackString, major, minor, servicePackString)))
# If the geoprocessor has already been instantiated and this
# tool requires that it be instantiated with a specific
# method, report an error if it has already been instantiated
# with the other method. Otherwise just return.
if GeoprocessorManager.GetWrappedGeoprocessor() is not None:
if requiresCOMInstantiation and not
GeoprocessorManager.GetGeoprocessorIsCOMObject():
Logger.RaiseException(RuntimeError(_(u'This tool requires
that the ArcGIS geoprocessor be instantiated using Microsoft COM Automation
(via the win32com.client.Dispatch function) but the geoprocessor was already
instantiated using the Python arcgisscripting module. Please contact the
author of this tool for assistance.')))
if self.RequiresPythonInstantiation and
GeoprocessorManager.GetGeoprocessorIsCOMObject():
if major == 9 and minor == 2 and not (sys.version_info[0] ==
2 and sys.version_info[1] == 4):
Logger.RaiseException(RuntimeError(_(u'This tool requires
that the ArcGIS geoprocessor be instantiated using the Python arcgisscripting
module but the geoprocessor was already instantiated using Microsoft COM
Automation (via the win32com.client.Dispatch function) because the ArcGIS 9.2
arcgisscripting module can only be used with Python 2.4. Please try to run
this tool again using Python 2.4.')))
if major == 9 and minor == 3 and not (sys.version_info[0] ==
2 and sys.version_info[1] == 5):
Logger.RaiseException(RuntimeError(_(u'This tool requires
that the ArcGIS geoprocessor be instantiated using the Python arcgisscripting
module but the geoprocessor was already instantiated using Microsoft COM
Automation (via the win32com.client.Dispatch function) because the ArcGIS 9.3
arcgisscripting module can only be used with Python 2.5. Please try to run
this tool again using Python 2.5.')))
if major == 10 and not (sys.version_info[0] == 2 and
sys.version_info[1] == 6):
Logger.RaiseException(RuntimeError(_(u'This tool requires
that the ArcGIS geoprocessor be instantiated using the Python arcgisscripting
module but the geoprocessor was already instantiated using Microsoft COM
Automation (via the win32com.client.Dispatch function) because the ArcGIS 10
arcgisscripting module can only be used with Python 2.6. Please try to run
this tool again using Python 2.6.')))
Logger.RaiseException(RuntimeError(_(u'This tool requires
that the ArcGIS geoprocessor be instantiated using the Python arcgisscripting
module but the geoprocessor was already instantiated using Microsoft COM
Automation (via the win32com.client.Dispatch function). Please contact the
author of this tool for assistance.')))
return
# Initialize the geoprocessor object.
GeoprocessorManager.InitializeGeoprocessor(forceCOMInstantiation=requiresCOMInstantiation,
forcePythonInstantiation=self.RequiresPythonInstantiation)
def GetConstraintDescriptionStrings(self):
if self.MinimumMajorVersion == 9 and self.MinimumMinorVersion == 3
and self.MinimumServicePack >= 2:
if self.MinimumServicePack == 2:
return [u'ArcGIS 9.3.1 or later']
return [u'ArcGIS 9.3.1 Service Pack %i or later' %
(self.MinimumServicePack - 2,)]
if self.MinimumServicePack > 0:
return [u'ArcGIS %i.%i Service Pack %i or later' %
(self.MinimumMajorVersion, self.MinimumMinorVersion, self.MinimumServicePack)]
return [u'ArcGIS %i.%i or later' % (self.MinimumMajorVersion,
self.MinimumMinorVersion)]
class ArcGISProductDependency(Dependency):
__doc__ = DynamicDocString()
def __init__(self, minimumProductLevel):
self.MinimumProductLevel = minimumProductLevel
def _SetMinimumProductLevel(self, value):
assert isinstance(value, types.UnicodeType), u'MinimumProductLevel
must be a Unicode string'
self._MinimumProductLevel = value
def _GetMinimumProductLevel(self):
return self._MinimumProductLevel
MinimumProductLevel = property(_GetMinimumProductLevel,
_SetMinimumProductLevel, doc=DynamicDocString())
_ProductStatus = {}
def GetResultCacheKey(self):
return u'ArcGISProductDependency:' + self._MinimumProductLevel
def Initialize(self):
Logger.Debug(_(u'Checking software dependency: ArcGIS product level
\"%s\".') % self.MinimumProductLevel)
# Obtain the geoprocessor. If we can't get it, it means the method
that
# declared this dependency did not first declare an ArcGISDependency.
gp = GeoprocessorManager.GetWrappedGeoprocessor()
assert gp is not None, u'An ArcGISDependency must be declared before
an ArcGISProductDependency is declared. Please add an ArcGISDependency to the
method metadata for this method.'
# If our product status dictionary does not have an entry for this
# product level, query ArcGIS for its availability.
if not
ArcGISProductDependency._ProductStatus.has_key(self.MinimumProductLevel):
ArcGISProductDependency._ProductStatus[self.MinimumProductLevel]
= gp.CheckProduct(self.MinimumProductLevel)
# Check the product status.
if
ArcGISProductDependency._ProductStatus.has_key(self.MinimumProductLevel):
if
ArcGISProductDependency._ProductStatus[self.MinimumProductLevel].lower() !=
u'available' and
ArcGISProductDependency._ProductStatus[self.MinimumProductLevel].lower() !=
u'alreadyinitialized':
Logger.RaiseException(SoftwareNotInstalledError(_(u'This tool
requires ArcGIS product license level \"%(level)s\" or higher. The ArcGIS
geoprocessor reported the following status for that license level:
\"%(status)s\". Please verify that you possess an ArcGIS product license of a
sufficient level. If you use an ArcGIS license server, verify that this
computer can properly communicate with it.') % {u'level':
self.MinimumProductLevel, u'status' :
ArcGISProductDependency._ProductStatus[self.MinimumProductLevel]}))
else:
Logger.RaiseException(SoftwareNotInstalledError(_(u'This tool
requires ArcGIS product license level \"%(level)s\" or higher. The ArcGIS
geoprocessor failed to report the status of that license level. Please verify
that you possess an ArcGIS product license of a sufficient level. If you use
an ArcGIS license server, verify that this computer can properly communicate
with it.') % {u'level': self.MinimumProductLevel}))
def GetConstraintDescriptionStrings(self):
return [u'ArcGIS product level of "%s" or higher' %
self.MinimumProductLevel]
class ArcGISExtensionDependency(Dependency):
__doc__ = DynamicDocString()
def __init__(self, extensionCode):
self.ExtensionCode = extensionCode
def _SetExtensionCode(self, value):
assert isinstance(value, types.UnicodeType), u'ExtensionCode must be
a Unicode string'
self._ExtensionCode = value
def _GetExtensionCode(self):
return self._ExtensionCode
ExtensionCode = property(_GetExtensionCode, _SetExtensionCode,
doc=DynamicDocString())
def GetResultCacheKey(self):
return u'ArcGISExtensionDependency:' + self._ExtensionCode
def Initialize(self):
Logger.Debug(_(u'Checking software dependency: ArcGIS \"%s\"
extension.') % self.ExtensionCode)
# Obtain the geoprocessor. If we can't get it, it means the method
that
# declared this dependency did not first declare an ArcGISDependency.
gp = GeoprocessorManager.GetWrappedGeoprocessor()
assert gp is not None, u'An ArcGISDependency must be declared before
an ArcGISExtensionDependency is declared. Please add an ArcGISDependency to
the method metadata for this method.'
# It appears that the geoprocessor does not maintain a reference count
# on checked out extensions. Thus, you can call CheckOutExtension
# multiple times for the same extension, but if you call
# CheckInExtension just once, the extension is no longer checked out.
# As a result, if we checked out an extension in a previous call we
# have no guarantee that it is still checked out, because the caller
# could have checked it in. To mitigate this, we always check out the
# extension every time we're called. This seems to have no ill
effects.
# It does not cause multiple licenses to be taken from the license
# server, and it does not yield an excessive performance hit (the
# CheckOutExtension call returns relatively quickly).
#
# We also never check in the extension, because we don't know if this
# would foul up the caller (he may assume the geoprocessor is
reference-
# counting the extensions, when it really is not...)
status = gp.CheckOutExtension(self.ExtensionCode)
if status is None:
Logger.RaiseException(SoftwareNotInstalledError(_(u'This tool
requires the ArcGIS \"%(extension)s\" extension. The ArcGIS geoprocessor
failed to report the status of the license for that extension. Please verify
that you possess a license for that extension and that the extension is
installed. If you use an ArcGIS license server, verify that this computer can
properly communicate with it.') % {u'extension': self.ExtensionCode}))
elif status.lower() != u'checkedout':
Logger.RaiseException(SoftwareNotInstalledError(_(u'This tool
requires the ArcGIS \"%(extension)s\" extension. The ArcGIS geoprocessor
reported the following status for that license level: \"%(status)s\". Please
verify that you possess a license for that extension and that the extension
is installed. If you use an ArcGIS license server, verify that this computer
can properly communicate with it.') % {u'extension': self.ExtensionCode,
u'status' :
ArcGISProductDependency._ProductStatus[self.MinimumProductLevel]}))
def GetConstraintDescriptionStrings(self):
return [u'ArcGIS "%s" extension' % self.ExtensionCode]
class ArcGISError(GeoEcoError):
__doc__ = DynamicDocString()
def ValidateMethodMetadataForExposureAsArcGISTool(moduleName, className,
methodName):
# Validate the class and method metadata.
assert sys.modules.has_key(moduleName), u'Module %s must be imported
before ValidateMethodMetadataForExposureAsArcGISTool is invoked on that
module.' % moduleName
assert sys.modules[moduleName].__dict__.has_key(className) and
issubclass(sys.modules[moduleName].__dict__[className], object), u'Module %s
must contain a class named %s, and the class must derive from object.' %
(moduleName, className)
cls = sys.modules[moduleName].__dict__[className]
assert isinstance(cls.__doc__, DynamicDocString) and
isinstance(cls.__doc__.Obj, ClassMetadata), u'The __doc__ attribute of class
%s must be an instance of DynamicDocString, and that Obj property of that
instance must be an instance of ClassMetadata.' % className
assert hasattr(cls, methodName) and inspect.ismethod(getattr(cls,
methodName)), u'Class %s must contain an instance method or classmethod named
%s.' % (className, methodName)
assert isinstance(getattr(cls, methodName).__doc__, DynamicDocString)
and isinstance(getattr(cls, methodName).__doc__.Obj, MethodMetadata), u'The
__doc__ attribute of method %s of class %s must be an instance of
DynamicDocString, and that Obj property of that instance must be an instance
of MethodMetadata.' % (methodName, className)
methodMetadata = getattr(cls, methodName).__doc__.Obj
assert methodMetadata.IsInstanceMethod or
methodMetadata.IsClassMethod, u'Method %s of class %s must be an instance
method or a classmethod.' % (methodName, className)
assert methodMetadata.IsExposedAsArcGISTool,
u'%s.%s.__doc__.Obj.IsExposedAsArcGISTool must be true.' % (className,
methodName)
assert isinstance(methodMetadata.ArcGISDisplayName,
types.UnicodeType), u'%s.%s.__doc__.Obj.ArcGISDisplayName must be a unicode
string.' % (className, methodName)
assert '_' not in className and '_' not in methodName, u'In order for
method %s of class %s to be exposed as an ArcGIS tool, neither the method
name nor the class name may contain an underscore.' % (methodName, className)
# Validate the metadata for the method's arguments.
(args, varargs, varkw, defaults) = inspect.getargspec(getattr(cls,
methodName))
assert varargs is None, u'%s.%s cannot include a varargs argument
because this method is designated for exposure as an ArcGIS tool (ArcGIS
tools do not support varargs arguments). Please remove the *%s argument.'
(className, methodName, varargs)
assert varkw is None, u'%s.%s cannot include a varkw argument because
this method is designated for exposure as an ArcGIS tool (ArcGIS tools do not
support varkw arguments). Please remove the **%s argument.' (className,
methodName, varkw)
assert len(methodMetadata.Arguments) == len(args),
u'%s.%s.__doc__.Obj.Arguments must contain exactly one element for each
argument to %s.%s. %s.%s.__doc__.Obj.Arguments contains %i elements, but %i
elements were expected.' % (className, methodName, className, methodName,
className, methodName, len(methodMetadata.Arguments), len(args))
for i in range(1, len(args)): # Skip the self or cls argument
assert methodMetadata.Arguments[i].Name == args[i],
u'%s.%s.__doc__.Obj.Arguments[%i].Name must match the name of argument %i of
%s.%s (where 0 is the first argument).' % (className, methodName, i, i,
className, methodName)
assert isinstance(methodMetadata.Arguments[i].Type,
TypeMetadata), u'%s.%s.__doc__.Obj.Arguments[%i].Type must be an instance of
GeoEco.Metadata.TypeMetadata.' % (className, methodName, i)
if methodMetadata.Arguments[i].ArcGISDisplayName is not None:
assert
isinstance(methodMetadata.Arguments[i].ArcGISDisplayName, types.UnicodeType),
u'%s.%s.__doc__.Obj.Arguments[%i].ArcGISDisplayName must be a unicode
string.' % (className, methodName, i)
assert
methodMetadata.Arguments[i].Type.CanBeArcGISInputParameter,
u'%s.%s.__doc__.Obj.Arguments[%i].Type.CanBeArcGISInputParameter must be
True' % (className, methodName, i)
assert
methodMetadata.Arguments[i].InitializeToArcGISGeoprocessorVariable is None,
u'Argument %i of %s.%s cannot have a value for ArcGISDisplayName when
InitializeToArcGISGeoprocessorVariable is True. Either the argument can have
an ArcGISDisplayName, in which case the argument is exposed as an ArcGIS
parameter, or it can have InitializeToArcGISGeoprocessorVariable set to True,
in which case the argument is not exposed in ArcGIS but is initialized to a
geoprocessor variable.' % (i, className, methodName)
if methodMetadata.Arguments[i].ArcGISParameterDependencies is
not None:
for param in
methodMetadata.Arguments[i].ArcGISParameterDependencies:
assert param != methodMetadata.Arguments[i].Name,
u'%s.%s.__doc__.Obj.Arguments[%i].ArcGISParameterDependencies must not
declare that this argument has a dependency on itself.' % (className,
methodName, i)
assert param in args,
u'%s.%s.__doc__.Obj.Arguments[%i].ArcGISParameterDependencies must declare
dependencies on existing arguments. The argument \'%s\' does not exist.' %
(className, methodName, i, param)
else:
assert methodMetadata.Arguments[i].HasDefault or
methodMetadata.Arguments[i].InitializeToArcGISGeoprocessorVariable is not
None, u'Argument %i of %s.%s must have a default value, or its metadata must
specify that it should be initialized to an ArcGIS geoprocessor variable,
because the method is designated for exposure as an ArcGIS tool but the
argument itself is not (its ArcGISDisplayName is None).' % (i, className,
methodName)
# Validate the metadata for the method's results.
for i in range(len(methodMetadata.Results)):
assert isinstance(methodMetadata.Results[i].Type, TypeMetadata),
u'%s.%s.__doc__.Obj.Results[%i].Type must be an instance of
GeoEco.Metadata.TypeMetadata.' % (className, methodName, i)
if methodMetadata.Results[i].ArcGISDisplayName is not None:
assert
isinstance(methodMetadata.Results[i].ArcGISDisplayName, types.UnicodeType),
u'%s.%s.__doc__.Obj.Results[%i].ArcGISDisplayName must be a unicode string.'
% (className, methodName, i)
assert
methodMetadata.Results[i].Type.CanBeArcGISOutputParameter,
u'%s.%s.__doc__.Obj.Results[%i].Type.CanBeArcGISOutputParameter must be True'
% (className, methodName, i)
if methodMetadata.Results[i].ArcGISParameterDependencies is
not None:
for param in
methodMetadata.Results[i].ArcGISParameterDependencies:
assert param in args,
u'%s.%s.__doc__.Obj.Results[%i].ArcGISParameterDependencies must declare
dependencies on existing arguments. The argument \'%s\' does not exist.' %
(className, methodName, i, param)
class _ArcGISObjectWrapper(object):
def __init__(self, obj, name=None):
assert isinstance(name, (types.UnicodeType, types.NoneType)), u'The
name argument must be a unicode string, or None.'
if name is not None:
self._Name = name
else:
self._Name = u'<unknown>'
self._Object = obj
self._WrappedMethods = {}
def _LogDebug(self, format, *args, **kwargs):
try:
logging.getLogger(u'GeoEco.ArcGIS').debug(format, *args, **kwargs)
except:
pass
def _LogInfo(self, format, *args, **kwargs):
try:
logging.getLogger(u'GeoEco.ArcGIS').info(format, *args, **kwargs)
except:
pass
def _LogWarning(self, format, *args, **kwargs):
try:
logging.getLogger(u'GeoEco.ArcGIS').warning(format, *args,
**kwargs)
except:
pass
def _LogError(self, format, *args, **kwargs):
try:
logging.getLogger(u'GeoEco.ArcGIS').error(format, *args, **kwargs)
except:
pass
def __getattr__(self, name):
assert isinstance(name, basestring), u'name must be a string.'
# If the caller is asking for a private attribute (the name starts
with
# an underscore), he wants an attribute of the wrapper class instance,
# not of the wrapped object. In this case, we must use the object
# class's implementation of __getattr__.
if isinstance(name, types.StringType):
name = unicode(name)
if name.startswith(u'_'):
return object.__getattribute__(self, name)
# The caller is asking for a data attribute or a method of the wrapped
# object. If we already built a wrapper method for the specified name,
# it means the caller asked for it before and we determined that it
was
# a method. Return the wrapped method to the caller now.
if self._WrappedMethods.has_key(name.lower()):
return new.instancemethod(self._WrappedMethods[name.lower()],
self, _ArcGISObjectWrapper)
# Retrieve the attribute from the wrapped object.
try:
# If we imported pythoncom successfully, get the value and
# catch com_error. Raise com_error as ArcGISError.
#
# Note: call raise, rather than Logger.RaiseException.
# This is so the caller can swallow the exception, if
# needed. Python's hasattr function works by calling
# getattr and seeing if it raises an exception. If we call
# Logger.RaiseException, we will break this behavior
# because we'll cause error messages to be reported. We
# leave it to the caller to call
# Logger.LogExceptionAsError, if needed.
if sys.modules.has_key('pythoncom'):
try:
value = getattr(self._Object, name)
except sys.modules['pythoncom'].com_error, (hr, msg, exc,
arg):
from GeoEco.COM import FormatCOMError
raise ArcGISError(_(u'Failed to get the value of the %s
attribute of ArcGIS %s object 0x%08X. This may result from a problem with
your inputs or it may indicate a programming mistake in this tool or ArcGIS
itself. Please check your inputs and try again. Also review any preceding
error messages and the detailed error information that appears at the end of
this message. If you suspect a programming mistake in this tool or ArcGIS,
please contact the author of this tool for assistance. Detailed error
information: The following exception was raised when the property retrieved:
%s') % (name, self._Name, id(self._Object), FormatCOMError(hr, msg, exc,
arg)))
# If we did not import pythoncom, set the value and allow the
outer
# exception handler to catch any errors.
else:
try:
value = getattr(self._Object, name)
except AttributeError, e:
# ArcGIS 10 seems to randomly fail with AttributeError:
DescribeData: Method SpatialReference does not exist.
# If we failed to retrieve SpatialReference, try again
once.
if name == 'SpatialReference':
value = getattr(self._Object, name)
else:
raise
# If we catch ArcGISError here, it is the com_error we just caught.
# Reraise it.
except ArcGISError:
raise
# If we catch some other exception, raise it as ArcGISError.
#
# Note: call raise, rather than Logger.RaiseException. This is
# so the caller can swallow the exception, if needed. Python's
# hasattr function works by calling getattr and seeing if it
# raises an exception. If we call Logger.RaiseException, we
# will break this behavior because we'll cause error messages
# to be reported. We leave it to the caller to call
# Logger.LogExceptionAsError, if needed.
except Exception, e:
raise ArcGISError(_(u'Failed to get the value of the %s attribute
of ArcGIS %s object 0x%08X. This may result from a problem with your inputs
or it may indicate a programming mistake in this tool or ArcGIS itself.
Please check your inputs and try again. Also review any preceding error
messages and the detailed error information that appears at the end of this
message. If you suspect a programming mistake in this tool or ArcGIS, please
contact the author of this tool for assistance. Detailed error information:
The following exception was raised when the property retrieved: %s: %s') %
(name, self._Name, id(self._Object), e.__class__.__name__, unicode(e)))
# If it is a method, create a wrapper, add it to our dictionary of
# wrapped methods, and return the wrapper.
#
# Note: for ArcGIS 10.1, geoprocessing tools are no longer
# returned as methods or functions. Instead they are instances
# of <type 'geoprocessing Tool object'>, which are callable
# like methods.
if isinstance(value, (types.MethodType, types.BuiltinFunctionType,
types.BuiltinMethodType)) or (GeoprocessorManager.GetArcGISMajorVersion() ==
10 and GeoprocessorManager.GetArcGISMinorVersion() >= 1 or
GeoprocessorManager.GetArcGISMajorVersion() > 10) and isinstance(value,
type(getattr(GeoprocessorManager.GetGeoprocessor(), 'Delete_management'))):
# Write the methods's definition.
#
# If we obtained the geoprocessor object through COM Automation,
the
# object is a Python class with normal methods, and we can obtain
# their signatures through inspect.getargspec.
#
# If we obtained the geoprocessor object through
# arcgisscripting.create(), the object is not a class, but it has
# attributes that are "builtin" functions. These functions cannot
be
# inspected so we cannot determine their signatures. In this case,
# we just assume the signature is func(self, *args). This should
# work fine because our callers will not be passing in neither
named
# formal parameters nor keyword dictionaries.
if isinstance(value, types.MethodType):
(args, varargs, varkw, defaults) = inspect.getargspec(value)
sourceCode = 'def %s%s:\n' % (str(name),
inspect.formatargspec(args, varargs, varkw, defaults))
else:
sourceCode = 'def %s(self, *args):\n' % str(name)
# Write the method's body.
sourceCode = sourceCode + ' return
self._InvokeMethod(self._Object.%s)\n' % name
# Compile the method.
_locals = {}
exec sourceCode in globals(), _locals
# Add it to our dictionary of wrapped methods.
self._WrappedMethods[name.lower()] = _locals[name]
# Return it to the caller.
return new.instancemethod(_locals[name], self,
_ArcGISObjectWrapper)
# Log the returned attribute value.
try:
self._LogDebug(_(u'ArcGIS %s object 0x%08X: Get %s returned %s')
% (self._Name, id(self._Object), name, repr(value)))
except:
self._LogDebug(_(u'ArcGIS %s object 0x%08X: Get %s returned %s')
% (self._Name, id(self._Object), name, type(value))) # In ArcGIS 10.2,
repr(value) fails (with TypeError: bad argument type for built-in operation)
when value is a geoprocessing tool like gp.CreateSpatialReference_management.
Try again using type(value)
# The returned value is a property. Convert it from the geoprocessor's
# preferred type to the type we prefer.
value = self._FromGeoprocessorPreferredType(value, name)
# Special case: If the geoprocessor was created with
# arcgisscripting.create(), and we're retrieving a field of a row of a
# cursor, and that field is supposed to be a date, parse a datetime
from
# the string returned by the geoprocessor.
nameLower = name.lower()
if (self._Name == u'Row' or self._Name == u'ReadOnlyRow') and
nameLower != u'getvalue' and nameLower != u'setvalue' and nameLower !=
u'isnull' and nameLower != u'setnull' and not
GeoprocessorManager.GetGeoprocessorIsCOMObject():
fieldDataType = None
if self._FieldTypesDict.has_key(nameLower):
fieldDataType = self._FieldTypesDict[nameLower]
else:
try:
fieldDataType =
GeoprocessorManager.GetWrappedGeoprocessor().ListFields(self._Table,
nameLower).Next().Type.lower()
except:
pass
self._FieldTypesDict[nameLower] = fieldDataType
if fieldDataType == u'date':
value = DateTimeTypeMetadata.ParseDatetimeFromString(value)
# Special case: The Extent property of the Describe object is
# string containing a space-delimited list of the four
# coordinates of the sides of a bounding box. The coordinates
# are floating point numbers. An MGET user reported to
# mget-help that ArcGIS 10.2 apparently will return numbers
# using a comma as the decimal point rather than a period,
# probably on a French operating system or version of ArcGIS.
# It resulted in this failure:
#
# Traceback (most recent call last):
# File "C:\Program
Files\GeoEco\ArcGISToolbox\Scripts\ArcGISLinesFromVectorComponentRasters.py",
line 5, in <module>
#
ExecuteMethodFromCommandLineAsArcGISTool('GeoEco.SpatialAnalysis.Lines',
'ArcGISLines', 'FromVectorComponentRasters')
# ...
# File "C:\Python27\lib\site-packages\GeoEco\Datasets\ArcGIS.py",
line 1403, in _GetLazyPropertyPhysicalValue
# self.SetLazyPropertyValue('CornerCoords',
(float(d.Extent.split()[1]) + d.MeanCellHeight / 2.0,
float(d.Extent.split()[0]) + d.MeanCellWidth / 2.0))
# ValueError: invalid literal for float(): 18,75
#
# So, if the caller is asking for the Extent property of the
# Describe object, replace commas with periods before
# returning it.
if self._Name.lower() == u'describe' and nameLower == u'extent' and
isinstance(value, basestring):
value = value.replace(',', '.')
# Return the attribute value.
return value
def __setattr__(self, name, value):
assert isinstance(name, basestring), u'name must be a string.'
# If the caller is asking for a private attribute (the name starts
with
# an underscore), he wants to set an attribute of the wrapper class
# instance, not of the wrapped object. In this case, we must use the
# object class's implementation of __setattr__.
if isinstance(name, types.StringType):
name = unicode(name)
if name.startswith(u'_'):
return object.__setattr__(self, name, value)
# The caller wants to set an attribute of the wrapped object. Convert
# the value from our preferred type to that preferred by the
# geoprocessor.
valueIsNone = value is None
value = self._ToGeoprocessorPreferredType(value)
# Set the attribute.
try:
# If we imported pythoncom successfully, set the value and
# catch com_error. Raise com_error as ArcGISError. Note:
# call raise, rather than Logger.RaiseException. This is
# so the caller can swallow the exception, if needed.
if sys.modules.has_key('pythoncom'):
try:
# ArcGIS sometimes accepts None, sometimes rejects
# it but will accept an empty string instead. I
# cannot determine a consistent pattern. We try ''
# first. If that fails, try None.
try:
setattr(self._Object, name, value)
except:
if valueIsNone and value == '':
setattr(self._Object, name, None)
else:
raise
except sys.modules['pythoncom'].com_error, (hr, msg, exc,
arg):
from GeoEco.COM import FormatCOMError
raise ArcGISError(_(u'Failed to set the %s property of
ArcGIS %s object 0x%08X to %s. This may result from a problem with your
inputs or it may indicate a programming mistake in this tool or ArcGIS
itself. Please check your inputs and try again. Also review any preceding
error messages and the detailed error information that appears at the end of
this message. If you suspect a programming mistake in this tool or ArcGIS,
please contact the author of this tool for assistance. Detailed error
information: The following exception was raised when the property was
assigned: %s') % (name, self._Name, id(self._Object), repr(value),
FormatCOMError(hr, msg, exc, arg)))
# If we did not import pythoncom, set the value and allow the
outer
# exception handler to catch any errors.
else:
setattr(self._Object, name, value)
# If we catch ArcGISError here, it is the com_error we just caught.
# Reraise it.
except ArcGISError:
raise
# If we catch some other exception, raise it as ArcGISError.
# Note: call raise, rather than Logger.RaiseException. This is
# so the caller can swallow the exception, if needed.
except Exception, e:
raise ArcGISError(_(u'Failed to set the %s property of ArcGIS %s
object 0x%08X to %s. This may result from a problem with your inputs or it
may indicate a programming mistake in this tool or ArcGIS itself. Please
check your inputs and try again. Also review any preceding error messages and
the detailed error information that appears at the end of this message. If
you suspect a programming mistake in this tool or ArcGIS, please contact the
author of this tool for assistance. Detailed error information: The following
exception was raised when the property was assigned: %s: %s') % (name,
self._Name, id(self._Object), repr(value), e.__class__.__name__, unicode(e)))
# Log the set value.
self._LogDebug(_(u'ArcGIS %s object 0x%08X: Set %s to %s') %
(self._Name, id(self._Object), name, repr(value)))
def _InvokeMethod(self, method):
# Convert the arguments from the types we prefer to those preferred
# by the geoprocessor.
(_args, _varargs, _varkw, _locals) =
inspect.getargvalues(inspect.currentframe().f_back)
del _args[0]
for argName in _args:
_locals[argName] =
self._ToGeoprocessorPreferredType(_locals[argName])
if hasattr(method, 'Name') and isinstance(method.Name, basestring)
and len(method.Name) > 0:
if hasattr(method, 'Toolbox') and hasattr(method.Toolbox,
'Alias') and isinstance(method.Toolbox.Alias, basestring) and
len(method.Toolbox.Alias) > 0:
methodName = method.Name + '_' + method.Toolbox.Alias
else:
methodName = method.Name
else:
methodName = method.__name__
if _varargs is not None:
# Hack: In ArcGIS 9.3.1 SP1, ESRI finally fixed NIM010734,
# in which the SetValue method of a Row object obtained
# from a cursor opened with the arcgisscripting
# geoprocessor would not accept None in order to set the
# field to a database NULL value. So, if this is the
# SetValue method of a Row object and the second parameter
# is None, leave it as none.
#
# In all other circumstances, do the normal behavior:
# allow self._ToGeoprocessorPreferredType to translate all
# Nones to empty strings, when the arcgisscripting
# geoprocessor is used.
if self._Name == 'Row' and methodName.lower() == 'setvalue' and
len(_locals[_varargs]) == 2 and _locals[_varargs][1] is None:
_locals[_varargs] =
(self._ToGeoprocessorPreferredType(_locals[_varargs][0]), None)
else:
_locals[_varargs] =
self._ToGeoprocessorPreferredType(_locals[_varargs])
# Build the source code needed to invoke the method.
sourceCode = 'self._Object.%s(' % methodName
for argName in _args:
if not sourceCode.endswith('('):
sourceCode = sourceCode + ', '
sourceCode = sourceCode + '%s=_locals[\'%s\']' % (argName,
argName)
if _varargs is not None:
if not sourceCode.endswith('('):
sourceCode = sourceCode + ', '
sourceCode = sourceCode + '*_locals[\'%s\'] ' % _varargs
sourceCode = sourceCode + ')'
# Before invoking the method, check whether it is a Spatial
# Analyst tool, which is indicated by it ending in "_sa". If
# it is, create a temp directory and set the ScratchWorkspace
# to it.
#
# We do this because some Spatial Analyst tools, particularly
# the Map Algebra tools, create temporary ArcInfo binary grids
# as part of their processing, but they do not delete them
# upon completion. These will accumulate in the user's TEMP
# directory unless a ScratchWorkspace has been set. Once
# several thousand exist, the Spatial Analyst tools will stop
# working (ArcCatalog or ArcMap will crash) until they are
# deleted.
#
# Users typically encounter this only after running several
# thousand Spatial Analyst tools without logging off. Windows
# deletes the contents of the TEMP directory at logoff.
# Nonetheless, certain batch jobs, such as converting
# thousands of HDFs to rasters, are common scenarios for
# GeoEco users so we must protect them from this problem.
try:
tempDir = None
scratchDir = None
if self._Name == u'Geoprocessor' and methodName.endswith('_sa'):
scratchDir = self.ScratchWorkspace
from GeoEco.DataManagement.Directories import
TemporaryDirectory
tempDir = TemporaryDirectory()
self.ScratchWorkspace = tempDir.Path
# Invoke the method.
self._LogDebug(_(u'ArcGIS %s object 0x%08X: Invoking %s%s...') %
(self._Name, id(self._Object), methodName, inspect.formatargvalues(_args,
_varargs, _varkw, _locals)))
try:
# If we imported pythoncom successfully, invoke the method
# and catch com_error. Raise com_error as ArcGISError.
# Note: call raise, rather than Logger.RaiseException.
# This is so the caller can swallow the exception, if
# needed.
if sys.modules.has_key('pythoncom'):
try:
value = eval(sourceCode, globals(), locals())
except sys.modules['pythoncom'].com_error, (hr, msg, exc,
arg):
self._LogReturnedGeoprocessingMessages(methodName)
from GeoEco.COM import FormatCOMError
if self._Name == u'Geoprocessor' and
methodName.lower() not in _ArcGISObjectWrapper._NonGeoprocessingToolMethods:
raise ArcGISError(_(u'The ArcGIS %(tool)s
geoprocessing tool failed when given the parameters %(params)s and reported
%(error)s') % {u'tool': methodName, u'params': inspect.formatargvalues(_args,
_varargs, _varkw, _locals), u'error': FormatCOMError(hr, msg, exc, arg)})
else:
raise ArcGISError(_(u'The %(func)s function of
the ArcGIS %(obj)s object failed when given the parameters %(params)s and
reported %(error)s') % {u'func': methodName, u'obj': self._Name, u'params':
inspect.formatargvalues(_args, _varargs, _varkw, _locals), u'error':
FormatCOMError(hr, msg, exc, arg)})
# If we did not import pythoncom, invoke the method and allow
the
# outer exception handler to catch any errors.
else:
value = eval(sourceCode, globals(), locals())
# If we catch ArcGISError here, it is the com_error we just
caught.
# Reraise it.
except ArcGISError:
raise
# If we catch some other exception, raise it as ArcGISError.
# Note: call raise, rather than Logger.RaiseException. This is
# so the caller can swallow the exception, if needed.
except Exception, e:
self._LogReturnedGeoprocessingMessages(methodName)
if self._Name == u'Geoprocessor' and methodName.lower() not
in _ArcGISObjectWrapper._NonGeoprocessingToolMethods:
raise ArcGISError(_(u'The ArcGIS %(tool)s geoprocessing
tool failed when given the parameters %(params)s and reported %(error)s:
%(msg)s') % {u'tool': methodName, u'params': inspect.formatargvalues(_args,
_varargs, _varkw, _locals), u'error': e.__class__.__name__, u'msg':
unicode(e)})
else:
raise ArcGISError(_(u'The %(func)s function of the ArcGIS
%(obj)s object failed when given the parameters %(params)s and reported
%(error)s') % {u'func': methodName, u'obj': self._Name, u'params':
inspect.formatargvalues(_args, _varargs, _varkw, _locals), u'error':
e.__class__.__name__, u'msg': unicode(e)})
# The method executed successfully. Log any geoprocessing
messages it
# generated.
self._LogReturnedGeoprocessingMessages(methodName)
# Log the returned value.
self._LogDebug(_(u'ArcGIS %s object 0x%08X: %s returned %s') %
(self._Name, id(self._Object), methodName, repr(value)))
# If we created a temporary directory to manage the rasters
# leaked by the Spatial Analyst tools, delete it now.
finally:
if tempDir is not None:
try:
del tempDir
except:
pass
self.ScratchWorkspace = scratchDir
# Convert the returned value from the geoprocessor's preferred type to
# the type we prefer.
value = self._FromGeoprocessorPreferredType(value, methodName,
*(tuple(map(_locals.get, _args)) + _locals[_varargs]))
# Special case: If the geoprocessor was created with
# arcgisscripting.create(), and we're retrieving a field of a row of a
# cursor, and that field is supposed to be a date, parse a datetime
from
# the string returned by the geoprocessor.
if not GeoprocessorManager.GetGeoprocessorIsCOMObject() and value is
not None:
methodName = methodName.lower()
if self._Name == u'Geoprocessor' and (methodName ==
u'searchcursor' or methodName == u'insertcursor' or methodName ==
u'updatecursor'):
if len(_args) > 0:
value._Table = _locals[_args[0]]
else:
value._Table = _locals[_varargs][0]
value._FieldTypesDict = {}
elif (self._Name == u'SearchCursor' or self._Name ==
u'UpdateCursor') and methodName == u'next' or self._Name == u'InsertCursor'
and methodName == u'newrow':
value._Table = self._Table
value._FieldTypesDict = self._FieldTypesDict
elif (self._Name == u'Row' or self._Name == u'ReadOnlyRow') and
methodName == u'getvalue':
if len(_args) > 0:
field = _locals[_args[0]].lower()
else:
field = _locals[_varargs][0].lower()
fieldDataType = None
if self._FieldTypesDict.has_key(field):
fieldDataType = self._FieldTypesDict[field]
else:
try:
fieldDataType =
GeoprocessorManager.GetWrappedGeoprocessor().ListFields(self._Table,
field).Next().Type.lower()
except:
pass
self._FieldTypesDict[field] = fieldDataType
if fieldDataType == u'date':
value =
DateTimeTypeMetadata.ParseDatetimeFromString(value)
# Return the returned value.
return value
_NonGeoprocessingToolMethods = {
'adderror' : None,
'addmessage' : None,
'addreturnmessage' : None,
'addtoolbox' : None,
'addwarning' : None,
'checkextension' : None,
'checkinextension' : None,
'checkoutextension' : None,
'checkproduct' : None,
'clearenvironment' : None,
'command' : None,
'copyparameter' : None,
'createobject' : None,
'createrandomvaluegenerator' : None,
'createscratchname' : None,
'createuniquename' : None,
'describe' : None,
'exists' : None,
'getmessage' : None,
'getmessages' : None,
'getparameter' : None,
'getparameterastext' : None,
'getparametercount' : None,
'getparametervalue' : None,
'getreturncode' : None,
'getseverity' : None,
'getsystemenvironment' : None,
'insertcursor' : None,
'issynchronous' : None,
'listdatasets' : None,
'listenvironments' : None,
'listfeatureclasses' : None,
'listfields' : None,
'listindexes' : None,
'listrasters' : None,
'listtables' : None,
'listtoolboxes' : None,
'listtools' : None,
'listworkspaces' : None,
'loadsettings' : None,
'parsefieldname' : None,
'parsetablename' : None,
'productinfo' : None,
'qualifyfieldname' : None,
'qualifytablename' : None,
'refreshcatalog' : None,
'removetoolbox' : None,
'resetenvironments' : None,
'savesettings' : None,
'searchcursor' : None,
'setparameter' : None,
'setparameterastext' : None,
'setproduct' : None,
'testschemalock' : None,
'updatecursor' : None,
'usage' : None,
'validatefieldname' : None,
'validatetablename' : None
}
def _LogReturnedGeoprocessingMessages(self, methodName):
# Only log the messages returned by the geoprocessor if the
# invoked method appears to be a geoprocessing tool. The other
# methods of the geoprocessor, the ones that are not
# geoprocessing tools, do not report any messages. If the
# geoprocessor object was created with
# arcgisscripting.create(), it will not clear out the message
# queue when one of these non-geoprocessing-tool methods is
# called. If the messages queue is examined again, it will
# have the same messages as before. For example, if
# SingleOutputMapAlgebra_sa is called, followed by
# RefreshCatalog, the messages from SingleOutputMapAlgebra_sa
# will still be in the queue following the call to
# RefreshCatalog. We must avoid logging these again, as if
# they were reported by RefreshCatalog. See ticket #132.
#
# This behavior of the geoprocessor is a change introduced in
# ArcGIS 9.2 and only seems to occur if the geoprocessor was
# created with arcgisscripting.create(). But we do the same
# logic in all circumstances. This probably yields a minor
# performance gain when calling non-geoprocessing-tool methods
# of the geoprocessor.
if self._Name == u'Geoprocessor' and not
_ArcGISObjectWrapper._NonGeoprocessingToolMethods.has_key(methodName.lower()):
i = 0
try:
geoprocessor = GeoprocessorManager.GetGeoprocessor()
if geoprocessor is not None:
try:
while i < geoprocessor.MessageCount:
sev = geoprocessor.GetSeverity(i)
if sev == 0:
self._LogInfo(geoprocessor.GetMessage(i))
elif sev == 1:
self._LogWarning(geoprocessor.GetMessage(i))
else:
self._LogError(geoprocessor.GetMessage(i))
i += 1
finally:
del geoprocessor
except:
pass
def _ToGeoprocessorPreferredType(self, value):
# Process every item in lists and tuples.
if isinstance(value, types.ListType):
return self._ToGeoprocessorPreferredTypeList(value)
if isinstance(value, types.TupleType):
l = list(value)
l = self._ToGeoprocessorPreferredTypeList(l)
return tuple(l)
# When the geoprocessor is obtained through arcgisscripting.create(),
it
# expects 8-bit strings.
geoprocessorIsCOMObject =
GeoprocessorManager.GetGeoprocessorIsCOMObject()
if not geoprocessorIsCOMObject and isinstance(value,
types.UnicodeType):
return UnicodeToUserPreferredEncoding(value)
# When the geoprocessor is obtained through COM Automation, it expects
# dates as pywintypes.TimeType instances. When it is obtained through
# arcgisscripting.create(), it expects strings.
if isinstance(value, datetime.datetime):
if geoprocessorIsCOMObject:
import pywintypes
return pywintypes.Time((value.year, value.month, value.day,
value.hour, value.minute, value.second, 0, 0, 0))
else:
return value.strftime('%Y-%m-%d %H:%M:%S')
elif isinstance(value, datetime.date):
if geoprocessorIsCOMObject:
import pywintypes
return pywintypes.Time((value.year, value.month, value.day,
0, 0, 0, 0, 0, 0))
else:
return value.strftime('%Y-%m-%d 00:00:00')
# When the geoprocessor is obtained through arcgisscripting.create(),
it
# expects integers rather than booleans.
#
# NOTE: This is commented out beacuse it seems the geoprocessor will
# accept booleans, even though it returns integers.
## if not geoprocessorIsCOMObject and isinstance(value,
types.BooleanType):
## return int(value)
# Under some scenarios, the geoprocessor does not like to set
# attributes to None (see, for example, Trac Ticket #505). But
# it seems to usually allow setting attributes to an empty
# string in place of None.
if isinstance(value, types.NoneType):
return ''
# If the value is wrapped with a _ArcGISObjectWrapper, return the
# wrapped object.
if isinstance(value, _ArcGISObjectWrapper):
return value._Object
# The value is fine as it is. Just return it.
return value
def _ToGeoprocessorPreferredTypeList(self, value):
for i in range(len(value)):
value[i] = self._ToGeoprocessorPreferredType(value[i])
return value
def _FromGeoprocessorPreferredType(self, value, name, *args):
# Process every item in lists and tuples.
if isinstance(value, types.ListType):
return self._FromGeoprocessorPreferredTypeList(value)
if isinstance(value, types.TupleType):
l = list(value)
l = self._FromGeoprocessorPreferredTypeList(l)
return tuple(l)
# When the geoprocessor is obtained through arcgisscripting.create(),
it
# returns 8-bit strings, but if we obtain it through COM Automation,
it
# returns Unicode strings. We always prefer Unicode, so ensure it is
in
# Unicode.
if isinstance(value, types.StringType):
return UserPreferredEncodingToUnicode(value)
# When the geoprocessor is obtained through COM Automation, it
# returns dates as pywintypes.TimeType instances. We prefer
# datetime.datetime instances.
if not sys.modules.has_key('pywintypes'):
try:
import pywintypes # It is not really necessary to do
this, but because I'm fixing this right before MGET 0.7 is released, I'm
being extra careful.
except:
pass
if sys.modules.has_key('pywintypes') and isinstance(value,
sys.modules['pywintypes'].TimeType):
return datetime.datetime(value.year, value.month, value.day,
value.hour, value.minute, value.second, value.msec)
# If it is a class instance, wrap it in _ArcGISObjectWrapper.
if not isinstance(value, (types.BooleanType, types.FloatType,
types.IntType, types.ListType, types.LongType, types.NoneType, basestring,
datetime.datetime)):
wrap = False
objName = self._LookupReturnedObjectName(name, *args)
try:
if objName is not None or isinstance(value,
types.InstanceType) or inspect.getmodule(type(value)) !=
sys.modules[u'__builtin__']: # Shouldn't raise an exception, but I'm
suspicious of inspect.getmodule
wrap = True
except:
pass
if wrap:
return _ArcGISObjectWrapper(value, objName)
# The value is fine as it is. Just return it.
return value
def _FromGeoprocessorPreferredTypeList(self, value):
for i in range(len(value)):
value[i] = self._FromGeoprocessorPreferredType(value[i],
u'<unknown>')
return value
def _LookupReturnedObjectName(self, name, *args):
_Name = self._Name.lower()
name = name.lower()
if not _ArcGISObjectWrapper._NameMap.has_key(_Name):
return None
if not isinstance(_ArcGISObjectWrapper._NameMap[_Name],
types.DictType):
return _ArcGISObjectWrapper._NameMap[_Name]
if not _ArcGISObjectWrapper._NameMap[_Name].has_key(name):
return None
if not isinstance(_ArcGISObjectWrapper._NameMap[_Name][name],
types.DictType):
return _ArcGISObjectWrapper._NameMap[_Name][name]
d = _ArcGISObjectWrapper._NameMap[_Name][name]
for arg in args:
if isinstance(arg, basestring):
arg = unicode(arg).lower()
if not d.has_key(arg):
return None
if not isinstance(d[arg], types.DictType):
return d[arg]
d = d[arg]
return None
_NameMap = {
u'geoprocessor' : {
u'createobject' : {
u'spatialreference' : u'SpatialReference',
u'valuetable' : u'ValueTable',
u'fieldinfo' : u'FieldInfo',
u'array' : u'Array',
u'point' : u'Point',
u'fieldmappings' : u'FieldMappings',
u'fieldmap' : u'FieldMap',
u'field' : u'Field'},
u'describe' : u'Describe',
u'listfields' : u'Fields',
u'listindexes' : u'Indexes',
u'listrasters' : u'Enumeration',
u'listtables' : u'Enumeration',
u'listworkspaces' : u'Enumeration',
u'listdatasets' : u'Enumeration',
u'listfeatureclasses' : u'Enumeration',
u'listenvironments' : u'Enumeration',
u'listtoolboxes' : u'Enumeration',
u'listtools' : u'Enumeration',
u'insertcursor' : u'InsertCursor',
u'searchcursor' : u'SearchCursor',
u'updatecursor' : u'UpdateCursor'},
u'spatialreference' : None,
u'valuetable' : None,
u'fieldinfo' : { u'getfield' : u'Field'},
u'array' : None, # Some methods return objects but we
can't tell what they are from the method signatures.
u'point' : None,
u'fieldmappings' : { u'fields' : u'Fields', u'getfieldmap' :
u'FieldMap'},
u'fieldmap' : { u'outputfield' : u'Field'},
u'field' : None,
u'fields' : { u'next' : u'Field'},
u'indexes' : { u'next' : u'Index' },
u'index' : { u'fields' : u'Fields' },
u'searchcursor' : { u'next' : u'ReadOnlyRow' },
u'insertcursor' : { u'newrow' : u'Row' },
u'updatecursor' : { u'next' : u'Row' },
u'readonlyrow' : { u'shape' : u'Geometry', u'GetValue' : { u'shape' :
u'Geometry' } },
u'row' : { u'shape' : u'Geometry', u'GetValue' : { u'shape' :
u'Geometry' } },
u'geometry': { u'getpart' : u'Point or Array' }, #
Geometry.GetPart returns either Point or Array, depending on what type of
feature it is.
u'describe' : {
u'fieldinfo' : u'FieldInfo',
u'fields' : u'Fields',
u'indexes' : u'Indexes',
u'spatialreference' : u'SpatialReference',
u'fidset' : u'FIDSet',
u'connectionproperties' : u'PropertySet',
u'tolerances' : u'PropertySet'},
u'fidset' : None,
u'PropertySet' : None}
###############################################################################
# Metadata: module
###############################################################################
from GeoEco.Metadata import *
from GeoEco.Types import *
AddModuleMetadata(shortDescription=_(u'Provides utility functions for
interacting with the ESRI ArcGIS software package.'))
###############################################################################
# Metadata: GeoprocessorManager class
###############################################################################
AddClassMetadata(GeoprocessorManager,
shortDescription=_(u'Manages the instance of the ArcGIS geoprocessor
object used whenever any GeoEco function needs to invoke ArcGIS tools.'),
isExposedAsCOMServer=True,
comIID=u'{3DAAF9BD-2C7F-4A0B-8AB1-8975103F3E78}',
comCLSID=u'{6E4B25C1-0E1D-496B-A661-AC75ADCB24C8}')
# Public properties
AddPropertyMetadata(GeoprocessorManager.Geoprocessor,
typeMetadata=AnyObjectTypeMetadata(canBeNone=True),
shortDescription=_(u'The ArcGIS geoprocessor object used whenever any
GeoEco function needs to invoke ArcGIS tools.'),
longDescription=_(
u"""This property is a singleton; all Python modules running in the same
instance of the Python interpreter share the same value for this property.
This
property remains empty until it is explicitly set, or the
InitializeGeoprocessor
method is explicitly invoked, or a GeoEco function that has a dependency on
ArcGIS is invoked (in which case it will invoke InitializeGeoprocessor).
If you want to invoke GeoEco functions from your own ArcGIS geoprocessing
script
and you have already obtained a geoprocessor object, you should set this
property to that object before invoking any other GeoEco functions. Failing to
do so will cause GeoEco to allocate its own geoprocessor object, which can
yield
unpredictable results. (As far as I can tell, the ArcGIS tools still work
correctly, but log messages may not end up in the ArcGIS GUIs.)
If your geoprocessing script has not yet obtained the geoprocessor object, you
may allow the GeoEco functions to obtain one when they first need it and then
retrieve it by getting the value of this property.
If you want to invoke GeoEco functions from something that is not a
"geoprocessing script" (a program that does not invoke any ArcGIS
geoprocessing tools directly), then you should ignore this property and
allow the GeoEco functions to obtain and use their own geoprocessor object.
See the documentation for InitializeGeoprocessor for more information about
this
property.
*Note to GeoEco developers:* Generally, GeoEco functions should *not* use this
property; they should use WrappedGeoprocessor instead. That property
implements
a wrapper around the geoprocessor that logs debug messages every time the
geoprocessor is invoked."""),
isExposedToPythonCallers=True,
isExposedByCOM=True)
AddPropertyMetadata(GeoprocessorManager.WrappedGeoprocessor,
typeMetadata=AnyObjectTypeMetadata(canBeNone=True),
shortDescription=_(u'The Geoprocessor property, wrapped by a class that
logs messages whenever the geoprocessor is accessed.'),
longDescription=_(
u"""This property is a singleton; all Python modules running in the same
instance of the Python interpreter share the same value for this property. It
is
initialized whenever the Geoprocessor property is initialized; see the
documentation for that property for more information.
This property is actually a wrapper class around the ArcGIS geoprocessor
object.
The wrapper exports the same interface as the wrapped object but logs a debug
message every time a method is invoked or a property is accessed. By default,
these debug messages are discarded by the GeoEco logging infrastructure. You
can
enable them by initializing the Logger class with a custom configuration file
or by editing the default configuration file. See the Logger class
documentation
for more information.
All GeoEco functions use WrappedGeoprocessor to access the geoprocessor,
rather
than the Geoprocessor property, so that debug messages are reported whenever
any
function accesses the geoprocessor. External callers are welcome to use
WrappedGeoprocessor as well, but they should consider using Geoprocessor
instead, to completely eliminate the chance that a bug in the wrapper would
affect their code."""),
isExposedToPythonCallers=True,
isExposedByCOM=True)
AddPropertyMetadata(GeoprocessorManager.GeoprocessorIsCOMObject,
typeMetadata=BooleanTypeMetadata(),
shortDescription=_(u'True if the object returned by the Geoprocessor
property is a COM Automation object. False if it is some other kind of object
(such as the object returned by arcgisscripting.create()).'),
isExposedToPythonCallers=True,
isExposedByCOM=True)
AddPropertyMetadata(GeoprocessorManager.ArcGISMajorVersion,
typeMetadata=IntegerTypeMetadata(canBeNone=True),
shortDescription=_(u'The major version number for ArcGIS, if it is
installed on the machine.'),
longDescription=_(u'This property is empty if ArcGIS is not installed on
the machine.'),
isExposedToPythonCallers=True,
isExposedByCOM=True)
AddPropertyMetadata(GeoprocessorManager.ArcGISMinorVersion,
typeMetadata=IntegerTypeMetadata(canBeNone=True),
shortDescription=_(u'The minor version number for ArcGIS, if it is
installed on the machine.'),
longDescription=_(u'This property is empty if ArcGIS is not installed on
the machine.'),
isExposedToPythonCallers=True,
isExposedByCOM=True)
AddPropertyMetadata(GeoprocessorManager.ArcGISServicePack,
typeMetadata=IntegerTypeMetadata(canBeNone=True),
shortDescription=_(u'The service pack number for ArcGIS, if it is
installed on the machine.'),
longDescription=_(u'This property is empty if ArcGIS is not installed on
the machine.'),
isExposedToPythonCallers=True,
isExposedByCOM=True)
# Public method: GeoprocessorManager.GetGeoprocessor
AddMethodMetadata(GeoprocessorManager.GetGeoprocessor,
shortDescription=_(u'Returns the value of the Geoprocessor property.'),
isExposedToPythonCallers=True)
AddArgumentMetadata(GeoprocessorManager.GetGeoprocessor, u'cls',
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=GeoprocessorManager),
description=_(u'%s class or an instance of it.') %
GeoprocessorManager.__name__)
AddResultMetadata(GeoprocessorManager.GetGeoprocessor, u'geoprocessor',
typeMetadata=AnyObjectTypeMetadata(canBeNone=True),
description=_(u'The value of the Geoprocessor property.'))
# Public method: GeoprocessorManager.SetGeoprocessor
AddMethodMetadata(GeoprocessorManager.SetGeoprocessor,
shortDescription=_(u'Sets the value of the Geoprocessor property.'),
isExposedToPythonCallers=True)
AddArgumentMetadata(GeoprocessorManager.SetGeoprocessor, u'cls',
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=GeoprocessorManager),
description=_(u'%s class or an instance of it.') %
GeoprocessorManager.__name__)
AddArgumentMetadata(GeoprocessorManager.SetGeoprocessor, u'geoprocessor',
typeMetadata=AnyObjectTypeMetadata(),
description=_(u'The ArcGIS geoprocessor object obtained from COM
Automation or the arcgisscripting Python module. See the documentation for
the Geoprocessor property for more information.'))
# Public method: GeoprocessorManager.GetWrappedGeoprocessor
AddMethodMetadata(GeoprocessorManager.GetWrappedGeoprocessor,
shortDescription=_(u'Returns the value of the WrappedGeoprocessor
property.'),
isExposedToPythonCallers=True)
AddArgumentMetadata(GeoprocessorManager.GetWrappedGeoprocessor, u'cls',
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=GeoprocessorManager),
description=_(u'%s class or an instance of it.') %
GeoprocessorManager.__name__)
AddResultMetadata(GeoprocessorManager.GetWrappedGeoprocessor, u'geoprocessor',
typeMetadata=AnyObjectTypeMetadata(canBeNone=True),
description=_(u'The value of the WrappedGeoprocessor property.'))
# Public method: GeoprocessorManager.GetArcGISMajorVersion
AddMethodMetadata(GeoprocessorManager.GetArcGISMajorVersion,
shortDescription=_(u'Returns the value of the ArcGISMajorVersion
property.'),
isExposedToPythonCallers=True)
AddArgumentMetadata(GeoprocessorManager.GetArcGISMajorVersion, u'cls',
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=GeoprocessorManager),
description=_(u'%s class or an instance of it.') %
GeoprocessorManager.__name__)
AddResultMetadata(GeoprocessorManager.GetArcGISMajorVersion, u'majorVersion',
typeMetadata=IntegerTypeMetadata(canBeNone=True),
description=_(u'The value of the ArcGISMajorVersion property.'))
# Public method: GeoprocessorManager.GetArcGISMinorVersion
AddMethodMetadata(GeoprocessorManager.GetArcGISMinorVersion,
shortDescription=_(u'Returns the value of the ArcGISMinorVersion
property.'),
isExposedToPythonCallers=True)
AddArgumentMetadata(GeoprocessorManager.GetArcGISMinorVersion, u'cls',
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=GeoprocessorManager),
description=_(u'%s class or an instance of it.') %
GeoprocessorManager.__name__)
AddResultMetadata(GeoprocessorManager.GetArcGISMinorVersion, u'minorVersion',
typeMetadata=IntegerTypeMetadata(canBeNone=True),
description=_(u'The value of the ArcGISMinorVersion property.'))
# Public method: GeoprocessorManager.GetArcGISServicePack
AddMethodMetadata(GeoprocessorManager.GetArcGISServicePack,
shortDescription=_(u'Returns the value of the ArcGISServicePack
property.'),
isExposedToPythonCallers=True)
AddArgumentMetadata(GeoprocessorManager.GetArcGISServicePack, u'cls',
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=GeoprocessorManager),
description=_(u'%s class or an instance of it.') %
GeoprocessorManager.__name__)
AddResultMetadata(GeoprocessorManager.GetArcGISServicePack, u'servicePack',
typeMetadata=IntegerTypeMetadata(canBeNone=True),
description=_(u'The value of the ArcGISMinorVersion property.'))
# Public method: GeoprocessorManager.InitializeGeoprocessor
AddMethodMetadata(GeoprocessorManager.InitializeGeoprocessor,
shortDescription=_(u'Initializes the Geoprocessor property with a new
ArcGIS geoprocessor object.'),
longDescription=_(
u"""If you want to use GeoEco's GeoprocessorManager to instantiate the
geoprocessor, you should either explicitly invoke this method or call
a GeoEco function that requires ArcGIS; the GeoEco function will
invoke this method on your behalf.
If you do not want to use GeoEco's GeoprocessorManager to instantiate
the geoprocessor, you should instantiate it yourself and call
GeoprocessorManager.SetGeoprocessor. GeoEco will cache a reference to
your geoprocessor and not allocate its own instance.
If the Geoprocessor property has already been initialized with a
geoprocessor object and forceCOMInstantiation and
forcePythonInstantiation are both False, this method does nothing. If
either forceCOMInstantiation or forcePythonInstantiation are True,
this method will raise a RuntimeError if the geoprocessor was
previously instantiated with the opposite method.
You should only pass True for forceCOMInstantiation or
forcePythonInstantiation if you plan to perform geoprocessing
operations that truly require one type of geoprocessor or the other.
If both are False, this method will automatically select the best
technique, as follows:
* If ArcGIS 9.1 is installed, COM Automation will always be used.
* If ArcGIS 9.2 is installed, arcgisscripting will be used if the
script is executing under Python 2.4. Otherwise COM Automation will
be used.
* If ArcGIS 9.3 is installed, arcgisscripting will be used if the
script is executing under Python 2.5. Otherwise COM Automation will
be used.
IMPORTANT NOTE: If arcgisscripting is used to instantiate the
geoprocessor, the arcgisscripting.create function will always be
called without any parameters, regardless of which version of ArcGIS
is installed. This means that, even if ArcGIS 9.3 or later is
installed, the instantiated geoprocessor will always use the inteface
from ArcGIS 9.2."""),
isExposedToPythonCallers=True,
isExposedByCOM=True)
AddArgumentMetadata(GeoprocessorManager.InitializeGeoprocessor, u'cls',
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=GeoprocessorManager),
description=_(u'%s class or an instance of it.') %
GeoprocessorManager.__name__)
AddArgumentMetadata(GeoprocessorManager.InitializeGeoprocessor,
u'forceCOMInstantiation',
typeMetadata=BooleanTypeMetadata(),
description=_(
u"""If True, the geoprocessor will be instantiated with Microsoft COM
Automation, regardless of what version of ArcGIS is installed. The
win32com.client.Dispatch function from the "Python for Windows
extensions" Python package (also known as "pywin32") will be used to
perform the instantiation."""))
AddArgumentMetadata(GeoprocessorManager.InitializeGeoprocessor,
u'forcePythonInstantiation',
typeMetadata=BooleanTypeMetadata(),
description=_(
u"""If True, the geoprocessor will be instantiated by calling the
create function in the arcgisscripting Python module, regardless of
which version of ArcGIS is installed."""))
# Public method: GeoprocessorManager.RefreshCatalog
AddMethodMetadata(GeoprocessorManager.RefreshCatalog,
shortDescription=_(u'Refreshes the ArcGIS catalog\'s cached view of the
specified directory.'),
longDescription=_(
u"""The ArcGIS geoprocessing system interacts with the file system through the
ArcGIS catalog, a cached view of the files and directories on the computer. It
is important that the catalog be "refreshed" after any changes are made to
files
or directories. Otherwise the ArcGIS geoprocessor will not know about the
changes and operate off an obsolete view of the file system, ultimately
causing
subsequent geoprocessing operations to fail.
Most GeoEco methods automatically refresh the ArcGIS catalog when it is
necessary to do so. Some methods allow you to explictly control whether the
refresh occurs. In general, you should always allow the catalog to be
refreshed.
The main scenario in which it is appropriate to prevent it is when you are
making many consecutive changes inside a directory and do not want to incur
the
performance hit of refreshing the catalog after each change. In that scenario,
you can use this method to refresh the catalog's view of that directory when
you
are done.
If the GeoprocessorManager class is not holding an instance of the ArcGIS
geoprocessor, then this parameter is ignored. It will be holding one under the
following circumstances:
* Your code invokes a method of some class that has a dependency on ArcGIS and
internally uses the geoprocessor to do whatever work it needs to do. In
this,
scenario, that method will cause
GeoprocessorManager.InitializeGeoprocessor() to
be called. This is the most common scenario.
* Your code explicitly initializes the geoprocessor by calling
GeoprocessorManager.InitializeGeoprocessor().
* Your code provides the GeoprocessorManager with a geoprocessor instance by
calling GeoprocessorManager.SetGeoprocessor()."""),
isExposedToPythonCallers=True,
isExposedByCOM=True)
AddArgumentMetadata(GeoprocessorManager.RefreshCatalog, u'cls',
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=GeoprocessorManager),
description=_(u'%s class or an instance of it.') %
GeoprocessorManager.__name__)
AddArgumentMetadata(GeoprocessorManager.RefreshCatalog, u'directory',
typeMetadata=DirectoryTypeMetadata(mustExist=True),
description=_(
u"""Parent directory of the files or directories that have changed. For
example,
if you added three files to C:\\Data, you should pass C:\\Data as this
parameter. If you just created C:\\Data, then you need to pass C:\\ for this
parameter."""))
# Public method: GeoprocessorManager.ArcGISObjectExists
AddMethodMetadata(GeoprocessorManager.ArcGISObjectExists,
shortDescription=_(u'Tests that a given path to an ArcGIS object exists
and that the object is of a given type.'),
longDescription=_(
u"""This method uses the ArcGIS geoprocessor's Exists and Describe
functions to check the existence and type of the object."""),
isExposedToPythonCallers=True,
isExposedByCOM=True)
AddArgumentMetadata(GeoprocessorManager.ArcGISObjectExists, u'cls',
typeMetadata=ClassOrClassInstanceTypeMetadata(cls=GeoprocessorManager),
description=_(u'%s class or an instance of it.') %
GeoprocessorManager.__name__)
AddArgumentMetadata(GeoprocessorManager.ArcGISObjectExists, u'path',
typeMetadata=UnicodeStringTypeMetadata(),
description=_(u'Path to the object (e.g. a file, directory, raster,
shapefile, table, etc.).'))
AddArgumentMetadata(GeoprocessorManager.ArcGISObjectExists, u'correctTypes',
typeMetadata=ListTypeMetadata(elementType=UnicodeStringTypeMetadata()),
description=_(
u"""List of data types that the object is expected to be, chosen from
the possible values of the DataType property of the object returned by
the geoprocessor's Describe function. Please see the ArcGIS
geoprocessing documentation for the possible data type strings."""))
AddArgumentMetadata(GeoprocessorManager.ArcGISObjectExists,
u'typeDisplayName',
typeMetadata=UnicodeStringTypeMetadata(),
description=_(
u"""Name of the expected data type of the object to display in logging
messages. This is usually a more generic name than the entries that
appear in correctTypes. For example, if the object is expected to be
some kind of table, correctTypes may contain five or ten possible
values, while typeDisplayName might simply be "table"."""))
AddResultMetadata(GeoprocessorManager.ArcGISObjectExists, u'exists',
typeMetadata=BooleanTypeMetadata(),
description=_(u'True if the geoprocessor\'s Exists function reports that
the specified path exists.'))
AddResultMetadata(GeoprocessorManager.ArcGISObjectExists, u'isCorrectType',
typeMetadata=BooleanTypeMetadata(),
description=_(u'True if the geoprocessor\'s Describe function reports
that the specified path is one of the types of objects specified by
correctTypes.'))
# Public method: GeoprocessorManager.DeleteArcGISObject
AddMethodMetadata(GeoprocessorManager.DeleteArcGISObject,
shortDescription=_(u'Deletes the specified ArcGIS object, if it exists.'),
longDescription=_(
u"""If the object does not exist, no error will be raised. If the
object exists but the geoprocessor's Describe function reports that it
is not one of the types specified by the correctTypes parameter, a
ValueError will be raised. If it exists and is one of the correct
types, it will be deleted with the geoprocessor's Delete_management
function."""),
isExposedToPythonCallers=True,
isExposedByCOM=True)
CopyArgumentMetadata(GeoprocessorManager.ArcGISObjectExists, u'cls',
GeoprocessorManager.DeleteArcGISObject, u'cls')
CopyArgumentMetadata(GeoprocessorManager.ArcGISObjectExists, u'path',
GeoprocessorManager.DeleteArcGISObject, u'path')
CopyArgumentMetadata(GeoprocessorManager.ArcGISObjectExists, u'correctTypes',
GeoprocessorManager.DeleteArcGISObject, u'correctTypes')
CopyArgumentMetadata(GeoprocessorManager.ArcGISObjectExists,
u'typeDisplayName', GeoprocessorManager.DeleteArcGISObject,
u'typeDisplayName')
# Public method: GeoprocessorManager.CopyArcGISObject
AddMethodMetadata(GeoprocessorManager.CopyArcGISObject,
shortDescription=_(u'Copies the specified ArcGIS object.'),
longDescription=_(
u"""A ValueError will be raised if the source object does not exist or
the geoprocessor's Describe function reports that it is not one of the
types specified by the correctTypes parameter. A ValueError will also
be raised if the destination object exists but overwriteExisting is
False or if the object is not one of the correct types. If the
destination object exists and is a correct type, it will be deleted
with the geoprocessor's Delete_management function prior to making the
copy. The source object will be copied with the geoprocessor's
CopyFeatures_management (if the source object is a feature class,
shapefile, or feature layer) or the Copy_management function (if the
source object is some other type)."""),
isExposedToPythonCallers=True,
isExposedByCOM=True)
CopyArgumentMetadata(GeoprocessorManager.ArcGISObjectExists, u'cls',
GeoprocessorManager.CopyArcGISObject, u'cls')
AddArgumentMetadata(GeoprocessorManager.CopyArcGISObject, u'source',
typeMetadata=UnicodeStringTypeMetadata(),
description=_(u'Path to the object to copy (e.g. a file, directory,
raster, shapefile, table, etc.).'))
AddArgumentMetadata(GeoprocessorManager.CopyArcGISObject, u'destination',
typeMetadata=UnicodeStringTypeMetadata(),
description=_(u'Path to the copy to create.'))
AddArgumentMetadata(GeoprocessorManager.CopyArcGISObject,
u'overwriteExisting',
typeMetadata=BooleanTypeMetadata(),
description=_(u'If True, the destination object will be overwritten.'))
CopyArgumentMetadata(GeoprocessorManager.ArcGISObjectExists, u'correctTypes',
GeoprocessorManager.CopyArcGISObject, u'correctTypes')
CopyArgumentMetadata(GeoprocessorManager.ArcGISObjectExists,
u'typeDisplayName', GeoprocessorManager.CopyArcGISObject, u'typeDisplayName')
# Public method: GeoprocessorManager.MoveArcGISObject
AddMethodMetadata(GeoprocessorManager.MoveArcGISObject,
shortDescription=_(u'Movies the specified ArcGIS object.'),
longDescription=_(
u"""A ValueError will be raised if the source object does not exist or
the geoprocessor's Describe function reports that it is not one of the
types specified by the correctTypes parameter. A ValueError will also
be raised if the destination object exists but overwriteExisting is
False or if the object is not one of the correct types. If the
destination object exists and is a correct type, it will be deleted
with the geoprocessor's Delete_management function prior to making the
copy. The source object will be copied with the geoprocessor's
CopyFeatures_management (if the source object is a feature class,
shapefile, or feature layer) or the Copy_management function (if the
source object is some other type), and then deleted with the
Delete_management function."""),
isExposedToPythonCallers=True,
isExposedByCOM=True)
CopyArgumentMetadata(GeoprocessorManager.ArcGISObjectExists, u'cls',
GeoprocessorManager.MoveArcGISObject, u'cls')
AddArgumentMetadata(GeoprocessorManager.MoveArcGISObject, u'source',
typeMetadata=UnicodeStringTypeMetadata(),
description=_(u'Path to the object to move (e.g. a file, directory,
raster, shapefile, table, etc.).'))
AddArgumentMetadata(GeoprocessorManager.MoveArcGISObject, u'destination',
typeMetadata=UnicodeStringTypeMetadata(),
description=_(u'New path for the object.'))
CopyArgumentMetadata(GeoprocessorManager.CopyArcGISObject,
u'overwriteExisting', GeoprocessorManager.MoveArcGISObject,
u'overwriteExisting')
CopyArgumentMetadata(GeoprocessorManager.ArcGISObjectExists, u'correctTypes',
GeoprocessorManager.MoveArcGISObject, u'correctTypes')
CopyArgumentMetadata(GeoprocessorManager.ArcGISObjectExists,
u'typeDisplayName', GeoprocessorManager.MoveArcGISObject, u'typeDisplayName')
# Public method: GeoprocessorManager.GetUniqueLayerName
AddMethodMetadata(GeoprocessorManager.GetUniqueLayerName,
shortDescription=_(u'Returns a randomly generated string that may be used
as the name of a new geoprocessing layer.'),
longDescription=_(
u"""This function loops through random names until it finds one for
which the geoprocessors Exists function returns False."""),
isExposedToPythonCallers=True,
isExposedByCOM=True)
CopyArgumentMetadata(GeoprocessorManager.ArcGISObjectExists, u'cls',
GeoprocessorManager.GetUniqueLayerName, u'cls')
AddResultMetadata(GeoprocessorManager.GetUniqueLayerName, u'name',
typeMetadata=UnicodeStringTypeMetadata(),
description=_(u'Randomly generated string that may be used as the name of
a geoprocessing layer.'))
###############################################################################
# Names exported by this module
###############################################################################
__all__ = ['GeoprocessorManager',
'ArcGISDependency',
'ArcGISProductDependency',
'ArcGISExtensionDependency',
'ArcGISError',
'ValidateMethodMetadataForExposureAsArcGISTool']
Archives powered by MHonArc.