Skip to Content.

mget-help - RE: [mget-help] Issue with the "Create Lines from Vector Component Rasters" tool in ArcGIS 10.2

Please Wait...

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']
Archives powered by MHonArc.
Top of Page