Skip to Content.

mget-help - RE: ArcGISRasterSamplerSampleRasters

Please Wait...

Subject: Marine Geospatial Ecology Tools (MGET) help

Text archives


From: "Jason Roberts" <>
To: <>, <>
Subject: RE: ArcGISRasterSamplerSampleRasters
Date: Thu, 11 Dec 2008 21:41:03 -0500
Hi Joe,

Thanks for your interest in MGET. I'm sorry the sampling tool is not working 
for you. The short answer is that the tool does not currently support 
sampling raster bands, only rasters or raster layers. But I have a solution 
for you.

First, here is some code that demonstrates how to sample rasters that do not 
have bands from a traditional Python geoprocessing script:


# Instantiate Arc 9.2 geoprocessor.

import arcgisscripting
gp = arcgisscripting.create()

# Reference MGET toolbox. Note: path may change before MGET 0.7 is
# released. See https://code.env.duke.edu/projects/mget/ticket/299

gp.AddToolbox(r'C:\Python24\Lib\site-packages\GeoEco\ArcGISToolbox\Marine 
Geospatial Ecology Tools.tbx')

# A simple sampling example for two fields:

points = r'C:\HabModExample2\Geodatabase.mdb\PointsToSample'
rasters = r'C:\HabModExample2\OceanographyRasters\Chl\Monthly\chl199908;' + \
          r'C:\HabModExample2\OceanographyRasters\SST\Monthly\sst\sst199908'
fields = 'Chlorophyll;SST'

gp.ArcGISRasterSamplerSampleRasters_GeoEco(points, rasters, fields)

# Since we are sampling Chl and SST for August 1998, we can restrict
# the sampler to just do the points that have that date. Since we're
# querying an MS Access database, we can use VBScript DatePart
# function. This is not very efficient, but will work.

where = 'DatePart("m", [obs_date]) = 8'

gp.ArcGISRasterSamplerSampleRasters_GeoEco(points, rasters, fields, where)

# If the destination field has the an integer data type (i.e. SHORT or
# LONG), we must explicitly cast the sampled values to integers. This
# is because the MGET tool always gets floats back from ArcGIS, even
# when sampling integer rasters. A future version of the MGET tool
# will do this automatically, or call ArcGIS in a different way, so
# this is not required. Sorry for the inconvenience.

fields = 'Bathymetry'
rasters = r'C:\HabModExample2\OceanographyRasters\Bathymetry\etopo2v2'
expressions = 'int(value)'      # etopo2v2 is depth as integer

gp.ArcGISRasterSamplerSampleRasters_GeoEco(points, rasters, fields, where, 
'#', '#', expressions)


I saved that script to C:\SampTest\SampTest.py. It uses points and rasters 
from the HabModExample2 habitat modeling example on the MGET web site. I ran 
it on an Arc 9.2 SP6 machine and got the following output. You'll see the 
output if you run it from a CMD shell, but if you run it from a Python 
debugger (e.g. PythonWin) I don’t think you'll see it because those debuggers 
do not traditionally capture messages written to the stdout stream.


C:\SampTest>SampTest.py
2008-12-11 21:03:29,246 INFO Sampling rasters: 
points=C:\HabModExample2\Geodatabase.mdb\PointsToSample, 
rasters=[u'C:\\HabModExample2\\OceanographyRasters\\Chl\\Monthly\\chl199908', 
u'C:\\HabModExample2\\OceanographyRasters\\SST\\Monthly\\sst\\sst199908'], 
fields=[u'Chlorophyll', u'SST']...
2008-12-11 21:03:47,763 INFO Sampled 2 rasters at 600 points.
2008-12-11 21:04:06,226 INFO Sampling rasters: 
points=C:\HabModExample2\Geodatabase.mdb\PointsToSample, 
rasters=[u'C:\\HabModExample2\\OceanographyRasters\\Chl\\Monthly\\chl199908', 
u'C:\\HabModExample2\\OceanographyRasters\\SST\\Monthly\\sst\\sst199908'], 
fields=[u'Chlorophyll', u'SST'], where=DatePart("m", [obs_date]) = 8...
2008-12-11 21:04:23,822 INFO Sampled 2 rasters at 328 points.
2008-12-11 21:04:40,775 INFO Sampling rasters: 
points=C:\HabModExample2\Geodatabase.mdb\PointsToSample, 
rasters=[u'C:\\HabModExample2\\OceanographyRasters\\Bathymetry\\etopo2v2'], 
fields=[u'Bathymetry'], where=DatePart("m", [obs_date]) = 8...
2008-12-11 21:04:58,901 INFO Sampled 1 rasters at 328 points.


Here is what code for sampling bands should look like:


# Create a raster with two bands so we can test band sampling.

bands = r'C:\HabModExample2\OceanographyRasters\Chl\Monthly\chl199908;' + \
        r'C:\HabModExample2\OceanographyRasters\SST\Monthly\sst\sst199908'

gp.OverwriteOutput = True
gp.CompositeBands_management(bands, r'C:\SampTest\multiband.img')

# Sample the bands.

rasters = r'C:\SampTest\multiband.img\Band_1;' + \
          r'C:\SampTest\multiband.img\Band_2'
fields = 'Chlorophyll;SST'

gp.ArcGISRasterSamplerSampleRasters_GeoEco(points, rasters, fields)


But the tool fails with this message:


C:\SampTest>SampTest.py
2008-12-11 21:13:36,144 ERROR ValueError: The value specified for the element 
0 of the rasters parameter (where 0 is the first element), 
C:\SampTest\multiband.img\Band_1, exists but it is not a raster or raster 
layer. Please specify a raster or raster layer.
Traceback (most recent call last):
  File "C:\SampTest\SampTest.py", line 56, in ?
    gp.ArcGISRasterSamplerSampleRasters_GeoEco(points, rasters, fields)
RuntimeError:
ValueError: The value specified for the element 0 of the rasters parameter 
(where 0 is the first element), C:\SampTest\multiband.img\Band_1, exists but 
it is not a raster or raster layer. Please specify a raster or raster layer.
Error in script ArcGISRasterSamplerSampleRasters.
Error in executing: cmd.exe /C 
C:\Python24\Lib\SITE-P~1\GeoEco\ARCGIS~1\Scripts\AR87D7~1.PY  
"C:\HabModExample2\Geodatabase.mdb\PointsToSample" 
"C:\SampTest\multiband.img\Band_1;C:\SampTest\multiband.img\Band_2" 
"Chlorophyll;SST" "#" "NEAREST" "#" "#" "#" 
"C:\HabModExample2\Geodatabase.mdb\PointsToSample"

Failed to execute (ArcGISRasterSamplerSampleRasters).


If you are not seeing anything like that, then there is some other problem. 
If you're trying to run it from PythonWin, IDLE, or another editor, try it 
from a CMD shell instead. If you still don't see any messages, it probably 
means there is an installation problem. Usually it means the pywin32 Python 
package is not installed. You could check for that (see MGET's Installation 
Instructions).

Now, assuming you can reproduce an error that looks like the above (i.e. 
"ValueError: The value specified ... exists but it is not a raster or raster 
layer.") you can fix it by overwriting your file 
C:\Python24\Lib\site-packages\GeoEco\Types.py with the one attached to this 
message. This contains a one line fix that enables the tool to sample bands. 
My apologies for the bug. You should then get this output:


C:\SampTest>SampTest.py
2008-12-11 21:18:13,516 INFO Sampling rasters: 
points=C:\HabModExample2\Geodatabase.mdb\PointsToSample, 
rasters=[u'C:\\SampTest\\multiband.img\\Band_1', 
u'C:\\SampTest\\multiband.img\\Band_2'], fields=[u'Chlorophyll', u'SST']...
2008-12-11 21:18:35,184 INFO Sampled 2 rasters at 600 points.


Hope that helps. Let me know if it does not...

Jason


-----Original Message-----
From: 

 
[mailto:]
 
Sent: Thursday, December 11, 2008 7:55 PM
To: 

Subject: ArcGISRasterSamplerSampleRasters

Hi MGET-ers.
I'm new to the list and new to the GeoEco toolbox, so here goes...

I'm trying to sample all the rasters (including multiple raster bands) in a
directory using the ArcGISRasterSamplerSampleRasters tool. All the rasters are
Erdas IMAGEs (.img), 7 are single-band, 3 are 3-band, and 3 are 6-band images,
for a total of 34 fields being added to my point shapefile. 

I originally downloaded the toolbox because I had previously tried Python to
use the "Sample" command and also to loop through "Extract Values to Points",
but ran into errors in both. (The former would not allow that many rasters to
be sampled, and the latter just failed at various places, giving the "ERROR
99999: unknown error" message.)

So, can the ArcGISRasterSamplerSampleRasters tool sample all bands of
multi-band rasters, or do I need to copy each band as a single-band raster? 
I'm
running the tool unsuccessfully in a Python script now, but I get no error
messages when it fails, so I'm guessing that this is the problem. Here's the
pseudocode of what I'm doing:

rasters = 'raster1.img;raster2.img\Band_1;raster2.img\Band_2...'
fields = 'raster1;raster2_1;raster2_2...'
gp.ArcGISRasterSamplerSampleRasters(shapefile, rasters, fields)  

Thanks,
Joe
# Types.py - Provides classes derived from GeoEco.Metadata.TypeMetadata that
# represent data types of properties and method arguments and return values 
for
# classes in the GeoEco Python 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 operator
import os.path
import re
import sys
import time
import types
import xml.dom

from GeoEco.DynamicDocString import DynamicDocString
from GeoEco.Internationalization import _
from GeoEco.Metadata import Metadata, TypeMetadata


# Private helper function for raising exceptions

def _RaiseException(e):
    from GeoEco.Logging import Logger
    Logger.RaiseException(e)


# Types representing Python class instances or classes


class AnyObjectTypeMetadata(TypeMetadata):

    def __init__(self, canBeNone=False):
        super(AnyObjectTypeMetadata, 
self).__init__(pythonType=types.ObjectType,
                                                    canBeNone=canBeNone,
                                                    comIDLType=u'VARIANT',
                                                    canBeCOMParameter=True,
                                                    
arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPTypeClass',
                                                    
arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing',
                                                    
canBeArcGISInputParameter=True,
                                                    
canBeArcGISOutputParameter=True)


class NoneTypeMetadata(TypeMetadata):

    def __init__(self):
        super(NoneTypeMetadata, self).__init__(pythonType=types.NoneType, 
canBeNone=True)

    def ValidateValue(self, value, variableName, methodLocals=None, 
argMetadata=None):
        if value is not None:
            _RaiseException(TypeError(_(u'The %s must be None (also called 
null or empty in languages other than Python).') % variableName))
        return (False, value)


class ClassTypeMetadata(TypeMetadata):

    def __init__(self, cls, canBeNone=False):
        assert inspect.isclass(cls), u'cls must be a class'
        super(ClassTypeMetadata, self).__init__(pythonType=cls, 
canBeNone=canBeNone)

    def ValidateValue(self, value, variableName, methodLocals=None, 
argMetadata=None):
        if value is None:
            if not self.CanBeNone:
                _RaiseException(TypeError(_(u'The %s is required. Please 
provide a value.') % variableName))
        elif not issubclass(value, self.PythonType):
            _RaiseException(TypeError(_(u'The value provided for the 
%(variable)s is invalid because it is a %(type)s, an invalid type. Please 
provide the class %(class)s or a subclass.') % {u'variable' : variableName, 
u'type' : type(value).__name__, u'class' : self.PythonType.__name__}))
        return (False, value)


class ClassInstanceTypeMetadata(TypeMetadata):

    def __init__(self, cls, canBeNone=False):
        assert inspect.isclass(cls), u'cls must be a class'
        super(ClassInstanceTypeMetadata, self).__init__(pythonType=cls, 
canBeNone=canBeNone)


class ClassOrClassInstanceTypeMetadata(TypeMetadata):

    def __init__(self, cls, canBeNone=False):
        assert inspect.isclass(cls), u'cls must be a class'
        super(ClassOrClassInstanceTypeMetadata, 
self).__init__(pythonType=cls, canBeNone=canBeNone)

    def ValidateValue(self, value, variableName, methodLocals=None, 
argMetadata=None):
        if value is None:
            if not self.CanBeNone:
                _RaiseException(TypeError(_(u'The %s is required. Please 
provide a value.') % variableName))
        elif not (inspect.isclass(value) and issubclass(value, 
self.PythonType)) and not isinstance(value, self.PythonType):
            _RaiseException(TypeError(_(u'The value provided for the 
%(variable)s is invalid because it is a %(type)s, an invalid type. Please 
provide the class %(class)s, a subclass, or an instance of it or a 
subclass.') % {u'variable' : variableName, u'type' : type(value).__name__, 
u'class' : self.PythonType.__name__}))
        return (False, value)


# Simple Python types from which many other types derive


class BooleanTypeMetadata(TypeMetadata):

    def __init__(self,
                 canBeNone=False,
                 allowedValues=None):
        
        super(BooleanTypeMetadata, 
self).__init__(pythonType=types.BooleanType,
                                                  canBeNone=canBeNone,
                                                  allowedValues=allowedValues,
                                                  comIDLType=u'VARIANT_BOOL',
                                                  canBeCOMParameter=True,
                                                  
arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPBooleanTypeClass',
                                                  
arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing',
                                                  
canBeArcGISInputParameter=True,
                                                  
canBeArcGISOutputParameter=True)

    def AppendXMLNodesForValue(self, value, node, document):
        assert isinstance(value, self.PythonType), u'value must be an 
instance of %s' % self.PythonType.__name__
        assert isinstance(node, xml.dom.Node) and node.nodeType == 
xml.dom.Node.ELEMENT_NODE, u'node must be an instance of xml.dom.Node with 
nodeType==ELEMENT_NODE'
        assert isinstance(document, xml.dom.Node) and document.nodeType == 
xml.dom.Node.DOCUMENT_NODE, u'node must be an instance of xml.dom.Node with 
nodeType==DOCUMENT_NODE'
        
node.appendChild(document.createElement(u'boolean')).appendChild(document.createTextNode(unicode(value).lower()))

    def COMIDLRepresentationOfValue(self, value):
        assert isinstance(value, types.BooleanType), u'value must be a 
boolean'
        if value:
            return '-1'     # VARIANT_TRUE
        return '0'          # VARIANT_FALSE

    def ParseValueFromArcGISInputParameterString(self, paramString, 
paramDisplayName, paramIndex):
        s = super(BooleanTypeMetadata, 
self).ParseValueFromArcGISInputParameterString(paramString, paramDisplayName, 
paramIndex).strip().lower()
        if s == u'true':
            return True
        if s == u'false':
            return False
        _RaiseException(ValueError(_(u'Failed to parse a boolean from the 
string "%(string)s" provided for the %(paramName)s parameter (parameter 
number %(paramIndex)i). Please provide either "True" or "False".') % 
{u'string' : s, u'paramName' : paramDisplayName, u'paramIndex' : paramIndex}))


class DateTimeTypeMetadata(TypeMetadata):

    def __init__(self,
                 minValue=None,
                 maxValue=None,
                 canBeNone=False,
                 allowedValues=None):
        
        assert isinstance(minValue, (datetime.datetime, types.NoneType)), 
u'minValue must be a datetime.datetime, or None'
        assert isinstance(maxValue, (datetime.datetime, types.NoneType)), 
u'maxValue must be a datetime.datetime, or None'
        assert minValue is None or maxValue is None or minValue <= maxValue, 
u'minValue must be less than or equal to maxValue'
        super(DateTimeTypeMetadata, 
self).__init__(pythonType=datetime.datetime,
                                                   canBeNone=canBeNone,
                                                   
allowedValues=allowedValues,
                                                   comIDLType=u'DATE',
                                                   canBeCOMParameter=True,
                                                   
arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPDateTypeClass',
                                                   
arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing',
                                                   
canBeArcGISInputParameter=True,
                                                   
canBeArcGISOutputParameter=True)
        self._MinValue = minValue
        self._MaxValue = maxValue

    def _GetMinValue(self):
        return self._MinValue
    
    MinValue = property(_GetMinValue, doc=DynamicDocString())

    def _GetMaxValue(self):
        return self._MaxValue
    
    MaxValue = property(_GetMaxValue, doc=DynamicDocString())

    def AppendXMLNodes(self, node, document):
        super(DateTimeTypeMetadata, self).AppendXMLNodes(node, document)
        #Metadata.AppendPropertyXMLNode(self, u'MinValue', node, document)
        #Metadata.AppendPropertyXMLNode(self, u'MaxValue', node, document)

    def AppendXMLNodesForValue(self, value, node, document):
        _RaiseException(NotImplementedError(_(u'Properties or method 
parameters of type DateTimeTypeMetadata cannot currently have default 
values.')))

    def ValidateValue(self, value, variableName, methodLocals=None, 
argMetadata=None):
        valueChanged = False
        if value is not None and not isinstance(value, datetime.datetime):
            try:
                import pythoncom
            except:
                pass
            else:
                if isinstance(value, pythoncom.PyTimeType):
                    value = datetime.datetime(value.year, value.month, 
value.day, value.hour, value.minute, value.second, value.msec)
                    valueChanged = True
        (valueChanged2, value) = super(DateTimeTypeMetadata, 
self).ValidateValue(value, variableName, methodLocals, argMetadata)
        if value is not None:
            if self.MinValue is not None and value < self.MinValue:
                _RaiseException(ValueError(_(u'The value %(value)s provided 
for the %(variable)s is less than the minimum allowed value %(minValue)s.') % 
{u'value' : unicode(value), u'variable' : variableName, u'minValue' : 
unicode(self.MinValue)}))
            if self.MaxValue is not None and value > self.MaxValue:
                _RaiseException(ValueError(_(u'The value %(value)s provided 
for the %(variable)s is greater than the maximum allowed value 
%(maxValue)s.') % {u'value' : unicode(value), u'variable' : variableName, 
u'maxValue' : unicode(self.MaxValue)}))
        return (valueChanged or valueChanged2, value)

    def COMIDLRepresentationOfValue(self, value):
        _RaiseException(NotImplementedError(_(u'Properties or method 
parameters of type DateTimeTypeMetadata cannot currently have default 
values.')))

    def ParseValueFromArcGISInputParameterString(self, paramString, 
paramDisplayName, paramIndex):
        s = super(DateTimeTypeMetadata, 
self).ParseValueFromArcGISInputParameterString(paramString, paramDisplayName, 
paramIndex).strip().lower()

        # Sadly, it appears that ArcGIS passes datetimes in the 
locale-specific
        # format. I verified this on Windows by switching the Regional and
        # Language Options from English (United States) to German (Germany) 
and
        # observing the datetime string being passed in a different format.
        #
        # This means we have to try to parse the string in the locale-specific
        # format. Sadly Python does not give us much help here. The
        # time.strptime function does have some support for parsing
        # locale-specific formats (%x and %X) but it does not seem to work on
        # Windows (ArcGIS passes dates as mm/dd/YYYY but the function expects
        # mm/dd/yy). As a result, we have to exhaustively try to parse 
different
        # formats. This is really annoying. We could take a dependency on
        # mxDateTime but their licensing model is not compatible with ours, 
and
        # it would be a shame to take the dependency just to parse a datetime.

        t = self.ParseDatetimeFromString(s)

        if t is None:
            _RaiseException(ValueError(_(u'Failed to parse a date/time value 
from the string "%(string)s" provided for the %(paramName)s parameter 
(parameter number %(paramIndex)i). Please provide a value in a supported 
date/time format. If you provide a date but omit the time, midnight is 
assumed. You may not provide a time without a date.') % {u'string' : s, 
u'paramName' : paramDisplayName, u'paramIndex' : paramIndex}))

        return t

    @classmethod
    def ParseDatetimeFromString(cls, s):

        # Order the parsing formats that we will attempt according to whether
        # the year, month, or day comes first in the current locale-specific
        # date format.

        yearFirstFormats = ['%Y/%m/%d',
                            '%Y-%m-%d',
                            '%Y-.%m-.%d',
                            '%y/%m/%d',
                            '%y-%m-%d',
                            '%y-.%m-.%d',
                            '%Y/%m/%d %I:%M:%S %p',
                            '%Y-%m-%d %I:%M:%S %p',
                            '%Y.%m.%d %I:%M:%S %p',
                            '%y/%m/%d %I:%M:%S %p',
                            '%y-%m-%d %I:%M:%S %p',
                            '%y.%m.%d %I:%M:%S %p',
                            '%Y/%m/%d %H:%M:%S',
                            '%Y-%m-%d %H:%M:%S',
                            '%Y.%m.%d %H:%M:%S',
                            '%y/%m/%d %H:%M:%S',
                            '%y-%m-%d %H:%M:%S',
                            '%y.%m.%d %H:%M:%S']

        dayFirstFormats = ['%d/%m/%Y',
                           '%d-%m-%Y',
                           '%d.%m.%Y',
                           '%d/%m/%y',
                           '%d-%m-%y',
                           '%d.%m.%y',
                           '%d/%m/%Y %I:%M:%S %p',
                           '%d-%m-%Y %I:%M:%S %p',
                           '%d.%m.%Y %I:%M:%S %p',
                           '%d/%m/%y %I:%M:%S %p',
                           '%d-%m-%y %I:%M:%S %p',
                           '%d.%m.%y %I:%M:%S %p',
                           '%d/%m/%Y %H:%M:%S',
                           '%d-%m-%Y %H:%M:%S',
                           '%d.%m.%Y %H:%M:%S',
                           '%d/%m/%y %H:%M:%S',
                           '%d-%m-%y %H:%M:%S',
                           '%d.%m.%y %H:%M:%S']

        monthFirstFormats = ['%m/%d/%Y',
                             '%m-%d-%Y',
                             '%m.%d.%Y',
                             '%m/%d/%y',
                             '%m-%d-%y',
                             '%m.%d.%y',
                             '%m/%d/%Y %I:%M:%S %p',
                             '%m-%d-%Y %I:%M:%S %p',
                             '%m.%d.%Y %I:%M:%S %p',
                             '%m/%d/%y %I:%M:%S %p',
                             '%m-%d-%y %I:%M:%S %p',
                             '%m.%d.%y %I:%M:%S %p',
                             '%m/%d/%Y %H:%M:%S',
                             '%m-%d-%Y %H:%M:%S',
                             '%m.%d.%Y %H:%M:%S',
                             '%m/%d/%y %H:%M:%S',
                             '%m-%d-%y %H:%M:%S',
                             '%m.%d.%y %H:%M:%S']

        otherFormats = ['%Y.%m.%d.',
                        '%Y.%m.%d. %H:%M:%S',
                        '%Y-%m-%d %I:%M:%S.%p',
                        '%d/%m %Y',
                        '%d/%m %Y %H:%M:%S']

        localeTimeStr = time.strftime('%x', (2007, 12, 31, 0, 0, 0, 0, 365, 
-1))
        if localeTimeStr.startswith('2007') or localeTimeStr.startswith('07') 
or localeTimeStr.startswith('7'):
            formats = yearFirstFormats + dayFirstFormats + monthFirstFormats 
+ otherFormats
        elif localeTimeStr.startswith('31'):
            formats = dayFirstFormats + monthFirstFormats + yearFirstFormats 
+ otherFormats
        else:
            formats = monthFirstFormats + yearFirstFormats + dayFirstFormats 
+ otherFormats

        # Parse the string using the list of formats.

        t = None
        for f in formats:
            try:
                t = time.strptime(s, f)
            except:
                pass
            else:
                break

        if t is not None:
            return datetime.datetime(*t[0:6])
        
        return None


class FloatTypeMetadata(TypeMetadata):

    def __init__(self,
                 minValue=None,
                 maxValue=None,
                 canBeNone=False,
                 allowedValues=None):
        
        assert isinstance(minValue, (types.FloatType, types.NoneType)), 
u'minValue must be a float, or None'
        assert isinstance(maxValue, (types.FloatType, types.NoneType)), 
u'maxValue must be a float, or None'
        assert minValue is None or maxValue is None or minValue <= maxValue, 
u'minValue must be less than or equal to maxValue'
        super(FloatTypeMetadata, self).__init__(pythonType=types.FloatType,
                                                canBeNone=canBeNone,
                                                allowedValues=allowedValues,
                                                comIDLType=u'double',
                                                canBeCOMParameter=True,
                                                
arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPDoubleTypeClass',
                                                
arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing',
                                                
canBeArcGISInputParameter=True,
                                                
canBeArcGISOutputParameter=True)
        self._MinValue = minValue
        self._MaxValue = maxValue

    def _GetMinValue(self):
        return self._MinValue
    
    MinValue = property(_GetMinValue, doc=DynamicDocString())

    def _GetMaxValue(self):
        return self._MaxValue
    
    MaxValue = property(_GetMaxValue, doc=DynamicDocString())

    def AppendXMLNodes(self, node, document):
        super(FloatTypeMetadata, self).AppendXMLNodes(node, document)
        Metadata.AppendPropertyXMLNode(self, u'MinValue', node, document)
        Metadata.AppendPropertyXMLNode(self, u'MaxValue', node, document)

    def AppendXMLNodesForValue(self, value, node, document):
        assert isinstance(value, self.PythonType), u'value must be an 
instance of %s' % self.PythonType.__name__
        assert isinstance(node, xml.dom.Node) and node.nodeType == 
xml.dom.Node.ELEMENT_NODE, u'node must be an instance of xml.dom.Node with 
nodeType==ELEMENT_NODE'
        assert isinstance(document, xml.dom.Node) and document.nodeType == 
xml.dom.Node.DOCUMENT_NODE, u'node must be an instance of xml.dom.Node with 
nodeType==DOCUMENT_NODE'
        
node.appendChild(document.createElement(u'double')).appendChild(document.createTextNode(unicode(value)))

    def ValidateValue(self, value, variableName, methodLocals=None, 
argMetadata=None):
        valueChanged = False
        if isinstance(value, types.IntType):
            value = float(value)
            valueChanged = True
        (valueChanged2, value) = super(FloatTypeMetadata, 
self).ValidateValue(value, variableName, methodLocals, argMetadata)
        if value is not None:
            if self.MinValue is not None and value < self.MinValue:
                _RaiseException(ValueError(_(u'The value %(value)G provided 
for the %(variable)s is less than the minimum allowed value %(minValue)G.') % 
{u'value' : value, u'variable' : variableName, u'minValue' : self.MinValue}))
            if self.MaxValue is not None and value > self.MaxValue:
                _RaiseException(ValueError(_(u'The value %(value)G provided 
for the %(variable)s is greater than the maximum allowed value 
%(maxValue)G.') % {u'value' : value, u'variable' : variableName, u'maxValue' 
: self.MaxValue}))
        return (valueChanged or valueChanged2, value)
    
    def COMIDLRepresentationOfValue(self, value):
        assert isinstance(value, types.FloatType), u'value must be a float'
        return str(value)

    def ParseValueFromArcGISInputParameterString(self, paramString, 
paramDisplayName, paramIndex):
        s = super(FloatTypeMetadata, 
self).ParseValueFromArcGISInputParameterString(paramString, paramDisplayName, 
paramIndex).strip()
        try:
            value = float(s)
        except Exception, e:
            _RaiseException(ValueError(_(u'Failed to parse a floating-point 
number from the string "%(string)s" provided for the %(paramName)s parameter 
(parameter number %(paramIndex)i). Please provide a string with valid 
formatting. The Python float function reported: %(msg)s') % {u'string' : s, 
u'paramName' : paramDisplayName, u'paramIndex' : paramIndex, u'msg' : 
unicode(e)}))
        return value


class IntegerTypeMetadata(TypeMetadata):

    def __init__(self,
                 minValue=None,
                 maxValue=None,
                 canBeNone=False,
                 allowedValues=None):
        
        assert isinstance(minValue, (types.IntType, types.NoneType)), 
u'minValue must be an integer, or None'
        assert isinstance(maxValue, (types.IntType, types.NoneType)), 
u'maxValue must be an integer, or None'
        assert minValue is None or maxValue is None or minValue <= maxValue, 
u'minValue must be less than or equal to maxValue'
        super(IntegerTypeMetadata, self).__init__(pythonType=types.IntType,
                                                  canBeNone=canBeNone,
                                                  allowedValues=allowedValues,
                                                  comIDLType=u'long',
                                                  canBeCOMParameter=True,
                                                  
arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPLongTypeClass',
                                                  
arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing',
                                                  
canBeArcGISInputParameter=True,
                                                  
canBeArcGISOutputParameter=True)
        self._MinValue = minValue
        self._MaxValue = maxValue

    def _GetMinValue(self):
        return self._MinValue
    
    MinValue = property(_GetMinValue, doc=DynamicDocString())

    def _GetMaxValue(self):
        return self._MaxValue
    
    MaxValue = property(_GetMaxValue, doc=DynamicDocString())

    def AppendXMLNodes(self, node, document):
        super(IntegerTypeMetadata, self).AppendXMLNodes(node, document)
        Metadata.AppendPropertyXMLNode(self, u'MinValue', node, document)
        Metadata.AppendPropertyXMLNode(self, u'MaxValue', node, document)

    def AppendXMLNodesForValue(self, value, node, document):
        assert isinstance(value, self.PythonType), u'value must be an 
instance of %s' % self.PythonType.__name__
        assert isinstance(node, xml.dom.Node) and node.nodeType == 
xml.dom.Node.ELEMENT_NODE, u'node must be an instance of xml.dom.Node with 
nodeType==ELEMENT_NODE'
        assert isinstance(document, xml.dom.Node) and document.nodeType == 
xml.dom.Node.DOCUMENT_NODE, u'node must be an instance of xml.dom.Node with 
nodeType==DOCUMENT_NODE'
        
node.appendChild(document.createElement(u'int')).appendChild(document.createTextNode(unicode(value)))

    def ValidateValue(self, value, variableName, methodLocals=None, 
argMetadata=None):
        (valueChanged, value) = super(IntegerTypeMetadata, 
self).ValidateValue(value, variableName, methodLocals, argMetadata)
        if value is not None:
            if self.MinValue is not None and value < self.MinValue:
                _RaiseException(ValueError(_(u'The value %(value)i provided 
for the %(variable)s is less than the minimum allowed value %(minValue)i.') % 
{u'value' : value, u'variable' : variableName, u'minValue' : self.MinValue}))
            if self.MaxValue is not None and value > self.MaxValue:
                _RaiseException(ValueError(_(u'The value %(value)i provided 
for the %(variable)s is greater than the maximum allowed value 
%(maxValue)i.') % {u'value' : value, u'variable' : variableName, u'maxValue' 
: self.MaxValue}))
        return (valueChanged, value)

    def COMIDLRepresentationOfValue(self, value):
        assert isinstance(value, types.IntType), u'value must be an int'
        return str(value)

    def ParseValueFromArcGISInputParameterString(self, paramString, 
paramDisplayName, paramIndex):
        s = super(IntegerTypeMetadata, 
self).ParseValueFromArcGISInputParameterString(paramString, paramDisplayName, 
paramIndex).strip()
        try:
            value = int(s)
        except Exception, e:
            _RaiseException(ValueError(_(u'Failed to parse an integer from 
the string "%(string)s" provided for the %(paramName)s parameter (parameter 
number %(paramIndex)i). Please provide a string with valid formatting. The 
Python integer function reported: %(msg)s') % {u'string' : s, u'paramName' : 
paramDisplayName, u'paramIndex' : paramIndex, u'msg' : unicode(e)}))
        return value


class UnicodeStringTypeMetadata(TypeMetadata):

    def __init__(self,
                 stripWhitespace=True,
                 makeLowercase=False,
                 minLength=1,
                 maxLength=2147483647,
                 mustMatchRegEx=None,
                 canBeNone=False,
                 allowedValues=None,
                 arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPStringTypeClass',
                 arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing',
                 canBeArcGISInputParameter=True,
                 canBeArcGISOutputParameter=True):
        
        assert isinstance(stripWhitespace, types.BooleanType), 
u'stripWhitespace must be a boolean'
        assert isinstance(makeLowercase, types.BooleanType), u'makeLowercase 
must be a boolean'
        assert isinstance(minLength, types.IntType) and minLength >= 0 and 
minLength <= 2147483647, u'minLength must be an integer between 0 and 
2147483647, inclusive'
        assert isinstance(maxLength, types.IntType) and maxLength >= 0 and 
maxLength <= 2147483647, u'maxLength must be an integer between 0 and 
2147483647, inclusive'
        assert maxLength >= minLength, u'maxLength must be greater than or 
equal to minLength'
        assert isinstance(mustMatchRegEx, (types.NoneType, 
types.UnicodeType)), u'mustMatchRegEx must be a Unicode string, or None'
        super(UnicodeStringTypeMetadata, 
self).__init__(pythonType=types.UnicodeType,
                                                        canBeNone=canBeNone,
                                                        
allowedValues=allowedValues,
                                                        comIDLType=u'BSTR',
                                                        
canBeCOMParameter=True,
                                                        arcGISType=arcGISType,
                                                        
arcGISAssembly=arcGISAssembly,
                                                        
canBeArcGISInputParameter=canBeArcGISInputParameter,
                                                        
canBeArcGISOutputParameter=canBeArcGISOutputParameter)
        self._StripWhitespace = stripWhitespace
        self._MakeLowercase = makeLowercase
        self._MinLength = minLength
        self._MaxLength = maxLength
        self._MustMatchRegEx = mustMatchRegEx

    def _GetStripWhitespace(self):
        return self._StripWhitespace
    
    StripWhitespace = property(_GetStripWhitespace, doc=DynamicDocString())

    def _GetMakeLowercase(self):
        return self._MakeLowercase
    
    MakeLowercase = property(_GetMakeLowercase, doc=DynamicDocString())

    def _GetMinLength(self):
        return self._MinLength
    
    MinLength = property(_GetMinLength, doc=DynamicDocString())

    def _GetMaxLength(self):
        return self._MaxLength
    
    MaxLength = property(_GetMaxLength, doc=DynamicDocString())

    def _GetMustMatchRegEx(self):
        return self._MustMatchRegEx
    
    MustMatchRegEx = property(_GetMustMatchRegEx, doc=DynamicDocString())

    def COMIDLRepresentationOfValue(self, value):
        assert isinstance(value, types.UnicodeType), u'value must be a 
Unicode string'
        return '"' + str(value).replace('"', '\\"') + '"'

    def AppendXMLNodes(self, node, document):
        super(UnicodeStringTypeMetadata, self).AppendXMLNodes(node, document)
        Metadata.AppendPropertyXMLNode(self, u'StripWhitespace', node, 
document)
        Metadata.AppendPropertyXMLNode(self, u'MakeLowercase', node, document)
        Metadata.AppendPropertyXMLNode(self, u'MinLength', node, document)
        Metadata.AppendPropertyXMLNode(self, u'MaxLength', node, document)
        Metadata.AppendPropertyXMLNode(self, u'MustMatchRegEx', node, 
document)

    def AppendXMLNodesForValue(self, value, node, document):
        assert isinstance(value, self.PythonType), u'value must be an 
instance of %s' % self.PythonType.__name__
        assert isinstance(node, xml.dom.Node) and node.nodeType == 
xml.dom.Node.ELEMENT_NODE, u'node must be an instance of xml.dom.Node with 
nodeType==ELEMENT_NODE'
        assert isinstance(document, xml.dom.Node) and document.nodeType == 
xml.dom.Node.DOCUMENT_NODE, u'node must be an instance of xml.dom.Node with 
nodeType==DOCUMENT_NODE'
        
node.appendChild(document.createElement(u'string')).appendChild(document.createTextNode(value))

    def ValidateValue(self, value, variableName, methodLocals=None, 
argMetadata=None):
        valueChanged = False
        if isinstance(value, types.StringType):
            value = unicode(value)
            valueChanged = True
        (valueChanged2, value) = super(UnicodeStringTypeMetadata, 
self).ValidateValue(value, variableName, methodLocals, argMetadata)
        valueChanged = valueChanged or valueChanged2
        if value is not None:
            if self.StripWhitespace:
                value = value.strip()
                valueChanged = True

            if self.MakeLowercase:
                value = value.lower()
                valueChanged = True

            if len(value) < self.MinLength:
                _RaiseException(ValueError(_(u'The value provided for the 
%(variable)s is too short. It may be no shorter than %(len)i characters.') % 
{u'variable' : variableName, u'len' : self.MinLength}))

            if len(value) > self.MaxLength:
                _RaiseException(ValueError(_(u'The value provided for the 
%(variable)s is too long. It may be no longer than %(len)i characters.') % 
{u'variable' : variableName, u'len' : self.MaxLength}))

            if self.MustMatchRegEx is not None and not 
re.match(self.MustMatchRegEx, value):
                _RaiseException(ValueError(_(u'The value provided for the 
%(variable)s is not formatted properly. Please check the documentation for 
the %(variable)s for details on the format. (Technical details: the value did 
not match the regular expression "%(regex)s".)') % {u'variable' : 
variableName, u'regex' : self.MustMatchRegEx}))

        return (valueChanged, value)


# Python sequence types


class SequenceTypeMetadata(TypeMetadata):

    def __init__(self,
                 elementType,
                 minLength=0,
                 maxLength=2147483647,
                 maxItemsToValidate=2147483647,
                 mustBeSameLengthAsArgument=None,
                 pythonType=types.ObjectType,
                 canBeNone=False,
                 comIDLType=None,
                 canBeCOMParameter=True,
                 
arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPMultiValueTypeClass',
                 arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing',
                 canBeArcGISInputParameter=True,
                 canBeArcGISOutputParameter=False):
        
        assert isinstance(elementType, TypeMetadata), u'elementType must be 
an instance of TypeMetadata'
        assert isinstance(minLength, types.IntType) and minLength >= 0 and 
minLength <= 2147483647, u'minLength must be an integer between 0 and 
2147483647, inclusive'
        assert isinstance(maxLength, types.IntType) and maxLength >= 0 and 
maxLength <= 2147483647, u'maxLength must be an integer between 0 and 
2147483647, inclusive'
        assert maxLength >= minLength, u'maxLength must be greater than or 
equal to minLength'
        assert isinstance(maxItemsToValidate, types.IntType) and 
maxItemsToValidate >= 0, u'maxItemsToValidate must be an integer greater than 
or equal to 0'
        assert isinstance(mustBeSameLengthAsArgument, (types.UnicodeType, 
types.NoneType)), u'mustBeSameLengthAsArgument must be a Unicode string, or 
None'
        assert not canBeArcGISInputParameter or not arcGISType != 
u'ESRI.ArcGIS.Geoprocessing.GPMultiValueTypeClass' or 
(issubclass(elementType.PythonType, basestring) or not 
hasattr(elementType.PythonType, '__getitem__')), u'For this sequence type to 
be passed as an ArcGIS input parameter using the ArcGIS data type 
ESRI.ArcGIS.Geoprocessing.GPMultiValueTypeClass, its elements may not 
themselves be sequences unless they are strings. (In other words, you can\'t 
pass nested sequences using ESRI.ArcGIS.Geoprocessing.GPMultiValueTypeClass.)'

        # If comIDLType is None and canBeCOMParameter is True, which is
        # the normal situation, set comIDLType to a SAFEARRAY of the proper 
IDL
        # type for the elementType.

        if comIDLType is None and canBeCOMParameter:
            t = elementType
            while isinstance(t, SequenceTypeMetadata):
                t = t.ElementType
            comIDLType = u'SAFEARRAY(%s)' % t.COMIDLType

        # Initialize the base class.
        
        super(SequenceTypeMetadata, self).__init__(pythonType=pythonType,
                                                   canBeNone=canBeNone,
                                                   comIDLType=comIDLType,
                                                   
canBeCOMParameter=canBeCOMParameter,
                                                   arcGISType=arcGISType,
                                                   
arcGISAssembly=arcGISAssembly,
                                                   
canBeArcGISInputParameter=canBeArcGISInputParameter,
                                                   
canBeArcGISOutputParameter=canBeArcGISOutputParameter)
        self._ElementType = elementType
        self._MinLength = minLength
        self._MaxLength = maxLength
        self._MaxItemsToValidate = maxItemsToValidate
        self._MustBeSameLengthAsArgument = mustBeSameLengthAsArgument

    def _GetElementType(self):
        return self._ElementType
    
    ElementType = property(_GetElementType, doc=DynamicDocString())

    def _GetMinLength(self):
        return self._MinLength
    
    MinLength = property(_GetMinLength, doc=DynamicDocString())

    def _GetMaxLength(self):
        return self._MaxLength
    
    MaxLength = property(_GetMaxLength, doc=DynamicDocString())

    def _GetMaxItemsToValidate(self):
        return self._MaxItemsToValidate
    
    MaxItemsToValidate = property(_GetMaxItemsToValidate, 
doc=DynamicDocString())

    def _GetMustBeSameLengthAsArgument(self):
        return self._MustBeSameLengthAsArgument
    
    MustBeSameLengthAsArgument = property(_GetMustBeSameLengthAsArgument, 
doc=DynamicDocString())

    def AppendXMLNodes(self, node, document):
        super(SequenceTypeMetadata, self).AppendXMLNodes(node, document)
        elementTypeNode = 
node.appendChild(document.createElement(u'ElementTypeMetadata'))
        self.ElementType.AppendXMLNodes(elementTypeNode, document)
        Metadata.AppendPropertyXMLNode(self, u'MinLength', node, document)
        Metadata.AppendPropertyXMLNode(self, u'MaxLength', node, document)
        Metadata.AppendPropertyXMLNode(self, u'MaxItemsToValidate', node, 
document)
        Metadata.AppendPropertyXMLNode(self, u'MustBeSameLengthAsArgument', 
node, document)

    def AppendXMLNodesForValue(self, value, node, document):
        assert isinstance(value, self.PythonType), u'value must be an 
instance of %s' % self.PythonType.__name__
        assert isinstance(node, xml.dom.Node) and node.nodeType == 
xml.dom.Node.ELEMENT_NODE, u'node must be an instance of xml.dom.Node with 
nodeType==ELEMENT_NODE'
        assert isinstance(document, xml.dom.Node) and document.nodeType == 
xml.dom.Node.DOCUMENT_NODE, u'node must be an instance of xml.dom.Node with 
nodeType==DOCUMENT_NODE'
        listNode = node.appendChild(document.createElement(u'ArrayList'))
        for element in value:
            self.ElementType.AppendXMLNodesForValue(element, listNode, 
document)

    def ValidateValue(self, value, variableName, methodLocals=None, 
argMetadata=None):
        (valueChanged, value) = super(SequenceTypeMetadata, 
self).ValidateValue(value, variableName, methodLocals, argMetadata)

        length1 = 0
        length2 = 0

        if value is not None:

            if len(value) < self.MinLength:
                _RaiseException(ValueError(_(u'The length of the %(variable)s 
is too short. It must contain at least %(len)i items.') % {u'variable' : 
variableName, u'len' : self.MinLength}))

            if len(value) > self.MaxLength:
                _RaiseException(ValueError(_(u'The length of the %(variable)s 
is too long. It must contain no more than %(len)i items.') % {u'variable' : 
variableName, u'len' : self.MaxLength}))

            if self.MustBeSameLengthAsArgument is not None and methodLocals 
is not None:
                assert methodLocals.has_key(self.MustBeSameLengthAsArgument), 
_(u'To validate the %(param1)s of the method being validated, that method 
must also have an parameter named %(param2)s.') % {u'param1' : variableName, 
u'param2' : self.MustBeSameLengthAsArgument}
                length1 = len(value)

            if self.MustBeSameLengthAsArgument is not None and methodLocals 
is not None and methodLocals[self.MustBeSameLengthAsArgument] is not None:
                try:
                    length2 = 
len(methodLocals[self.MustBeSameLengthAsArgument])
                except Exception, e:
                    _RaiseException(TypeError(_(u'To validate the %(param1)s 
of the method being validated, the length of method\'s %(param2)s parameter 
must be able to be obtained with the Python len function. That function 
raised the following exception when passed the value of that parameter: 
%(error)s: %(msg)s') % {u'param1' : variableName, u'param2' : 
self.MustBeSameLengthAsArgument, u'error': e.__class__.__name__, u'msg': 
unicode(e)}))

            if length1 != length2:
                _RaiseException(TypeError(_(u'The %(param1)s must have the 
same number of items as the %(param2)s parameter.') % {u'param1' : 
variableName, u'param2' : self.MustBeSameLengthAsArgument}))

        return (valueChanged, value)

    def ParseValueFromArcGISInputParameterString(self, paramString, 
paramDisplayName, paramIndex):
        paramString = super(SequenceTypeMetadata, 
self).ParseValueFromArcGISInputParameterString(paramString, paramDisplayName, 
paramIndex)

        # The input string is a list of values formatted as follows:
        #     - Values are separated by semicolons
        #     - If a value contains a space or tab it is enclosed in 
apostrophes
        #     - There are no escape sequences for semicolons or apostrophes
        #     - An empty string is formatted as two successive semicolons
        #
        # We parse the string using a finite state machine. Because there are 
no
        # escape sequences for semicolons or apostrophes, it is not possible 
for
        # the user to pass certain strings to us, and some strings will lead 
to
        # undesirable results.
        
        FIRST_CHARACTER = 1                                     # We are 
positioned on the first character of the input strong or the first character 
following the semicolon that terminated the previous element.
        INSIDE_SEMICOLON = 2                                    # We are 
positioned on the second or subsequent character inside an element that did 
not begin with an apostrophe.
        INSIDE_QUOTE_NO_SPACE_FOUND = 3                         # We are 
positioned on the second or subsequent character inside an element that began 
with an apostrophe, and we have not yet found the space or tab character that 
necessitated the apostrophe, so it could just be part of the string.
        INSIDE_QUOTE_SPACE_FOUND = 4                            # We are 
positioned on the second or subsequent character inside an element that began 
with an apostrophe, and we have already found the space or tab character that 
necessitated the apostrophe.
        INSIDE_QUOTE_SPACE_FOUND_POSSIBLE_TRAILING_QUOTE = 5    # We are 
positioned on a character following the second or subsequent apostrophe 
inside an element that begain with an apostrophe and was found to have a 
space or tab character. The apostrophe we just parsed could be the closing 
apostrophe, if we now are positioned on a semicolon or the end of the string.

        state = FIRST_CHARACTER
        params = []
        i = 0
        paramStart = 0
        paramCharCount = 0
        failedBecauseArcGISForgotQuotes = False     # Sometimes ArcGIS seems 
to violate the rules described above in a way that makes the string 
unparsable. In this case we treat it as a single string and report a warning.

        #from GeoEco.Logging import Logger
        try:
            while i < len(paramString):
                #Logger.Debug('----------------------------')
                #Logger.Debug(u'i = %i, c = %s, state = %i, paramStart = %i, 
paramCharCount= %i' % (i, paramString[i], state, paramStart, paramCharCount))
                
                if state == FIRST_CHARACTER:
                    if paramString[i] == u';':
                        params.append(u'')
                    elif paramString[i] == u'\'':
                        state = INSIDE_QUOTE_NO_SPACE_FOUND
                        paramStart = i
                        paramCharCount = 1
                    else:
                        state = INSIDE_SEMICOLON
                        paramStart = i
                        paramCharCount = 1

                elif state == INSIDE_SEMICOLON:
                    if paramString[i] == u' ' or paramString[i] == u'\t':
                        failedBecauseArcGISForgotQuotes = True
                        raise ValueError(_(u'Failed to parse a list of values 
from the string provided for the %(paramName)s parameter (parameter number 
%(paramIndex)i). The parser encountered an error: a space or tab character 
was found outside of enclosing apostrophes. If an element in the list 
contains a space or tab, enclose the entire element in apostrophes. If you 
are invoking this function from ArcGIS, there is no need to do this 
explicitly, ArcGIS does it for you; you must have received this error for a 
different reason. Please contact the author of this function for 
assistance.') % {u'paramName' : paramDisplayName, u'paramIndex' : paramIndex})
                    elif paramString[i] == u';':
                        state = FIRST_CHARACTER
                        
params.append(paramString[paramStart:paramStart+paramCharCount])
                    else:
                        paramCharCount += 1

                elif state == INSIDE_QUOTE_NO_SPACE_FOUND:
                    if paramString[i] == u';':
                        state = FIRST_CHARACTER
                        if paramString[paramStart:paramStart+paramCharCount] 
== u'\'\'':
                            params.append(u'')
                        else:
                            
params.append(paramString[paramStart:paramStart+paramCharCount])
                    elif paramString[i] == u' ' or paramString[i] == u'\t':
                        state = INSIDE_QUOTE_SPACE_FOUND
                        paramStart += 1
                    else:
                        paramCharCount += 1

                elif state == INSIDE_QUOTE_SPACE_FOUND:
                    if paramString[i] == u'\'':
                        state = 
INSIDE_QUOTE_SPACE_FOUND_POSSIBLE_TRAILING_QUOTE
                    else:
                        paramCharCount += 1

                elif state == 
INSIDE_QUOTE_SPACE_FOUND_POSSIBLE_TRAILING_QUOTE:
                    if paramString[i] == u'\'':
                        paramCharCount += 1
                    elif paramString[i] == u';':
                        state = FIRST_CHARACTER
                        
params.append(paramString[paramStart:paramStart+paramCharCount])
                    else:
                        paramCharCount += 1

                else:
                    _RaiseException(RuntimeError(_(u'Failed to parse a list 
of values from the string provided for the %(paramName)s parameter (parameter 
number %(paramIndex)i) due to a programming error in the parser: the parser 
was found to be in unknown state %(state)i. Please contact the author of this 
function for assistance.') % {u'paramName' : paramDisplayName, u'paramIndex' 
: paramIndex, u'state' : state}))

                #Logger.Debug('state = %i, paramStart = %i, paramCharCount= 
%i' % (state, paramStart, paramCharCount))

                i += 1
                
        except:
            if failedBecauseArcGISForgotQuotes:
                from GeoEco.Logging import Logger
                Logger.Warning(_(u'The string provided for %(paramName)s 
parameter (parameter number %(paramIndex)i) included a space but the string 
itself was not enclosed in apostrophes. This is a known problem with how 
ArcGIS passes parameters to Python scripts. As a result, the string cannot be 
parsed into a list of items and will be treated as a single item. This may 
result in unintended effects. Please check your outputs carefully.') % 
{u'paramName' : paramDisplayName, u'paramIndex' : paramIndex})
                params.append(paramString)
            else:
                raise
            
        else:
            if state == FIRST_CHARACTER:
                if paramString.endswith(u';'):
                    params.append(u'')
            elif state == INSIDE_SEMICOLON or state == 
INSIDE_QUOTE_NO_SPACE_FOUND or state == 
INSIDE_QUOTE_SPACE_FOUND_POSSIBLE_TRAILING_QUOTE:
                
params.append(paramString[paramStart:paramStart+paramCharCount])
            elif state == INSIDE_QUOTE_SPACE_FOUND:
                _RaiseException(ValueError(_(u'Failed to parse a list of 
values from the string provided for the %(paramName)s parameter (parameter 
number %(paramIndex)i). The parser encountered an error: the last element in 
the list begain with an apostrophe, included at least one space or tab 
character but did not end with an apostrophe. Please end your string with an 
apostrophe. If you are invoking this function from ArcGIS, there is no need 
to do this explicitly, ArcGIS does it for you; you must have received this 
error for a different reason. Please contact the author of this function for 
assistance.') % {u'paramName' : paramDisplayName, u'paramIndex' : 
paramIndex}))
            else:
                _RaiseException(RuntimeError(_(u'Failed to parse a list of 
values from the string provided for the %(paramName)s parameter (parameter 
number %(paramIndex)i) due to a programming error in the parser: the parser 
was found to be in unknown state %(state)i. Please contact the author of this 
function for assistance.') % {u'paramName' : paramDisplayName, u'paramIndex' 
: paramIndex, u'state' : state}))

        # The parser built a list of Unicode strings. If we're supposed to
        # return a list of Unicode strings, just return now.

        if issubclass(self.ElementType.PythonType, types.UnicodeType):
            return params

        # Parse the list of Unicode strings into the appropriate Python type.
        # For Python types that are not strings, we interpret whitespace as
        # None.

        values = []        

        for i in range(len(params)):
            s = params[i]
            if not issubclass(self.ElementType.PythonType, types.StringType):
                s = params[i].strip()
                if len(s) <= 0 and self.ElementType.CanBeNone:
                    values.append(None)
                    continue
            
values.append(self.ElementType.ParseValueFromArcGISInputParameterString(s, 
_(u'element at position %i (where 0 is the first element) of the %s') % (i, 
paramDisplayName), paramIndex))
                
        return values


class ListTypeMetadata(SequenceTypeMetadata):

    def __init__(self,
                 elementType,
                 minLength=0,
                 maxLength=2147483647,
                 maxItemsToValidate=2147483647,
                 mustBeSameLengthAsArgument=None,
                 canBeNone=False):
        
        super(ListTypeMetadata, self).__init__(elementType=elementType,
                                               minLength=minLength,
                                               maxLength=maxLength,
                                               
maxItemsToValidate=maxItemsToValidate,
                                               
mustBeSameLengthAsArgument=mustBeSameLengthAsArgument,
                                               pythonType=types.ListType,
                                               canBeNone=canBeNone)

    def ValidateValue(self, value, variableName, methodLocals=None, 
argMetadata=None):
        (valueChanged, value) = super(ListTypeMetadata, 
self).ValidateValue(value, variableName, methodLocals, argMetadata)
        if value is not None:
            itemsToValidate = min(len(value), self.MaxItemsToValidate)
            if itemsToValidate != len(value):
                from GeoEco.Logging import Logger
                Logger.Debug(_(u'The %(var)s contains %(count1)i items, but 
to minimize execution time, only the first %(count2)i items will be 
validated. If an invalid item is present, unexpected results may occur.') % 
{u'var': variableName, u'count1': len(value), u'count2': 
self.MaxItemsToValidate})
            for i in range(itemsToValidate):
                (elementValueChanged, newElementValue) = 
self.ElementType.ValidateValue(value[i], _(u'element %i of the %s (where 0 is 
the first element)') % (i, variableName), methodLocals, argMetadata)
                if elementValueChanged:
                    value[i] = newElementValue
                    valueChanged = True
        return (valueChanged, value)


class TupleTypeMetadata(SequenceTypeMetadata):

    def __init__(self,
                 elementType,
                 minLength=0,
                 maxLength=2147483647,
                 maxItemsToValidate=2147483647,
                 mustBeSameLengthAsArgument=None,
                 canBeNone=False):
        
        super(TupleTypeMetadata, self).__init__(elementType=elementType,
                                                minLength=minLength,
                                                maxLength=maxLength,
                                                
maxItemsToValidate=maxItemsToValidate,
                                                
mustBeSameLengthAsArgument=mustBeSameLengthAsArgument,
                                                pythonType=types.TupleType,
                                                canBeNone=canBeNone)

    def ValidateValue(self, value, variableName, methodLocals=None, 
argMetadata=None):
        (valueChanged, value) = super(TupleTypeMetadata, 
self).ValidateValue(value, variableName, methodLocals, argMetadata)
        if value is not None:
            itemsToValidate = min(len(value), self.MaxItemsToValidate)
            if itemsToValidate != len(value):
                from GeoEco.Logging import Logger
                Logger.Debug(_(u'The %(var)s contains %(count1)i items, but 
to minimize execution time, only the first %(count2)i items will be 
validated. If an invalid item is present, unexpected results may occur.') % 
{u'var': variableName, u'count1': len(value), u'count2': 
self.MaxItemsToValidate})
            for i in range(itemsToValidate):
                (elementValueChanged, newElementValue) = 
self.ElementType.ValidateValue(value[i], _(u'element %i of the %s (where 0 is 
the first element)') % (i, variableName), methodLocals, argMetadata)
                if elementValueChanged:
                    if isinstance(value, types.TupleType):
                        value = list(value)
                    value[i] = newElementValue
                    valueChanged = True
        if isinstance(value, types.ListType):
            value = tuple(value)
            valueChanged = True
        return (valueChanged, value)

    def ParseValueFromArcGISInputParameterString(self, paramString, 
paramDisplayName, paramIndex):
        resultList = super(TupleTypeMetadata, 
self).ParseValueFromArcGISInputParameterString(paramString, paramDisplayName, 
paramIndex)
        return tuple(resultList)


class DictionaryTypeMetadata(TypeMetadata):

    def __init__(self,
                 keyType,
                 valueType,
                 minLength=0,
                 maxLength=2147483647,
                 pythonType=types.DictType,
                 canBeNone=False):
        
        assert isinstance(keyType, TypeMetadata), u'keyType must be an 
instance of TypeMetadata'
        assert isinstance(valueType, TypeMetadata), u'valueType must be an 
instance of TypeMetadata'
        assert isinstance(minLength, types.IntType) and minLength >= 0 and 
minLength <= 2147483647, u'minLength must be an integer between 0 and 
2147483647, inclusive'
        assert isinstance(maxLength, types.IntType) and maxLength >= 0 and 
maxLength <= 2147483647, u'maxLength must be an integer between 0 and 
2147483647, inclusive'
        assert maxLength >= minLength, u'maxLength must be greater than or 
equal to minLength'

        # Initialize the base class.
        
        super(DictionaryTypeMetadata, self).__init__(pythonType=pythonType, 
canBeNone=canBeNone)
        self._KeyType = keyType
        self._ValueType = valueType
        self._MinLength = minLength
        self._MaxLength = maxLength

    def _GetKeyType(self):
        return self._KeyType
    
    KeyType = property(_GetKeyType, doc=DynamicDocString())

    def _GetValueType(self):
        return self._ValueType
    
    ValueType = property(_GetValueType, doc=DynamicDocString())

    def _GetMinLength(self):
        return self._MinLength
    
    MinLength = property(_GetMinLength, doc=DynamicDocString())

    def _GetMaxLength(self):
        return self._MaxLength
    
    MaxLength = property(_GetMaxLength, doc=DynamicDocString())

    def AppendXMLNodes(self, node, document):
        super(DictionaryTypeMetadata, self).AppendXMLNodes(node, document)
        keyTypeNode = 
node.appendChild(document.createElement(u'KeyTypeMetadata'))
        self.KeyType.AppendXMLNodes(keyTypeNode, document)
        valueTypeNode = 
node.appendChild(document.createElement(u'ValueTypeMetadata'))
        self.ValueType.AppendXMLNodes(valueTypeNode, document)
        Metadata.AppendPropertyXMLNode(self, u'MinLength', node, document)
        Metadata.AppendPropertyXMLNode(self, u'MaxLength', node, document)

    def AppendXMLNodesForValue(self, value, node, document):
        raise AssertionError(u'Default values are not currently supported for 
parameters of type DictionaryTypeMetadata. Please remove the default value 
%s.' % unicode(repr(value)))

    def ValidateValue(self, value, variableName, methodLocals=None, 
argMetadata=None):
        (valueChanged, value) = super(DictionaryTypeMetadata, 
self).ValidateValue(value, variableName, methodLocals, argMetadata)

        if value is not None:

            if len(value) < self.MinLength:
                _RaiseException(ValueError(_(u'The length of the %(variable)s 
is too short. It must contain at least %(len)i items.') % {u'variable' : 
variableName, u'len' : self.MinLength}))

            if len(value) > self.MaxLength:
                _RaiseException(ValueError(_(u'The length of the %(variable)s 
is too long. It must contain no more than %(len)i items.') % {u'variable' : 
variableName, u'len' : self.MaxLength}))

            for key, val in value.items():
                (keyChanged, newKey) = self.ValueType.ValidateValue(val, 
_(u'key %s of the %s') % (unicode(repr(key)), variableName), methodLocals, 
argMetadata)
                (valChanged, newVal) = self.ValueType.ValidateValue(val, 
_(u'value of key %s of the %s') % (unicode(repr(key)), variableName), 
methodLocals, argMetadata)
                if keyChanged and valChanged:
                    del value[key]
                    value[newKey] = newVal
                elif keyChanged and not valChanged:
                    del value[key]
                    value[newKey] = val
                elif not keyChanged and valChanged:
                    value[key] = newVal
                valueChanged = keyChanged or valChanged

        return (valueChanged, value)


# Types that represents stored objects (files, directories, DB tables, etc.)


class StoredObjectTypeMetadata(UnicodeStringTypeMetadata):
    
    def __init__(self,
                 typeDisplayName,
                 isPath=True,
                 canBeRelativePath=True,
                 basePathArgument=None,
                 useArcGISWorkspace=True,
                 normalizePath=True,
                 mustBeDifferentThanArguments=None,
                 mustExist=False,
                 mustNotExist=False,
                 deleteIfParameterIsTrue=None,
                 createParentDirectories=False,
                 minLength=1,
                 maxLength=255,
                 mustMatchRegEx=None,
                 canBeNone=False,
                 arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPStringTypeClass',
                 arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing',
                 canBeArcGISInputParameter=True,
                 canBeArcGISOutputParameter=True):
        
        assert isinstance(typeDisplayName, types.UnicodeType), 
u'typeDisplayName must be a Unicode string'
        assert isinstance(isPath, types.BooleanType), u'isPath must be a 
boolean'
        assert isinstance(canBeRelativePath, types.BooleanType), 
u'canBeRelativePath must be a boolean'
        assert not (canBeRelativePath and not isPath), u'If canBeRelativePath 
is True, isPath must also be True'
        assert isinstance(basePathArgument, (types.UnicodeType, 
types.NoneType)), u'basePathArgument must be a Unicode string, or None'
        assert not (basePathArgument is not None and not canBeRelativePath), 
u'If basePathArgument is not None, canBeRelativePath must also be True'
        assert isinstance(useArcGISWorkspace, types.BooleanType), 
u'useArcGISWorkspace must be a boolean'
        assert not (useArcGISWorkspace and not canBeRelativePath), u'If 
useArcGISWorkspace is True, canBeRelativePath must also be True'
        assert isinstance(normalizePath, types.BooleanType), u'normalizePath 
must be a boolean'
        assert isinstance(mustExist, types.BooleanType), u'mustExist must be 
a boolean'
        assert isinstance(mustNotExist, types.BooleanType), u'mustNotExist 
must be a boolean'
        assert not mustExist or not mustNotExist, u'mustExist and 
mustNotExist cannot both be True'
        assert isinstance(deleteIfParameterIsTrue, (types.UnicodeType, 
types.NoneType)), u'deleteIfParameterIsTrue must be a Unicode string, or None'
        assert not mustNotExist or deleteIfParameterIsTrue is None, 
u'deleteIfParameterIsTrue must be None if mustNotExist is True'
        assert isinstance(createParentDirectories, types.BooleanType), 
u'createParentDirectories must be a boolean'
        super(StoredObjectTypeMetadata, self).__init__(minLength=minLength,
                                                       maxLength=maxLength,
                                                       
mustMatchRegEx=mustMatchRegEx,
                                                       canBeNone=canBeNone,
                                                       arcGISType=arcGISType,
                                                       
arcGISAssembly=arcGISAssembly,
                                                       
canBeArcGISInputParameter=canBeArcGISInputParameter,
                                                       
canBeArcGISOutputParameter=canBeArcGISOutputParameter)
        self._TypeDisplayName = typeDisplayName
        self._IsPath = isPath
        self._CanBeRelativePath = canBeRelativePath
        self._BasePathArgument = basePathArgument
        self._UseArcGISWorkspace = useArcGISWorkspace
        self._NormalizePath = normalizePath
        self._MustBeDifferentThanArguments = mustBeDifferentThanArguments
        self._MustExist = mustExist
        self._MustNotExist = mustNotExist
        self._DeleteIfParameterIsTrue = deleteIfParameterIsTrue
        self._CreateParentDirectories = createParentDirectories

    def _GetTypeDisplayName(self):
        return self._TypeDisplayName
    
    TypeDisplayName = property(_GetTypeDisplayName, doc=DynamicDocString())

    def _GetIsPath(self):
        return self._IsPath
    
    IsPath = property(_GetIsPath, doc=DynamicDocString())

    def _GetCanBeRelativePath(self):
        return self._CanBeRelativePath
    
    CanBeRelativePath = property(_GetCanBeRelativePath, 
doc=DynamicDocString())

    def _GetBasePathArgument(self):
        return self._BasePathArgument

    def _SetBasePathArgument(self, value):
        assert isinstance(value, (types.UnicodeType, types.NoneType)), 
u'BasePathArgument must be a Unicode string, or None'
        self._BasePathArgument = value
    
    BasePathArgument = property(_GetBasePathArgument, _SetBasePathArgument, 
doc=DynamicDocString())

    def _GetUseArcGISWorkspace(self):
        return self._UseArcGISWorkspace
    
    UseArcGISWorkspace = property(_GetUseArcGISWorkspace, 
doc=DynamicDocString())

    def _GetNormalizePath(self):
        return self._NormalizePath
    
    NormalizePath = property(_GetNormalizePath, doc=DynamicDocString())

    def _GetMustBeDifferentThanArguments(self):
        return self._MustBeDifferentThanArguments

    def _SetMustBeDifferentThanArguments(self, value):
        assert isinstance(value, (types.ListType, types.TupleType, 
types.NoneType)), u'MustBeDifferentThanArguments must be a list or tuple of 
Unicode strings, or None'
        if value is not None:
            if isinstance(value, types.TupleType):
                value = list(value)
            for v in value:
                assert isinstance(value, types.UnicodeType), 
u'MustBeDifferentThanArguments must be a list or tuple of Unicode strings, or 
None'
        self._MustBeDifferentThanArguments = value
    
    MustBeDifferentThanArguments = property(_GetMustBeDifferentThanArguments, 
_SetMustBeDifferentThanArguments, doc=DynamicDocString())

    def _GetMustExist(self):
        return self._MustExist

    def _SetMustExist(self, value):
        assert isinstance(value, types.BooleanType), u'MustExist must be a 
boolean'
        self._MustExist = value
    
    MustExist = property(_GetMustExist, _SetMustExist, doc=DynamicDocString())

    def _GetMustNotExist(self):
        return self._MustNotExist

    def _SetMustNotExist(self, value):
        assert isinstance(value, types.BooleanType), u'MustNotExist must be a 
boolean'
        self._MustNotExist = value
    
    MustNotExist = property(_GetMustNotExist, _SetMustNotExist, 
doc=DynamicDocString())

    def _GetDeleteIfParameterIsTrue(self):
        return self._DeleteIfParameterIsTrue

    def _SetDeleteIfParameterIsTrue(self, value):
        assert isinstance(value, (types.UnicodeType, types.NoneType)), 
u'DeleteIfParameterIsTrue must be a Unicode string, or None'
        self._DeleteIfParameterIsTrue = value
    
    DeleteIfParameterIsTrue = property(_GetDeleteIfParameterIsTrue, 
_SetDeleteIfParameterIsTrue, doc=DynamicDocString())

    def _GetCreateParentDirectories(self):
        return self._CreateParentDirectories

    def _SetCreateParentDirectories(self, value):
        assert isinstance(value, types.BooleanType), 
u'CreateParentDirectories must be a boolean'
        self._CreateParentDirectories = value
    
    CreateParentDirectories = property(_GetCreateParentDirectories, 
_SetCreateParentDirectories, doc=DynamicDocString())

    def AppendXMLNodes(self, node, document):
        super(StoredObjectTypeMetadata, self).AppendXMLNodes(node, document)
        Metadata.AppendPropertyXMLNode(self, u'TypeDisplayName', node, 
document)
        Metadata.AppendPropertyXMLNode(self, u'IsPath', node, document)
        Metadata.AppendPropertyXMLNode(self, u'CanBeRelativePath', node, 
document)
        Metadata.AppendPropertyXMLNode(self, u'BasePathArgument', node, 
document)
        Metadata.AppendPropertyXMLNode(self, u'UseArcGISWorkspace', node, 
document)
        Metadata.AppendPropertyXMLNode(self, u'NormalizePath', node, document)
        mustBeDifferentThanArgumentsNode = 
node.appendChild(document.createElement(u'MustBeDifferentThanArguments'))
        if self.MustBeDifferentThanArguments is not None:
            listNode = 
mustBeDifferentThanArgumentsNode.appendChild(document.createElement(u'ArrayList'))
            for i in range(len(self.MustBeDifferentThanArguments)):
                
self.AppendXMLNodesForValue(self.MustBeDifferentThanArguments[i], listNode, 
document)
        Metadata.AppendPropertyXMLNode(self, u'MustExist', node, document)
        Metadata.AppendPropertyXMLNode(self, u'MustNotExist', node, document)
        Metadata.AppendPropertyXMLNode(self, u'DeleteIfParameterIsTrue', 
node, document)
        Metadata.AppendPropertyXMLNode(self, u'CreateParentDirectories', 
node, document)

    def ValidateValue(self, value, variableName, methodLocals=None, 
argMetadata=None):
        (valueChanged, value) = super(StoredObjectTypeMetadata, 
self).ValidateValue(value, variableName, methodLocals, argMetadata)

        if value is not None:
            exists = None
            isCorrectType = None
            
            if self.IsPath:
                valueChanged, value, exists, isCorrectType = 
self._CanonicalizePath(value, argMetadata, methodLocals)

            if self.MustBeDifferentThanArguments is not None and methodLocals 
is not None:
                for arg in self.MustBeDifferentThanArguments:
                    assert methodLocals.has_key(arg), _(u'To validate the 
%(param1)s of the method being validated, that method must also have an 
parameter named %(param2)s.') % {u'param1' : variableName, u'param2' : arg}
                    if value == methodLocals[arg]:
                        same = True
                    elif hasattr(os.path,'samefile'):
                        try:
                            same = os.path.samefile(value, methodLocals[arg])
                        except OSError:
                            same = False
                    else:
                        same = os.path.normcase(os.path.abspath(value)) == 
os.path.normcase(os.path.abspath(methodLocals[arg]))
                    if same:
                        _RaiseException(ValueError(_(u'The %(param1)s and the 
%(param2)s parameter refer to the same %(type)s (%(value)s). You must not 
specify the same %(type)s.') % {u'param1' : variableName, u'param2' : arg, 
u'type' : self.TypeDisplayName, u'value' : value}))

            from GeoEco.Logging import Logger
            oldLogInfoAsDebug = Logger.GetLogInfoAsDebug()
            Logger.SetLogInfoAsDebug(True)
            try:

                if self.MustExist or self.MustNotExist or 
self.DeleteIfParameterIsTrue is not None:
                    assert self.DeleteIfParameterIsTrue is None or 
methodLocals.has_key(self.DeleteIfParameterIsTrue), _(u'To validate the 
%(param1)s of the method being validated, that method must also have an 
parameter named %(param2)s.') % {u'param1' : variableName, u'param2' : 
self.DeleteIfParameterIsTrue}
                    if exists is None:
                        exists, isCorrectType = self.Exists(value, 
argMetadata, methodLocals)
                    if exists:
                        if isCorrectType:
                            if self.MustNotExist or 
self.DeleteIfParameterIsTrue is not None and not 
methodLocals[self.DeleteIfParameterIsTrue]:
                                _RaiseException(ValueError(_(u'The %(type)s 
%(value)s, specified for the %(variable)s, already exists. Please delete it 
and try again, or specify a non-existing %(type)s.') % {u'type' : 
self.TypeDisplayName, u'value' : value, u'variable' : variableName}))
                            if self.DeleteIfParameterIsTrue is not None and 
methodLocals[self.DeleteIfParameterIsTrue]:
                                self.Delete(value, argMetadata, methodLocals)
                        else:
                            if self.MustNotExist:
                                _RaiseException(ValueError(_(u'The value 
specified for the %(variable)s, %(value)s, already exists although it is not 
a %(type)s. Please delete it and try again, or specify a non-existing 
object.') % {u'type' : self.TypeDisplayName, u'value' : value, u'variable' : 
variableName}))
                            if self.MustExist or self.DeleteIfParameterIsTrue 
is not None:
                                _RaiseException(ValueError(_(u'The value 
specified for the %(variable)s, %(value)s, exists but it is not a %(type)s. 
Please specify a %(type)s.') % {u'type' : self.TypeDisplayName, u'value' : 
value, u'variable' : variableName}))
                    elif self.MustExist:
                        _RaiseException(ValueError(_(u'The %(type)s 
%(value)s, specified for the %(variable)s, does not exist. Please specify an 
existing %(type)s.') % {u'type' : self.TypeDisplayName, u'value' : value, 
u'variable' : variableName}))

                if self.CreateParentDirectories and 
(re.match(u'^[A-Za-z]:[\\\\/]', value) or re.match(u'^[\\\\/]', value)) and 
not (os.path.dirname(value).lower().endswith(u'.mdb') and 
os.path.isfile(os.path.dirname(value))):
                    from GeoEco.DataManagement.Directories import Directory
                    Directory.Create(os.path.dirname(value))

            finally:
                Logger.SetLogInfoAsDebug(oldLogInfoAsDebug)
            
        return (valueChanged, value)

    def _CanonicalizePath(self, value, argMetadata, methodLocals):
        valueChanged = False
        
        if self.IsRelativePath(value):
            if not self.CanBeRelativePath:
                _RaiseException(ValueError(_(u'The %(variable)s specifies the 
relative path "%(value)s" but relative paths are not allowed. Please provide 
an absolute path and try again.') % {u'variable' : variableName, u'value' : 
value}))
                
            madeAbsolute = False

            if self.BasePathArgument is not None:
                if not methodLocals.has_key(self.BasePathArgument):
                    _RaiseException(RuntimeError(_(u'Programming error in 
this tool. The metadata for the %(variable)s specifies that when the caller 
provides a relative path, the base path can be obtained from the %(base)s 
parameter, but that parameter does not exist. Please contact the author of 
this tool for assistance.') % {u'variable' : variableName, u'base': 
self.BasePathArgument}))
                if methodLocals[self.BasePathArgument] is not None:
                    value2 = 
os.path.join(methodLocals[self.BasePathArgument], value)
                    if value != value2:
                        value = value2
                        valueChanged = True
                    madeAbsolute = True

            if not madeAbsolute and self.UseArcGISWorkspace:
                from GeoEco.ArcGIS import GeoprocessorManager
                gp = GeoprocessorManager.GetWrappedGeoprocessor()
                if gp is not None and isinstance(gp.Workspace, basestring) 
and len(gp.Workspace) > 0:
                    value2 = os.path.join(gp.Workspace, value)
                    if value != value2:
                        value = value2
                        valueChanged = True
                    madeAbsolute = True

            if not madeAbsolute:
                value2 = os.path.abspath(value)
                if value != value2:
                    value = value2
                    valueChanged = True

        if self.NormalizePath:
            value2 = os.path.normpath(value)
            if value != value2:
                value = value2
                valueChanged = True

        return valueChanged, value, None, None      # valueChanged, value, 
exists, isCorrectType

    @classmethod
    def Exists(cls, name, argMetadata=None, methodLocals=None):
        if isinstance(cls, StoredObjectTypeMetadata):
            className = cls.__class__.__name__
        else:
            className = cls.__name__
        _RaiseException(NotImplementedError(u'Programming error in the %s 
class: the class does not implement the Exists method.' % className))

    @classmethod
    def Delete(cls, name, argMetadata=None, methodLocals=None):
        if isinstance(cls, StoredObjectTypeMetadata):
            className = cls.__class__.__name__
        else:
            className = cls.__name__
        _RaiseException(NotImplementedError(u'Programming error in the %s 
class: the class does not implement the Delete method.' % className))

    @classmethod
    def Copy(cls, source, dest, overwriteExisting=False, argMetadata=None, 
methodLocals=None):
        if isinstance(cls, StoredObjectTypeMetadata):
            className = cls.__class__.__name__
        else:
            className = cls.__name__
        _RaiseException(NotImplementedError(u'Programming error in the %s 
class: the class does not implement the Copy method.' % className))

    @classmethod
    def IsRelativePath(cls, p):
        if p is None:
            return False
        if sys.platform == u'win32':
            if re.match(u'^[A-Za-z]:[\\\\/]', p) or 
re.match(u'^[\\\\/][\\\\/]\w', p):
                return False
        else:
            if p.startswith(u'/'):
                return False
        return True


class FileTypeMetadata(StoredObjectTypeMetadata):

    def __init__(self,
                 mayBeCompressed=False,
                 decompressedFileToUse=u'*',
                 typeDisplayName=_(u'file'),
                 canBeRelativePath=True,
                 basePathArgument=None,
                 useArcGISWorkspace=True,
                 normalizePath=True,
                 mustBeDifferentThanArguments=None,
                 mustExist=False,
                 mustNotExist=False,
                 deleteIfParameterIsTrue=None,
                 createParentDirectories=False,
                 minLength=1,
                 maxLength=255,
                 mustMatchRegEx=None,
                 canBeNone=False,
                 arcGISType=u'ESRI.ArcGIS.Catalog.DEFileTypeClass',
                 arcGISAssembly=u'ESRI.ArcGIS.Catalog',
                 canBeArcGISInputParameter=True,
                 canBeArcGISOutputParameter=True):
        
        assert isinstance(mayBeCompressed, types.BooleanType), 
u'mayBeCompressed must be a boolean'
        super(FileTypeMetadata, 
self).__init__(typeDisplayName=typeDisplayName,
                                               isPath=True,
                                               
canBeRelativePath=canBeRelativePath,
                                               
basePathArgument=basePathArgument,
                                               
useArcGISWorkspace=useArcGISWorkspace,
                                               normalizePath=normalizePath,
                                               
mustBeDifferentThanArguments=mustBeDifferentThanArguments,
                                               mustExist=mustExist,
                                               mustNotExist=mustNotExist,
                                               
deleteIfParameterIsTrue=deleteIfParameterIsTrue,
                                               
createParentDirectories=createParentDirectories,
                                               minLength=minLength,
                                               maxLength=maxLength,
                                               mustMatchRegEx=mustMatchRegEx,
                                               canBeNone=canBeNone,
                                               arcGISType=arcGISType,
                                               arcGISAssembly=arcGISAssembly,
                                               
canBeArcGISInputParameter=canBeArcGISInputParameter,
                                               
canBeArcGISOutputParameter=canBeArcGISOutputParameter)
        self._MayBeCompressed = mayBeCompressed
        self._DecompressedFileToUse = decompressedFileToUse

    def _GetMayBeCompressed(self):
        return self._MayBeCompressed
    
    MayBeCompressed = property(_GetMayBeCompressed, doc=DynamicDocString())

    def _GetDecompressedFileToUse(self):
        return self._DecompressedFileToUse
    
    DecompressedFileToUse = property(_GetDecompressedFileToUse, 
doc=DynamicDocString())

    def AppendXMLNodes(self, node, document):
        super(FileTypeMetadata, self).AppendXMLNodes(node, document)
        Metadata.AppendPropertyXMLNode(self, u'MayBeCompressed', node, 
document)
        Metadata.AppendPropertyXMLNode(self, u'DecompressedFileToUse', node, 
document)

    @classmethod
    def Exists(cls, name, argMetadata=None, methodLocals=None):
        from GeoEco.DataManagement.Files import File
        return File.Exists(name)

    @classmethod
    def Delete(cls, name, argMetadata=None, methodLocals=None):
        from GeoEco.DataManagement.Files import File
        File.Delete(name)

    @classmethod
    def Copy(cls, source, dest, overwriteExisting=False, argMetadata=None, 
methodLocals=None):
        from GeoEco.DataManagement.Files import File
        File.Copy(source, dest, overwriteExisting=overwriteExisting)


class TextFileTypeMetadata(FileTypeMetadata):

    def __init__(self,
                 mayBeCompressed=False,
                 decompressedFileToUse=u'*',
                 typeDisplayName=_(u'text file'),
                 canBeRelativePath=True,
                 basePathArgument=None,
                 useArcGISWorkspace=True,
                 normalizePath=True,
                 mustBeDifferentThanArguments=None,
                 mustExist=False,
                 mustNotExist=False,
                 deleteIfParameterIsTrue=None,
                 createParentDirectories=False,
                 minLength=1,
                 maxLength=255,
                 mustMatchRegEx=None,
                 canBeNone=False,
                 arcGISType=u'ESRI.ArcGIS.Catalog.DETextFileTypeClass',
                 arcGISAssembly=u'ESRI.ArcGIS.Catalog',
                 canBeArcGISInputParameter=True,
                 canBeArcGISOutputParameter=True):
        
        super(TextFileTypeMetadata, 
self).__init__(mayBeCompressed=mayBeCompressed,
                                                   
decompressedFileToUse=decompressedFileToUse,
                                                   
typeDisplayName=typeDisplayName,
                                                   
canBeRelativePath=canBeRelativePath,
                                                   
basePathArgument=basePathArgument,
                                                   
useArcGISWorkspace=useArcGISWorkspace,
                                                   
normalizePath=normalizePath,
                                                   
mustBeDifferentThanArguments=mustBeDifferentThanArguments,
                                                   mustExist=mustExist,
                                                   mustNotExist=mustNotExist,
                                                   
deleteIfParameterIsTrue=deleteIfParameterIsTrue,
                                                   
createParentDirectories=createParentDirectories,
                                                   minLength=minLength,
                                                   maxLength=maxLength,
                                                   
mustMatchRegEx=mustMatchRegEx,
                                                   canBeNone=canBeNone,
                                                   arcGISType=arcGISType,
                                                   
arcGISAssembly=arcGISAssembly,
                                                   
canBeArcGISInputParameter=canBeArcGISInputParameter,
                                                   
canBeArcGISOutputParameter=canBeArcGISOutputParameter)


class DirectoryTypeMetadata(StoredObjectTypeMetadata):

    def __init__(self,
                 typeDisplayName=_(u'directory'),
                 canBeRelativePath=True,
                 basePathArgument=None,
                 useArcGISWorkspace=True,
                 normalizePath=True,
                 mustBeDifferentThanArguments=None,
                 mustExist=False,
                 mustNotExist=False,
                 deleteIfParameterIsTrue=None,
                 createParentDirectories=False,
                 minLength=1,
                 maxLength=255,
                 mustMatchRegEx=None,
                 canBeNone=False,
                 arcGISType=u'ESRI.ArcGIS.Catalog.DEFolderTypeClass',
                 arcGISAssembly=u'ESRI.ArcGIS.Catalog',
                 canBeArcGISInputParameter=True,
                 canBeArcGISOutputParameter=True):
        
        super(DirectoryTypeMetadata, 
self).__init__(typeDisplayName=typeDisplayName,
                                                    isPath=True,
                                                    
canBeRelativePath=canBeRelativePath,
                                                    
basePathArgument=basePathArgument,
                                                    
useArcGISWorkspace=useArcGISWorkspace,
                                                    
normalizePath=normalizePath,
                                                    
mustBeDifferentThanArguments=mustBeDifferentThanArguments,
                                                    mustExist=mustExist,
                                                    mustNotExist=mustNotExist,
                                                    
deleteIfParameterIsTrue=deleteIfParameterIsTrue,
                                                    
createParentDirectories=createParentDirectories,
                                                    minLength=minLength,
                                                    maxLength=maxLength,
                                                    
mustMatchRegEx=mustMatchRegEx,
                                                    canBeNone=canBeNone,
                                                    arcGISType=arcGISType,
                                                    
arcGISAssembly=arcGISAssembly,
                                                    
canBeArcGISInputParameter=canBeArcGISInputParameter,
                                                    
canBeArcGISOutputParameter=canBeArcGISOutputParameter)

    @classmethod
    def Exists(cls, name, argMetadata=None, methodLocals=None):
        from GeoEco.DataManagement.Directories import Directory
        return Directory.Exists(name)

    @classmethod
    def Delete(cls, name, argMetadata=None, methodLocals=None):
        from GeoEco.DataManagement.Directories import Directory
        Directory.Delete(name, removeTree=True)

    @classmethod
    def Copy(cls, source, dest, overwriteExisting=False, argMetadata=None, 
methodLocals=None):
        from GeoEco.DataManagement.Directories import Directory
        Directory.Copy(source, dest, 
deleteExistingDestinationDirectory=overwriteExisting, 
overwriteExistingFiles=overwriteExisting)


# ArcGIS types


class ArcGISGeoDatasetTypeMetadata(StoredObjectTypeMetadata):

    def __init__(self,
                 typeDisplayName=_(u'geographic dataset'),
                 canBeRelativePath=True,
                 basePathArgument=None,
                 useArcGISWorkspace=True,
                 normalizePath=True,
                 mustBeDifferentThanArguments=None,
                 mustExist=False,
                 mustNotExist=False,
                 deleteIfParameterIsTrue=None,
                 createParentDirectories=False,
                 minLength=1,
                 maxLength=255,
                 mustMatchRegEx=None,
                 canBeNone=False,
                 
arcGISType=u'ESRI.ArcGIS.Geoprocessing.DEGeoDatasetTypeClass',
                 arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing',
                 canBeArcGISInputParameter=True,
                 canBeArcGISOutputParameter=True):
        
        super(ArcGISGeoDatasetTypeMetadata, 
self).__init__(typeDisplayName=typeDisplayName,
                                                           isPath=True,
                                                           
canBeRelativePath=canBeRelativePath,
                                                           
basePathArgument=basePathArgument,
                                                           
useArcGISWorkspace=useArcGISWorkspace,
                                                           
normalizePath=normalizePath,
                                                           
mustBeDifferentThanArguments=mustBeDifferentThanArguments,
                                                           
mustExist=mustExist,
                                                           
mustNotExist=mustNotExist,
                                                           
deleteIfParameterIsTrue=deleteIfParameterIsTrue,
                                                           
createParentDirectories=createParentDirectories,
                                                           
minLength=minLength,
                                                           
maxLength=maxLength,
                                                           
mustMatchRegEx=mustMatchRegEx,
                                                           
canBeNone=canBeNone,
                                                           
arcGISType=arcGISType,
                                                           
arcGISAssembly=arcGISAssembly,
                                                           
canBeArcGISInputParameter=canBeArcGISInputParameter,
                                                           
canBeArcGISOutputParameter=canBeArcGISOutputParameter)

    def _CanonicalizePath(self, value, argMetadata, methodLocals):
        
        # It could be a layer or it could be a path to something.
        # Layers will already exist and do not require
        # canonicalization. If the value already exists, assume it is
        # a layer and return successfully. (Note that it might not be
        # the correct type, but this will be handled by
        # StoredObjectTypeMetadata.ValidateValue).
        
        exists, isCorrectType = self.Exists(value, argMetadata, methodLocals)
        if exists:
            return False, value, exists, isCorrectType

        # It did not exist. Canonicalize it.

        valueChanged, value, exists, isCorrectType = 
super(ArcGISGeoDatasetTypeMetadata, self)._CanonicalizePath(value, 
argMetadata, methodLocals)

        # If the canonicalized form is different than the original, we
        # have to check its existence again later, if necessary.
        # Return None for the existence parameters.
        
        if valueChanged:
            return True, value, None, None

        # The canonicalized form is no different than the orginal.
        # Therefore it will not be necessary to check its existence
        # again later. Return the results of our check.
        
        return False, value, False, False

    @classmethod
    def Exists(cls, name, argMetadata=None, methodLocals=None):

        # See if it exists.
        
        from GeoEco.Logging import Logger
        from GeoEco.ArcGIS import GeoprocessorManager
        gp = GeoprocessorManager.GetWrappedGeoprocessor()
        if gp is None:
            Logger.RaiseException(RuntimeError(_(u'The ArcGIS geoprocessor 
must be initialized before this function may be called. Please call 
GeoprocessorManager.InitializeGeoprocessor or 
GeoprocessorManager.SetGeoprocessor before calling this function.')))
        exists = gp.Exists(name)
        isCorrectType = False

        # If it exists, see if the describe object has an Extent
        # property. If it does, then it is a "geodataset".
        
        if exists:
            d = gp.Describe(name)
            isCorrectType = d is not None and hasattr(d, 'Extent') and 
isinstance(d.Extent, basestring) and len(d.Extent) > 0

        # Log a debug message indicating what happened.
        
        if not exists:
            Logger.Debug(_(u'The geographic dataset %(path)s does not 
exist.') % {u'path': name})
        else:
            if isCorrectType:
                Logger.Debug(_(u'The geographic dataset %(path)s exists.') % 
{u'path': name})
            else:
                Logger.Debug(_(u'%(path)s exists but it is a %(actual)s, not 
a geographic dataset.') % {u'path': name, u'actual': d.DataType})

        # Return the results.
        
        return (exists, isCorrectType)


class ArcGISRasterTypeMetadata(StoredObjectTypeMetadata):

    def __init__(self,
                 allowedPixelTypes=None,
                 typeDisplayName=_(u'raster'),
                 canBeRelativePath=True,
                 basePathArgument=None,
                 useArcGISWorkspace=True,
                 normalizePath=True,
                 mustBeDifferentThanArguments=None,
                 mustExist=False,
                 mustNotExist=False,
                 deleteIfParameterIsTrue=None,
                 createParentDirectories=False,
                 minLength=1,
                 maxLength=255,
                 mustMatchRegEx=None,
                 canBeNone=False,
                 
arcGISType=u'ESRI.ArcGIS.DataSourcesRaster.DERasterDatasetTypeClass',
                 arcGISAssembly=u'ESRI.ArcGIS.DataSourcesRaster',
                 canBeArcGISInputParameter=True,
                 canBeArcGISOutputParameter=True):

        assert isinstance(allowedPixelTypes, (types.NoneType, types.ListType, 
types.TupleType)), u'allowedPixelTypes must be a list or tuple of Unicode 
strings, or None.'
        if isinstance(allowedPixelTypes, types.TupleType):
            allowedPixelTypes = list(allowedPixelTypes)
        if allowedPixelTypes is not None:
            for s in allowedPixelTypes:
                assert isinstance(s, types.UnicodeType), u'allowedPixelTypes 
must be a list or tuple of Unicode strings, or None.'
            self._AllowedPixelTypes = map(unicode.strip, map(unicode.lower, 
allowedPixelTypes))
        else:
            self._AllowedPixelTypes = None
        
        super(ArcGISRasterTypeMetadata, 
self).__init__(typeDisplayName=typeDisplayName,
                                                       isPath=True,
                                                       
canBeRelativePath=canBeRelativePath,
                                                       
basePathArgument=basePathArgument,
                                                       
useArcGISWorkspace=useArcGISWorkspace,
                                                       
normalizePath=normalizePath,
                                                       
mustBeDifferentThanArguments=mustBeDifferentThanArguments,
                                                       mustExist=mustExist,
                                                       
mustNotExist=mustNotExist,
                                                       
deleteIfParameterIsTrue=deleteIfParameterIsTrue,
                                                       
createParentDirectories=createParentDirectories,
                                                       minLength=minLength,
                                                       maxLength=maxLength,
                                                       
mustMatchRegEx=mustMatchRegEx,
                                                       canBeNone=canBeNone,
                                                       arcGISType=arcGISType,
                                                       
arcGISAssembly=arcGISAssembly,
                                                       
canBeArcGISInputParameter=canBeArcGISInputParameter,
                                                       
canBeArcGISOutputParameter=canBeArcGISOutputParameter)

    def _GetAllowedPixelTypes(self):
        return self._AllowedPixelTypes
    
    AllowedPixelTypes = property(_GetAllowedPixelTypes, 
doc=DynamicDocString())

    def AppendXMLNodes(self, node, document):
        super(ArcGISRasterTypeMetadata, self).AppendXMLNodes(node, document)
        allowedPixelTypesNode = 
node.appendChild(document.createElement(u'AllowedPixelTypes'))
        if self.AllowedPixelTypes is not None:
            listNode = 
allowedPixelTypesNode.appendChild(document.createElement(u'ArrayList'))
            for i in range(len(self.AllowedPixelTypes)):
                self.AppendXMLNodesForValue(self.AllowedPixelTypes[i], 
listNode, document)

    def ValidateValue(self, value, variableName, methodLocals=None, 
argMetadata=None):
        (valueChanged, value) = super(ArcGISRasterTypeMetadata, 
self).ValidateValue(value, variableName, methodLocals, argMetadata)
        if value is not None and self.AllowedPixelTypes is not None:
            from GeoEco.ArcGIS import GeoprocessorManager
            gp = GeoprocessorManager.GetWrappedGeoprocessor()
            if gp.Exists(value) and gp.Describe(value).PixelType.lower() not 
in self.AllowedPixelTypes:
                if len(self.AllowedPixelTypes) == 1:
                    _RaiseException(ValueError(_(u'The %(type)s %(value)s, 
specified for the %(variable)s, is a %(pt)s %(type)s but this function 
requires a %(allowed)s %(type)s. Please provide a %(allowed)s %(type)s.') % 
{u'type' : self.TypeDisplayName, u'value' : value, u'variable' : 
variableName, u'pt': self.GetPixelTypeName(gp.Describe(value).PixelType), 
u'allowed': self.GetPixelTypeName(self.AllowedPixelTypes[0])}))
                else:
                    _RaiseException(ValueError(_(u'The %(type)s %(value)s, 
specified for the %(variable)s, is a %(pt)s %(type)s but this function 
requires a %(type)s with one of the following pixel types: %(allowed)s. 
Please provide a %(type)s with an allowed pixel type.') % {u'type' : 
self.TypeDisplayName, u'value' : value, u'variable' : variableName, u'pt': 
self.GetPixelTypeName(gp.Describe(value).PixelType), u'allowed': unicode('\', 
\''.join(map(self.GetPixelTypeName, self.AllowedPixelTypes)))}))
        return (valueChanged, value)

    def GetPixelTypeName(self, pixelType):
        name = _(u'unknown data type')
        if isinstance(pixelType, basestring) and len(pixelType) >= 2:
            if pixelType[0] == u'u' or pixelType[0] == u'U':
                name = _('%s-bit unsigned integer') % pixelType[1:]
            elif pixelType[0] == u's' or pixelType[0] == u'S':
                name = _('%s-bit signed integer') % pixelType[1:]
            elif pixelType[0] == u'f' or pixelType[0] == u'F':
                name = _('%s-bit floating point') % pixelType[1:]
        return name

    @classmethod
    def Exists(cls, name, argMetadata=None, methodLocals=None):
        from GeoEco.DataManagement.ArcGISRasters import ArcGISRaster
        return ArcGISRaster.Exists(name)

    @classmethod
    def Delete(cls, name, argMetadata=None, methodLocals=None):
        from GeoEco.DataManagement.ArcGISRasters import ArcGISRaster
        ArcGISRaster.Delete(name)

    @classmethod
    def Copy(cls, source, dest, overwriteExisting=False, argMetadata=None, 
methodLocals=None):
        from GeoEco.DataManagement.ArcGISRasters import ArcGISRaster
        ArcGISRaster.Copy(source, dest, overwriteExisting=overwriteExisting)


class ArcGISRasterLayerTypeMetadata(ArcGISRasterTypeMetadata):

    def __init__(self,
                 allowedPixelTypes=None,
                 typeDisplayName=_(u'raster or raster layer'),
                 canBeRelativePath=True,
                 basePathArgument=None,
                 useArcGISWorkspace=True,
                 normalizePath=True,
                 mustBeDifferentThanArguments=None,
                 mustExist=False,
                 minLength=1,
                 maxLength=255,
                 mustMatchRegEx=None,
                 canBeNone=False,
                 
arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPRasterLayerTypeClass',
                 arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing'):
        
        super(ArcGISRasterLayerTypeMetadata, 
self).__init__(allowedPixelTypes=allowedPixelTypes,
                                                            
typeDisplayName=typeDisplayName,
                                                            
canBeRelativePath=canBeRelativePath,
                                                            
basePathArgument=basePathArgument,
                                                            
useArcGISWorkspace=useArcGISWorkspace,
                                                            
normalizePath=normalizePath,
                                                            
mustBeDifferentThanArguments=mustBeDifferentThanArguments,
                                                            
mustExist=mustExist,
                                                            
minLength=minLength,
                                                            
maxLength=maxLength,
                                                            
mustMatchRegEx=mustMatchRegEx,
                                                            
canBeNone=canBeNone,
                                                            
arcGISType=arcGISType,
                                                            
arcGISAssembly=arcGISAssembly)

    def _CanonicalizePath(self, value, argMetadata, methodLocals):
        
        # It could be a layer or it could be a path to something.
        # Layers will already exist and do not require
        # canonicalization. If the value already exists, assume it is
        # a layer and return successfully. (Note that it might not be
        # the correct type, but this will be handled by
        # StoredObjectTypeMetadata.ValidateValue).
        
        exists, isCorrectType = self.Exists(value, argMetadata, methodLocals)
        if exists:
            return False, value, exists, isCorrectType

        # It did not exist. Canonicalize it.

        valueChanged, value, exists, isCorrectType = 
super(ArcGISRasterLayerTypeMetadata, self)._CanonicalizePath(value, 
argMetadata, methodLocals)

        # If the canonicalized form is different than the original, we
        # have to check its existence again later, if necessary.
        # Return None for the existence parameters.
        
        if valueChanged:
            return True, value, None, None

        # The canonicalized form is no different than the orginal.
        # Therefore it will not be necessary to check its existence
        # again later. Return the results of our check.
        
        return False, value, False, False

    @classmethod
    def Exists(cls, name, argMetadata=None, methodLocals=None):
        from GeoEco.ArcGIS import GeoprocessorManager
        return GeoprocessorManager.ArcGISObjectExists(name, 
[u'rasterdataset', u'rasterlayer', u'rasterband'], _(u'ArcGIS raster, raster 
layer, or raster band'))


class ArcGISFeatureClassTypeMetadata(StoredObjectTypeMetadata):

    def __init__(self,
                 allowedShapeTypes=None,
                 typeDisplayName=_(u'feature class'),
                 canBeRelativePath=True,
                 basePathArgument=None,
                 useArcGISWorkspace=True,
                 normalizePath=True,
                 mustBeDifferentThanArguments=None,
                 mustExist=False,
                 mustNotExist=False,
                 deleteIfParameterIsTrue=None,
                 createParentDirectories=False,
                 minLength=1,
                 maxLength=255,
                 mustMatchRegEx=None,
                 canBeNone=False,
                 
arcGISType=u'ESRI.ArcGIS.Geodatabase.DEFeatureClassTypeClass',
                 arcGISAssembly=u'ESRI.ArcGIS.Geodatabase',
                 canBeArcGISInputParameter=True,
                 canBeArcGISOutputParameter=True):

        assert isinstance(allowedShapeTypes, (types.NoneType, types.ListType, 
types.TupleType)), u'allowedShapeTypes must be a list or tuple of Unicode 
strings, or None.'
        if isinstance(allowedShapeTypes, types.TupleType):
            allowedShapeTypes = list(allowedShapeTypes)
        if allowedShapeTypes is not None:
            for s in allowedShapeTypes:
                assert isinstance(s, types.UnicodeType), u'allowedShapeTypes 
must be a list or tuple of Unicode strings, or None.'
            self._AllowedShapeTypes = map(unicode.strip, map(unicode.lower, 
allowedShapeTypes))
        else:
            self._AllowedShapeTypes = None
                
        super(ArcGISFeatureClassTypeMetadata, 
self).__init__(typeDisplayName=typeDisplayName,
                                                             isPath=True,
                                                             
canBeRelativePath=canBeRelativePath,
                                                             
basePathArgument=basePathArgument,
                                                             
useArcGISWorkspace=useArcGISWorkspace,
                                                             
normalizePath=normalizePath,
                                                             
mustBeDifferentThanArguments=mustBeDifferentThanArguments,
                                                             
mustExist=mustExist,
                                                             
mustNotExist=mustNotExist,
                                                             
deleteIfParameterIsTrue=deleteIfParameterIsTrue,
                                                             
createParentDirectories=createParentDirectories,
                                                             
minLength=minLength,
                                                             
maxLength=maxLength,
                                                             
mustMatchRegEx=mustMatchRegEx,
                                                             
canBeNone=canBeNone,
                                                             
arcGISType=arcGISType,
                                                             
arcGISAssembly=arcGISAssembly,
                                                             
canBeArcGISInputParameter=canBeArcGISInputParameter,
                                                             
canBeArcGISOutputParameter=canBeArcGISOutputParameter)

    def _GetAllowedShapeTypes(self):
        return self._AllowedShapeTypes
    
    AllowedShapeTypes = property(_GetAllowedShapeTypes, 
doc=DynamicDocString())

    def AppendXMLNodes(self, node, document):
        super(ArcGISFeatureClassTypeMetadata, self).AppendXMLNodes(node, 
document)
        allowedShapeTypesNode = 
node.appendChild(document.createElement(u'AllowedShapeTypes'))
        if self.AllowedShapeTypes is not None:
            listNode = 
allowedShapeTypesNode.appendChild(document.createElement(u'ArrayList'))
            for i in range(len(self.AllowedShapeTypes)):
                self.AppendXMLNodesForValue(self.AllowedShapeTypes[i], 
listNode, document)

    def ValidateValue(self, value, variableName, methodLocals=None, 
argMetadata=None):
        (valueChanged, value) = super(ArcGISFeatureClassTypeMetadata, 
self).ValidateValue(value, variableName, methodLocals, argMetadata)
        if value is not None and self.AllowedShapeTypes is not None:
            from GeoEco.ArcGIS import GeoprocessorManager
            gp = GeoprocessorManager.GetWrappedGeoprocessor()
            if gp.Exists(value) and gp.Describe(value).ShapeType.lower() not 
in self.AllowedShapeTypes:
                if len(self.AllowedShapeTypes) == 1:
                    _RaiseException(ValueError(_(u'The %(type)s %(value)s, 
specified for the %(variable)s, has the shape type \'%(shape)s\', but this 
function requires a %(type)s with the shape type \'%(allowed)s\'. Please 
provide a %(type)s with shape type \'%(allowed)s\'.') % {u'type' : 
self.TypeDisplayName, u'value' : value, u'variable' : variableName, u'shape': 
gp.Describe(value).ShapeType.lower(), u'allowed': self.AllowedShapeTypes[0]}))
                else:
                    _RaiseException(ValueError(_(u'The %(type)s %(value)s, 
specified for the %(variable)s, has the shape type \'%(shape)s\', but this 
function requires a %(type)s with one of the following shape types: 
\'%(allowed)s\'. Please provide a %(type)s with an allowed shape type.') % 
{u'type' : self.TypeDisplayName, u'value' : value, u'variable' : 
variableName, u'shape': gp.Describe(value).ShapeType.lower(), u'allowed': 
unicode('\', \''.join(map(str, self.AllowedShapeTypes)))}))
        return (valueChanged, value)

    @classmethod
    def Exists(cls, name, argMetadata=None, methodLocals=None):
        from GeoEco.ArcGIS import GeoprocessorManager
        return GeoprocessorManager.ArcGISObjectExists(name, [u'featureclass', 
u'shapefile'], _(u'ArcGIS feature class'))

    @classmethod
    def Delete(cls, name, argMetadata=None, methodLocals=None):
        from GeoEco.ArcGIS import GeoprocessorManager
        GeoprocessorManager.DeleteArcGISObject(name, [u'featureclass', 
u'shapefile'], _(u'ArcGIS feature class'))

    @classmethod
    def Copy(cls, source, dest, overwriteExisting=False, argMetadata=None, 
methodLocals=None):
        from GeoEco.ArcGIS import GeoprocessorManager
        GeoprocessorManager.CopyArcGISObject(source, dest, overwriteExisting, 
[u'featureclass', u'shapefile'], _(u'ArcGIS feature class'))


class ArcGISFeatureLayerTypeMetadata(ArcGISFeatureClassTypeMetadata):

    def __init__(self,
                 allowedShapeTypes=None,
                 typeDisplayName=_(u'feature class or layer'),
                 canBeRelativePath=True,
                 basePathArgument=None,
                 useArcGISWorkspace=True,
                 normalizePath=True,
                 mustBeDifferentThanArguments=None,
                 mustExist=False,
                 minLength=1,
                 maxLength=255,
                 mustMatchRegEx=None,
                 canBeNone=False,
                 
arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPFeatureLayerTypeClass',
                 arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing'):
                
        super(ArcGISFeatureLayerTypeMetadata, 
self).__init__(allowedShapeTypes=allowedShapeTypes,
                                                             
typeDisplayName=typeDisplayName,
                                                             
canBeRelativePath=canBeRelativePath,
                                                             
basePathArgument=basePathArgument,
                                                             
useArcGISWorkspace=useArcGISWorkspace,
                                                             
normalizePath=normalizePath,
                                                             
mustBeDifferentThanArguments=mustBeDifferentThanArguments,
                                                             
mustExist=mustExist,
                                                             
minLength=minLength,
                                                             
maxLength=maxLength,
                                                             
mustMatchRegEx=mustMatchRegEx,
                                                             
canBeNone=canBeNone,
                                                             
arcGISType=arcGISType,
                                                             
arcGISAssembly=arcGISAssembly)

    def _CanonicalizePath(self, value, argMetadata, methodLocals):
        
        # It could be a layer or it could be a path to something.
        # Layers will already exist and do not require
        # canonicalization. If the value already exists, assume it is
        # a layer and return successfully. (Note that it might not be
        # the correct type, but this will be handled by
        # StoredObjectTypeMetadata.ValidateValue).
        
        exists, isCorrectType = self.Exists(value, argMetadata, methodLocals)
        if exists:
            return False, value, exists, isCorrectType

        # It did not exist. Canonicalize it.

        valueChanged, value, exists, isCorrectType = 
super(ArcGISFeatureLayerTypeMetadata, self)._CanonicalizePath(value, 
argMetadata, methodLocals)

        # If the canonicalized form is different than the original, we
        # have to check its existence again later, if necessary.
        # Return None for the existence parameters.
        
        if valueChanged:
            return True, value, None, None

        # The canonicalized form is no different than the orginal.
        # Therefore it will not be necessary to check its existence
        # again later. Return the results of our check.
        
        return False, value, False, False

    @classmethod
    def Exists(cls, name, argMetadata=None, methodLocals=None):
        from GeoEco.ArcGIS import GeoprocessorManager
        return GeoprocessorManager.ArcGISObjectExists(name, [u'featureclass', 
u'shapefile', u'featurelayer'], _(u'ArcGIS feature class or layer'))


class ShapefileTypeMetadata(FileTypeMetadata):

    def __init__(self,
                 typeDisplayName=_(u'shapefile'),
                 canBeRelativePath=True,
                 basePathArgument=None,
                 useArcGISWorkspace=True,
                 normalizePath=True,
                 mustBeDifferentThanArguments=None,
                 mustExist=False,
                 mustNotExist=False,
                 deleteIfParameterIsTrue=None,
                 createParentDirectories=False,
                 minLength=1,
                 maxLength=255,
                 mustMatchRegEx=u'.+\.[Ss][Hh][Pp]$',
                 canBeNone=False,
                 arcGISType=u'ESRI.ArcGIS.Catalog.DEShapeFileTypeClass',
                 arcGISAssembly=u'ESRI.ArcGIS.Catalog',
                 canBeArcGISInputParameter=True,
                 canBeArcGISOutputParameter=True):
        
        super(ShapefileTypeMetadata, 
self).__init__(typeDisplayName=typeDisplayName,
                                                    
canBeRelativePath=canBeRelativePath,
                                                    
basePathArgument=basePathArgument,
                                                    
useArcGISWorkspace=useArcGISWorkspace,
                                                    
normalizePath=normalizePath,
                                                    
mustBeDifferentThanArguments=mustBeDifferentThanArguments,
                                                    mustExist=mustExist,
                                                    mustNotExist=mustNotExist,
                                                    
deleteIfParameterIsTrue=deleteIfParameterIsTrue,
                                                    
createParentDirectories=createParentDirectories,
                                                    minLength=minLength,
                                                    maxLength=maxLength,
                                                    
mustMatchRegEx=mustMatchRegEx,
                                                    canBeNone=canBeNone,
                                                    arcGISType=arcGISType,
                                                    
arcGISAssembly=arcGISAssembly,
                                                    
canBeArcGISInputParameter=canBeArcGISInputParameter,
                                                    
canBeArcGISOutputParameter=canBeArcGISOutputParameter)

    @classmethod
    def Exists(cls, name, argMetadata=None, methodLocals=None):
        from GeoEco.DataManagement.Shapefiles import Shapefile
        return Shapefile.Exists(name)

    @classmethod
    def Delete(cls, name, argMetadata=None, methodLocals=None):
        from GeoEco.DataManagement.Shapefiles import Shapefile
        Shapefile.Delete(name)

    @classmethod
    def Copy(cls, source, dest, overwriteExisting=False, argMetadata=None, 
methodLocals=None):
        from GeoEco.DataManagement.Shapefiles import Shapefile
        Shapefile.Copy(source, dest, overwriteExisting=overwriteExisting)


class ArcGISWorkspaceTypeMetadata(StoredObjectTypeMetadata):

    def __init__(self,
                 typeDisplayName=_(u'workspace'),
                 canBeRelativePath=True,
                 basePathArgument=None,
                 useArcGISWorkspace=True,
                 normalizePath=True,
                 mustBeDifferentThanArguments=None,
                 mustExist=False,
                 mustNotExist=False,
                 deleteIfParameterIsTrue=None,
                 createParentDirectories=False,
                 minLength=1,
                 maxLength=255,
                 mustMatchRegEx=None,
                 canBeNone=False,
                 arcGISType=u'ESRI.ArcGIS.Geodatabase.DEWorkspaceTypeClass',
                 arcGISAssembly=u'ESRI.ArcGIS.Geodatabase',
                 canBeArcGISInputParameter=True,
                 canBeArcGISOutputParameter=True):
        
        super(ArcGISWorkspaceTypeMetadata, 
self).__init__(typeDisplayName=typeDisplayName,
                                                          isPath=True,
                                                          
canBeRelativePath=canBeRelativePath,
                                                          
basePathArgument=basePathArgument,
                                                          
useArcGISWorkspace=useArcGISWorkspace,
                                                          
normalizePath=normalizePath,
                                                          
mustBeDifferentThanArguments=mustBeDifferentThanArguments,
                                                          mustExist=mustExist,
                                                          
mustNotExist=mustNotExist,
                                                          
deleteIfParameterIsTrue=deleteIfParameterIsTrue,
                                                          
createParentDirectories=createParentDirectories,
                                                          minLength=minLength,
                                                          maxLength=maxLength,
                                                          
mustMatchRegEx=mustMatchRegEx,
                                                          canBeNone=canBeNone,
                                                          
arcGISType=arcGISType,
                                                          
arcGISAssembly=arcGISAssembly,
                                                          
canBeArcGISInputParameter=canBeArcGISInputParameter,
                                                          
canBeArcGISOutputParameter=canBeArcGISOutputParameter)

    @classmethod
    def Exists(cls, name, argMetadata=None, methodLocals=None):
        from GeoEco.ArcGIS import GeoprocessorManager
        return GeoprocessorManager.ArcGISObjectExists(name, [u'workspace', 
u'folder'], _(u'ArcGIS workspace'))

    @classmethod
    def Delete(cls, name, argMetadata=None, methodLocals=None):
        from GeoEco.ArcGIS import GeoprocessorManager
        GeoprocessorManager.DeleteArcGISObject(name, [u'workspace', 
u'folder'], _(u'ArcGIS workspace'))

    @classmethod
    def Copy(cls, source, dest, overwriteExisting=False, argMetadata=None, 
methodLocals=None):
        from GeoEco.ArcGIS import GeoprocessorManager
        GeoprocessorManager.CopyArcGISObject(source, dest, overwriteExisting, 
[u'workspace', u'folder'], _(u'ArcGIS workspace'))


class ArcGISTableTypeMetadata(StoredObjectTypeMetadata):

    def __init__(self,
                 typeDisplayName=_(u'table'),
                 canBeRelativePath=True,
                 basePathArgument=None,
                 useArcGISWorkspace=True,
                 normalizePath=True,
                 mustBeDifferentThanArguments=None,
                 mustExist=False,
                 mustNotExist=False,
                 deleteIfParameterIsTrue=None,
                 createParentDirectories=False,
                 minLength=1,
                 maxLength=255,
                 mustMatchRegEx=None,
                 canBeNone=False,
                 arcGISType=u'ESRI.ArcGIS.Geodatabase.DETableTypeClass',
                 arcGISAssembly=u'ESRI.ArcGIS.Geodatabase',
                 canBeArcGISInputParameter=True,
                 canBeArcGISOutputParameter=True):
        
        super(ArcGISTableTypeMetadata, 
self).__init__(typeDisplayName=typeDisplayName,
                                                      isPath=True,
                                                      
canBeRelativePath=canBeRelativePath,
                                                      
basePathArgument=basePathArgument,
                                                      
useArcGISWorkspace=useArcGISWorkspace,
                                                      
normalizePath=normalizePath,
                                                      
mustBeDifferentThanArguments=mustBeDifferentThanArguments,
                                                      mustExist=mustExist,
                                                      
mustNotExist=mustNotExist,
                                                      
deleteIfParameterIsTrue=deleteIfParameterIsTrue,
                                                      
createParentDirectories=createParentDirectories,
                                                      minLength=minLength,
                                                      maxLength=maxLength,
                                                      
mustMatchRegEx=mustMatchRegEx,
                                                      canBeNone=canBeNone,
                                                      arcGISType=arcGISType,
                                                      
arcGISAssembly=arcGISAssembly,
                                                      
canBeArcGISInputParameter=canBeArcGISInputParameter,
                                                      
canBeArcGISOutputParameter=canBeArcGISOutputParameter)

    @classmethod
    def Exists(cls, name, argMetadata=None, methodLocals=None):
        from GeoEco.ArcGIS import GeoprocessorManager
        return GeoprocessorManager.ArcGISObjectExists(name, [u'table', 
u'dbasetable', u'textfile', u'featureclass', u'shapefile', 
u'relationshipclass', u'rastercatalog', u'coveragefeatureclass', 
u'tableview', u'featurelayer', u'layer'], _(u'ArcGIS table'))

    @classmethod
    def Delete(cls, name, argMetadata=None, methodLocals=None):
        from GeoEco.ArcGIS import GeoprocessorManager
        GeoprocessorManager.DeleteArcGISObject(name, [u'table', 
u'dbasetable', u'textfile', u'featureclass', u'shapefile', 
u'relationshipclass', u'rastercatalog', u'coveragefeatureclass', 
u'tableview', u'featurelayer', u'layer'], _(u'ArcGIS table'))

    @classmethod
    def Copy(cls, source, dest, overwriteExisting=False, argMetadata=None, 
methodLocals=None):
        from GeoEco.ArcGIS import GeoprocessorManager
        GeoprocessorManager.CopyArcGISObject(source, dest, overwriteExisting, 
[u'table', u'dbasetable', u'textfile', u'shapefile', u'featureclass', 
u'relationshipclass', u'rastercatalog', u'coveragefeatureclass', 
u'tableview', u'featurelayer', u'layer'], _(u'ArcGIS table'))


class ArcGISTableViewTypeMetadata(ArcGISTableTypeMetadata):

    def __init__(self,
                 typeDisplayName=_(u'table or table view'),
                 canBeRelativePath=True,
                 basePathArgument=None,
                 useArcGISWorkspace=True,
                 normalizePath=True,
                 mustBeDifferentThanArguments=None,
                 mustExist=False,
                 minLength=1,
                 maxLength=255,
                 mustMatchRegEx=None,
                 canBeNone=False,
                 arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPTableViewTypeClass',
                 arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing'):
        
        super(ArcGISTableViewTypeMetadata, 
self).__init__(typeDisplayName=typeDisplayName,
                                                          
canBeRelativePath=canBeRelativePath,
                                                          
basePathArgument=basePathArgument,
                                                          
useArcGISWorkspace=useArcGISWorkspace,
                                                          
normalizePath=normalizePath,
                                                          
mustBeDifferentThanArguments=mustBeDifferentThanArguments,
                                                          mustExist=mustExist,
                                                          minLength=minLength,
                                                          maxLength=maxLength,
                                                          
mustMatchRegEx=mustMatchRegEx,
                                                          canBeNone=canBeNone,
                                                          
arcGISType=arcGISType,
                                                          
arcGISAssembly=arcGISAssembly)

    def _CanonicalizePath(self, value, argMetadata, methodLocals):
        
        # It could be a layer or it could be a path to something.
        # Layers will already exist and do not require
        # canonicalization. If the value already exists, assume it is
        # a layer and return successfully. (Note that it might not be
        # the correct type, but this will be handled by
        # StoredObjectTypeMetadata.ValidateValue).
        
        exists, isCorrectType = self.Exists(value, argMetadata, methodLocals)
        if exists:
            return False, value, exists, isCorrectType

        # It did not exist. Canonicalize it.

        valueChanged, value, exists, isCorrectType = 
super(ArcGISTableViewTypeMetadata, self)._CanonicalizePath(value, 
argMetadata, methodLocals)

        # If the canonicalized form is different than the original, we
        # have to check its existence again later, if necessary.
        # Return None for the existence parameters.
        
        if valueChanged:
            return True, value, None, None

        # The canonicalized form is no different than the orginal.
        # Therefore it will not be necessary to check its existence
        # again later. Return the results of our check.
        
        return False, value, False, False

    @classmethod
    def Exists(cls, name, argMetadata=None, methodLocals=None):
        from GeoEco.ArcGIS import GeoprocessorManager
        return GeoprocessorManager.ArcGISObjectExists(name, [u'table', 
u'dbasetable', u'textfile', u'featureclass', u'shapefile', 
u'relationshipclass', u'rastercatalog', u'coveragefeatureclass', 
u'tableview', u'featurelayer', u'layer'], _(u'ArcGIS table or table view'))


class ArcGISFieldTypeMetadata(StoredObjectTypeMetadata):

    def __init__(self,
                 allowedFieldTypes=None,
                 typeDisplayName=_(u'field'),
                 mustBeDifferentThanArguments=None,
                 mustExist=False,
                 mustNotExist=False,
                 deleteIfParameterIsTrue=None,
                 minLength=1,
                 maxLength=255,
                 mustMatchRegEx=None,
                 canBeNone=False,
                 arcGISType=u'ESRI.ArcGIS.Geodatabase.FieldTypeClass',
                 arcGISAssembly=u'ESRI.ArcGIS.Geodatabase',
                 canBeArcGISInputParameter=True,
                 canBeArcGISOutputParameter=True):

        assert isinstance(allowedFieldTypes, (types.NoneType, types.ListType, 
types.TupleType)), u'allowedFieldTypes must be a list or tuple of Unicode 
strings, or None.'
        if isinstance(allowedFieldTypes, types.TupleType):
            allowedFieldTypes = list(allowedFieldTypes)
        if allowedFieldTypes is not None:
            for s in allowedFieldTypes:
                assert isinstance(s, types.UnicodeType), u'allowedFieldTypes 
must be a list or tuple of Unicode strings, or None.'
            self._AllowedFieldTypes = map(unicode.strip, map(unicode.lower, 
allowedFieldTypes))
        else:
            self._AllowedFieldTypes = None
        
        super(ArcGISFieldTypeMetadata, 
self).__init__(typeDisplayName=typeDisplayName,
                                                      isPath=False,
                                                      canBeRelativePath=False,
                                                      basePathArgument=None,
                                                      
useArcGISWorkspace=False,
                                                      normalizePath=False,
                                                      
mustBeDifferentThanArguments=mustBeDifferentThanArguments,
                                                      mustExist=mustExist,
                                                      
mustNotExist=mustNotExist,
                                                      
deleteIfParameterIsTrue=deleteIfParameterIsTrue,
                                                      
createParentDirectories=False,
                                                      minLength=minLength,
                                                      maxLength=maxLength,
                                                      
mustMatchRegEx=mustMatchRegEx,
                                                      canBeNone=canBeNone,
                                                      arcGISType=arcGISType,
                                                      
arcGISAssembly=arcGISAssembly,
                                                      
canBeArcGISInputParameter=canBeArcGISInputParameter,
                                                      
canBeArcGISOutputParameter=canBeArcGISOutputParameter)

    def _GetAllowedFieldTypes(self):
        return self._AllowedFieldTypes
    
    AllowedFieldTypes = property(_GetAllowedFieldTypes, 
doc=DynamicDocString())

    def AppendXMLNodes(self, node, document):
        super(ArcGISFieldTypeMetadata, self).AppendXMLNodes(node, document)
        allowedFieldTypesNode = 
node.appendChild(document.createElement(u'AllowedFieldTypes'))
        if self.AllowedFieldTypes is not None:
            listNode = 
allowedFieldTypesNode.appendChild(document.createElement(u'ArrayList'))
            for i in range(len(self.AllowedFieldTypes)):
                self.AppendXMLNodesForValue(self.AllowedFieldTypes[i], 
listNode, document)

    def ValidateValue(self, value, variableName, methodLocals=None, 
argMetadata=None):
        (valueChanged, value) = super(ArcGISFieldTypeMetadata, 
self).ValidateValue(value, variableName, methodLocals, argMetadata)
        if value is not None and self.AllowedFieldTypes is not None and 
methodLocals is not None and argMetadata.ArcGISParameterDependencies is not 
None and len(argMetadata.ArcGISParameterDependencies) > 0 and 
methodLocals[argMetadata.ArcGISParameterDependencies[0]] is not None:
            from GeoEco.DatabaseAccess.ArcGIS import 
ArcGIS91DatabaseConnection
            conn = ArcGIS91DatabaseConnection()
            fieldDataType = 
conn.GetFieldDataType(methodLocals[argMetadata.ArcGISParameterDependencies[0]],
 value)
            if fieldDataType is not None and fieldDataType.lower() not in 
self.AllowedFieldTypes:
                if len(self.AllowedFieldTypes) == 1:
                    _RaiseException(ValueError(_(u'The %(type)s %(value)s, 
specified for the %(variable)s, has the data type \'%(dt)s\', but this 
function requires a %(type)s with the data type \'%(allowed)s\'. Please 
provide a %(type)s with data type \'%(allowed)s\'.') % {u'type' : 
self.TypeDisplayName, u'value' : 
os.path.join(methodLocals[argMetadata.ArcGISParameterDependencies[0]], 
value), u'variable' : variableName, u'dt': fieldDataType, u'allowed': 
self.AllowedFieldTypes[0]}))
                else:
                    _RaiseException(ValueError(_(u'The %(type)s %(value)s, 
specified for the %(variable)s, has the data type \'%(dt)s\', but this 
function requires a %(type)s with one of the following data types: 
\'%(allowed)s\'. Please provide a %(type)s with an allowed data type.') % 
{u'type' : self.TypeDisplayName, u'value' : 
os.path.join(methodLocals[argMetadata.ArcGISParameterDependencies[0]], 
value), u'variable' : variableName, u'dt': fieldDataType, u'allowed': 
unicode('\', \''.join(map(str, self.AllowedFieldTypes)))}))
        return (valueChanged, value)

    @classmethod
    def Exists(cls, name, argMetadata=None, methodLocals=None):
        assert methodLocals is not None and argMetadata is not None and 
argMetadata.ArcGISParameterDependencies is not None and 
len(argMetadata.ArcGISParameterDependencies) == 1, 
u'ArcGISFieldTypeMetadata.Exists requires that methodLocals and argMetadata 
be provided, and that argMetadata.ArcGISParameterDependencies[0] be set to 
the parameter that specifies the field\'s table.'
        from GeoEco.DatabaseAccess.ArcGIS import ArcGIS91DatabaseConnection
        conn = ArcGIS91DatabaseConnection()
        exists = 
conn.FieldExists(methodLocals[argMetadata.ArcGISParameterDependencies[0]], 
name)
        return exists, exists

    @classmethod
    def Delete(cls, name, argMetadata=None, methodLocals=None):
        assert methodLocals is not None and argMetadata is not None and 
argMetadata.ArcGISParameterDependencies is not None and 
len(argMetadata.ArcGISParameterDependencies) == 1, 
u'ArcGISFieldTypeMetadata.Delete requires that methodLocals and argMetadata 
be provided, and that argMetadata.ArcGISParameterDependencies[0] be set to 
the parameter that specifies the field\'s table.'
        from GeoEco.DatabaseAccess.ArcGIS import ArcGIS91DatabaseConnection
        conn = ArcGIS91DatabaseConnection()
        
conn.DeleteField(methodLocals[argMetadata.ArcGISParameterDependencies[0]], 
name)

    @classmethod
    def Copy(cls, source, dest, overwriteExisting=False, argMetadata=None, 
methodLocals=None):
        _RaiseException(NotImplementedError(u'ArcGISFieldTypeMetadata.Copy is 
not implemented.'))


class CoordinateSystemTypeMetadata(UnicodeStringTypeMetadata):
    
    def __init__(self, canBeNone=False):
        super(CoordinateSystemTypeMetadata, self).__init__(minLength=1,
                                                           
maxLength=2147483647,
                                                           
mustMatchRegEx=None,
                                                           
canBeNone=canBeNone,
                                                           
arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPCoordinateSystemTypeClass',
                                                           
arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing',
                                                           
canBeArcGISInputParameter=True,
                                                           
canBeArcGISOutputParameter=True)


class EnvelopeTypeMetadata(UnicodeStringTypeMetadata):
    
    def __init__(self, canBeNone=False):
        super(EnvelopeTypeMetadata, self).__init__(minLength=1,
                                                   maxLength=2147483647,
                                                   
mustMatchRegEx=u'([-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?)\\s+([-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?)\\s+([-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?)\\s+([-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?)',
                                                   canBeNone=canBeNone,
                                                   
arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPEnvelopeTypeClass',
                                                   
arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing',
                                                   
canBeArcGISInputParameter=True,
                                                   
canBeArcGISOutputParameter=True)

    @classmethod
    def ParseCoordinatesFromString(cls, value):
        if value is None:
            return None, None, None, None
        assert isinstance(value, basestring), u'value must be a string, or 
None'
        coords = value.split()
        return float(coords[0]), float(coords[1]), float(coords[2]), 
float(coords[3])       # left, bottom, right, top


class LinearUnitTypeMetadata(UnicodeStringTypeMetadata):
    
    def __init__(self, canBeNone=False):
        super(LinearUnitTypeMetadata, self).__init__(minLength=1,
                                                     maxLength=2147483647,
                                                     mustMatchRegEx=None,
                                                     canBeNone=canBeNone,
                                                     
arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPLinearUnitTypeClass',
                                                     
arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing',
                                                     
canBeArcGISInputParameter=True,
                                                     
canBeArcGISOutputParameter=True)
        
class MapAlgebraExpressionTypeMetadata(UnicodeStringTypeMetadata):
    
    def __init__(self, canBeNone=False):
        super(MapAlgebraExpressionTypeMetadata, self).__init__(minLength=1,
                                                               maxLength=4000,
                                                               
mustMatchRegEx=None,
                                                               
canBeNone=canBeNone,
                                                               
arcGISType=u'ESRI.ArcGIS.SpatialAnalystUI.GPSAMapAlgebraExpTypeClass',
                                                               
arcGISAssembly=u'ESRI.ArcGIS.SpatialAnalystUI',
                                                               
canBeArcGISInputParameter=True,
                                                               
canBeArcGISOutputParameter=True)
        
class PointTypeMetadata(UnicodeStringTypeMetadata):
    
    def __init__(self, canBeNone=False):
        super(PointTypeMetadata, self).__init__(minLength=1,
                                                               
mustMatchRegEx=u'([-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?)\\s+([-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?)',
                                                               
canBeNone=canBeNone,
                                                               
arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPPointTypeClass',
                                                               
arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing',
                                                               
canBeArcGISInputParameter=True,
                                                               
canBeArcGISOutputParameter=True)

    @classmethod
    def ParseCoordinatesFromString(cls, value):
        if value is None:
            return None, None
        assert isinstance(value, basestring), u'value must be a string, or 
None'
        coords = value.split()
        return float(coords[0]), float(coords[1])


class SpatialReferenceTypeMetadata(UnicodeStringTypeMetadata):
    
    def __init__(self, canBeNone=False):
        super(SpatialReferenceTypeMetadata, self).__init__(minLength=1,
                                                           
maxLength=2147483647,
                                                           
mustMatchRegEx=None,
                                                           
canBeNone=canBeNone,
                                                           
arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPSpatialReferenceTypeClass',
                                                           
arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing',
                                                           
canBeArcGISInputParameter=True,
                                                           
canBeArcGISOutputParameter=True)

    def ValidateValue(self, value, variableName, methodLocals=None, 
argMetadata=None):
        from GeoEco.ArcGIS import _ArcGISObjectWrapper
        if isinstance(value, _ArcGISObjectWrapper):
            return False, value

        (valueChanged, value) = super(SpatialReferenceTypeMetadata, 
self).ValidateValue(value, variableName, methodLocals, argMetadata)
        return (valueChanged, value)


class SQLWhereClauseTypeMetadata(UnicodeStringTypeMetadata):
    
    def __init__(self, canBeNone=False):
        super(SQLWhereClauseTypeMetadata, self).__init__(minLength=1,
                                                         maxLength=2147483647,
                                                         mustMatchRegEx=None,
                                                         canBeNone=canBeNone,
                                                         
arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPSQLExpressionTypeClass',
                                                         
arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing',
                                                         
canBeArcGISInputParameter=True,
                                                         
canBeArcGISOutputParameter=True)


# NumPy and SciPy types
#
# Note: do not move import statements out of the functions to the module 
level.
# We cannot require NumPy and SciPy to be installed just to import this 
module.


class NumPyArrayTypeMetadata(TypeMetadata):

    def __init__(self,
                 dimensions=None,
                 minShape=None,
                 maxShape=None,
                 allowedDTypes=None,
                 canBeNone=False):

        assert isinstance(dimensions, (types.IntType, types.NoneType)), 
u'dimensions must be an integer, or None'
        assert dimensions is None or dimensions > 0, u'dimensions, if 
provided, must be greater than zero'
        assert isinstance(minShape, (types.NoneType, types.ListType, 
types.TupleType)), u'minShape must be a list or tuple of integers, or None'
        if isinstance(minShape, types.TupleType):
            minShape = list(minShape)
        assert minShape is None or dimensions is not None and len(minShape) 
== dimensions, u'If minShape is provided, dimensions must also be provided, 
and len(minShape) must equal dimensions'
        if minShape is not None:
            for value in minShape:
                assert isinstance(value, types.IntType) and value >= 0, u'All 
elements of minShape must be non-negative integers.'
        assert isinstance(maxShape, (types.NoneType, types.ListType, 
types.TupleType)), u'maxShape must be a list or tuple of integers, or None'
        if isinstance(maxShape, types.TupleType):
            maxShape = list(maxShape)
        assert maxShape is None or dimensions is not None and len(maxShape) 
== dimensions, u'If maxShape is provided, dimensions must also be provided, 
and len(maxShape) must equal dimensions'
        if maxShape is not None:
            for value in maxShape:
                assert isinstance(value, types.IntType) and value >= 0, u'All 
elements of maxShape must be non-negative integers.'
        assert isinstance(allowedDTypes, (types.NoneType, types.ListType, 
types.TupleType)), u'allowedDTypes must be a list or tuple of Unicode 
strings, or None.'
        if isinstance(allowedDTypes, types.TupleType):
            allowedDTypes = list(allowedDTypes)
        if allowedDTypes is not None:
            for value in allowedDTypes:
                assert isinstance(value, types.UnicodeType) and len(value) >= 
0, u'All elements of allowedDTypes must be non-empty Unicode strings.'

        # We cannot assume that numpy can be imported. We must allow 
instances of
        # this class to be constructed without failing when numpy is not
        # installed. But if numpy is installed, we initialize our pythonType 
to
        # the appropriate class.

        try:
            import numpy
            pythonType = numpy.ndarray
        except:
            pythonType = object
                
        super(NumPyArrayTypeMetadata, self).__init__(pythonType=pythonType, 
canBeNone=canBeNone)

        self._Dimensions = dimensions
        self._MinShape = minShape
        self._MaxShape = maxShape
        self._AllowedDTypes = allowedDTypes

    def _GetDimensions(self):
        return self._Dimensions
    
    Dimensions = property(_GetDimensions, doc=DynamicDocString())

    def _GetMinShape(self):
        return self._MinShape
    
    MinShape = property(_GetMinShape, doc=DynamicDocString())

    def _GetMaxShape(self):
        return self._MaxShape
    
    MaxShape = property(_GetMaxShape, doc=DynamicDocString())

    def _GetAllowedDTypes(self):
        return self._AllowedDTypes
    
    AllowedDTypes = property(_GetAllowedDTypes, doc=DynamicDocString())

    def AppendXMLNodes(self, node, document):
        super(NumPyArrayTypeMetadata, self).AppendXMLNodes(node, document)

        Metadata.AppendPropertyXMLNode(self, u'Dimensions', node, document)

        minShapeNode = node.appendChild(document.createElement(u'MinShape'))
        if self.MinShape is not None:
            listNode = 
minShapeNode.appendChild(document.createElement(u'ArrayList'))
            for value in self.MinShape:
                
listNode.appendChild(document.createElement(u'int')).appendChild(document.createTextNode(unicode(value)))

        maxShapeNode = node.appendChild(document.createElement(u'MaxShape'))
        if self.MaxShape is not None:
            listNode = 
maxShapeNode.appendChild(document.createElement(u'ArrayList'))
            for value in self.MaxShape:
                
listNode.appendChild(document.createElement(u'int')).appendChild(document.createTextNode(unicode(value)))

        allowedDTypesNode = 
node.appendChild(document.createElement(u'AllowedDTypes'))
        if self.AllowedDTypes is not None:
            listNode = 
allowedDTypesNode.appendChild(document.createElement(u'ArrayList'))
            for value in self.AllowedDTypes:
                
listNode.appendChild(document.createElement(u'string')).appendChild(document.createTextNode(value))

    def ValidateValue(self, value, variableName, methodLocals=None, 
argMetadata=None):
        (valueChanged, value) = super(NumPyArrayTypeMetadata, 
self).ValidateValue(value, variableName, methodLocals, argMetadata)

        if value is not None:
            if self.Dimensions is not None:
                if self.Dimensions != value.ndim:
                    _RaiseException(ValueError(_(u'The NumPy array provided 
for the %(variable)s must have %(dim1)i dimensions. The array you provided 
has %(dim2)i.') % {u'variable' : variableName, u'dim1' : self.Dimensions, 
u'dim2' : value.ndim}))

                if self.MinShape is not None:
                    for i in range(self.Dimensions):
                        if value.shape[i] < self.MinShape[i]:
                            _RaiseException(ValueError(_(u'The NumPy array 
provided for the %(variable)s must have the minimum dimensions %(dim1)i. The 
array you provided has the dimensions %(dim2)i.') % {u'variable' : 
variableName, u'dim1' : repr(self.MinShape), u'dim2' : 
repr(list(value.shape))}))

                if self.MaxShape is not None:
                    for i in range(self.Dimensions):
                        if value.shape[i] > self.MaxShape[i]:
                            _RaiseException(ValueError(_(u'The NumPy array 
provided for the %(variable)s must have the maximum dimensions %(dim1)i. The 
array you provided has the dimensions %(dim2)i.') % {u'variable' : 
variableName, u'dim1' : repr(self.MaxShape), u'dim2' : 
repr(list(value.shape))}))

            if self.AllowedDTypes is not None and unicode(value.dtype.name) 
not in self.AllowedDTypes:
                _RaiseException(ValueError(_(u'The NumPy array provided for 
the %(variable)s must have one of the following dtypes: %(types)s. The array 
you provided has the dtype %(type)s.') % {u'variable' : variableName, 
u'types' : repr(self.AllowedDTypes), u'type' : unicode(value.dtype.name)}))

        return (valueChanged, value)


###############################################################################
# Names exported by this module
###############################################################################

__all__ = ['AnyObjectTypeMetadata',
           'NoneTypeMetadata',
           'ClassTypeMetadata',
           'ClassInstanceTypeMetadata',
           'ClassOrClassInstanceTypeMetadata',
           'BooleanTypeMetadata',
           'DateTimeTypeMetadata',
           'FloatTypeMetadata',
           'IntegerTypeMetadata',
           'UnicodeStringTypeMetadata',
           'SequenceTypeMetadata',
           'ListTypeMetadata',
           'TupleTypeMetadata',
           'DictionaryTypeMetadata',
           'StoredObjectTypeMetadata',
           'FileTypeMetadata',
           'TextFileTypeMetadata',
           'DirectoryTypeMetadata',
           'ArcGISGeoDatasetTypeMetadata',
           'ArcGISRasterTypeMetadata',
           'ArcGISRasterLayerTypeMetadata',
           'ArcGISFeatureClassTypeMetadata',
           'ArcGISFeatureLayerTypeMetadata',
           'ShapefileTypeMetadata',
           'ArcGISWorkspaceTypeMetadata',
           'ArcGISTableTypeMetadata',
           'ArcGISTableViewTypeMetadata',
           'ArcGISFieldTypeMetadata',
           'CoordinateSystemTypeMetadata',
           'EnvelopeTypeMetadata',
           'LinearUnitTypeMetadata',
           'MapAlgebraExpressionTypeMetadata',
           'PointTypeMetadata',
           'SpatialReferenceTypeMetadata',
           'SQLWhereClauseTypeMetadata',
           'NumPyArrayTypeMetadata']
< date >
< thread >
Archives powered by MHonArc.
Top of Page