Changeset 25
- Timestamp:
- 01/08/07 16:48:50 (3 years ago)
- Files:
-
- MGET/Trunk/PythonPackage/BuildWin32.cmd (modified) (1 diff)
- MGET/Trunk/PythonPackage/dist/GeoEco-0.1.0a1.win32.exe (modified) (previous)
- MGET/Trunk/PythonPackage/setup.py (modified) (13 diffs)
- MGET/Trunk/PythonPackage/src/GeoEco/ArcGIS.py (modified) (15 diffs)
- MGET/Trunk/PythonPackage/src/GeoEco/Configuration/Logging.txt (modified) (3 diffs)
- MGET/Trunk/PythonPackage/src/GeoEco/Dependencies.py (modified) (3 diffs)
- MGET/Trunk/PythonPackage/src/GeoEco/Exceptions.py (modified) (1 diff)
- MGET/Trunk/PythonPackage/src/GeoEco/Logging.py (modified) (6 diffs)
- MGET/Trunk/PythonPackage/src/GeoEco/Metadata.py (modified) (17 diffs)
- MGET/Trunk/PythonPackage/src/GeoEco/Tool.py (deleted)
- MGET/Trunk/PythonPackage/src/GeoEco/Tools/HelloWorld.py (modified) (7 diffs)
- MGET/Trunk/PythonPackage/src/GeoEco/Types.py (modified) (14 diffs)
- MGET/Trunk/VisualStudioSolutions/CreateArcGISToolbox/Program.cs (modified) (13 diffs)
- MGET/Trunk/VisualStudioSolutions/CreateArcGISToolbox/bin/Release/CreateArcGISToolbox.exe (modified) (previous)
- MGET/Trunk/VisualStudioSolutions/CreateArcGISToolbox/bin/Release/CreateArcGISToolbox.pdb (modified) (previous)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
MGET/Trunk/PythonPackage/BuildWin32.cmd
r11 r25 1 1 @echo off 2 if not "%DevEnvDir%"=="" goto Build 3 call "C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\vsvars32.bat" 4 :Build 2 5 cmd.exe /C setup.py bdist_wininst --install-script=GeoEcoPostInstall.py MGET/Trunk/PythonPackage/setup.py
r16 r25 14 14 import xml.dom.minidom 15 15 16 16 17 # Helper functions 17 18 … … 49 50 AppendMetadataXMLForModule(submoduleName, p, submodulesNode.appendChild(document.createElement(u'ModuleMetadata')), document) 50 51 52 51 53 def WriteArcGISWrapperScriptForMethod(moduleName, method, scriptsDir): 52 54 u"""Write a Python wrapper script to scriptsDir for invoking method from an ArcGIS toolbox.""" … … 54 56 import GeoEco.ArcGIS 55 57 56 GeoEco.ArcGIS.Validate ToolMetadata(moduleName, method.Class.Name, method.Name)58 GeoEco.ArcGIS.ValidateMethodMetadataForExposureAsArcGISTool(moduleName, method.Class.Name, method.Name) 57 59 fileName = os.path.join(scriptsDir, u'%s.%s.py' % (method.Class.Name, method.Name)) 58 60 print(u' Writing \"%s\"' % fileName) 59 61 f = file(fileName, u'w') 60 62 f.write('import GeoEco.ArcGIS\n') 61 f.write('GeoEco.ArcGIS.Execute ToolFromCommandLine(\'%s\', \'%s\', \'%s\')\n' % (str(moduleName), str(method.Class.Name), str(method.Name)))63 f.write('GeoEco.ArcGIS.ExecuteMethodFromCommandLineAsArcGISTool(\'%s\', \'%s\', \'%s\')\n' % (str(moduleName), str(method.Class.Name), str(method.Name))) 62 64 f.close() 63 65 66 64 67 def WriteArcGISWrapperScriptsForMethodsInModule(moduleName, modulePath, scriptsDir): 65 u"""For all methods flagged for exposure as ArcGIS tools, write Python wrapper scripts to scriptsDir for invoking these methods from an ArcGIS toolbox. If thisis a package, recurse down subpackages and submodules."""68 u"""For all methods of all classes in the specified module, if the method is flagged for exposure as ArcGIS tool, write a Python wrapper script to scriptsDir for invoking the method from an ArcGIS toolbox. If the specified module is a package, recurse down subpackages and submodules.""" 66 69 67 70 import GeoEco.Metadata … … 90 93 continue 91 94 WriteArcGISWrapperScriptsForMethodsInModule(submoduleName, p, scriptsDir) 95 96 97 def GetIDispatchClassesInModule(moduleName, modulePath): 98 u"""Return all classes in the specified module that are flagged for exposure using the Microsoft COM IDispatch interface. If the specified module is a package, recurse down subpackages and submodules.""" 99 100 import GeoEco.Metadata 101 102 # Add all classes from the specified module. 103 104 iDispatchClasses = [] 105 106 if isinstance(sys.modules[moduleName].__doc__, GeoEco.Metadata.DynamicDocString) and isinstance(sys.modules[moduleName].__doc__.Obj, GeoEco.Metadata.ModuleMetadata): 107 for (className, cls) in sys.modules[moduleName].__dict__.items(): 108 if inspect.isclass(cls) and isinstance(cls.__doc__, GeoEco.Metadata.DynamicDocString) and isinstance(cls.__doc__.Obj, GeoEco.Metadata.ClassMetadata) and cls.__doc__.Obj.Module == sys.modules[moduleName].__doc__.Obj and cls.__doc__.Obj.IsExposedByIDispatch: 109 iDispatchClasses.append(cls) 110 111 # If the specified module is a directory, then it is a Python package. 112 # Process the submodules and subpackages. 113 114 if os.path.isdir(modulePath): 115 paths = glob.glob(os.path.join(modulePath, u'*')) 116 for p in paths: 117 if os.path.isfile(p) and p.endswith(u'.py') and os.path.basename(p) != u'__init__.py': 118 submoduleName = moduleName + u'.' + os.path.basename(p)[:-3] 119 elif os.path.isdir(p) and p.lower() != u'.svn' and os.path.isfile(os.path.join(p, u'__init__.py')): 120 submoduleName = moduleName + u'.' + os.path.basename(p) 121 else: 122 continue 123 moreIDispatchClasses = GetIDispatchClassesInModule(submoduleName, p) 124 iDispatchClasses.extend(moreIDispatchClasses) 125 126 # Return a list of classes that are flagged for exposure using IDispatch, so 127 # the caller does not have to enumerate them again. 128 129 return iDispatchClasses 130 92 131 93 132 def CopyTree(src, dest): … … 220 259 WriteArcGISWrapperScriptsForMethodsInModule(u'GeoEco', sys.modules[u'GeoEco'].__path__[0], os.path.join(arcGISDir, u'Scripts')) 221 260 261 # TODO: validate that the same tool name is not exposed twice (Trac ticket #29) 262 222 263 # Create the ArcGIS toolbox. 223 264 … … 244 285 packageData[u'GeoEco'].append(os.path.join(u'ArcGISToolbox', u'Scripts', u'*.*')) 245 286 287 # If running on Windows, generate the COM type library for classes that can 288 # be invoked through COM Automation (IDispatch) interfaces. 289 290 if sys.platform.lower() == u'win32': 291 print(u'') 292 print(u'********************************************************************************') 293 print(u'* Generating the Microsoft COM type library') 294 print(u'********************************************************************************') 295 print(u'') 296 297 # Open the IDL file for writing. 298 299 comDir = os.path.join(srcDir, u'GeoEco', u'COM') 300 idlFilePath = os.path.join(comDir, u'GeoEco.idl') 301 print(u'Opening %s for writing.' % idlFilePath) 302 idlFile = file(idlFilePath, u'w') 303 idlFile.write('// IDL for GeoEco Type Library\n') 304 idlFile.write('//\n') 305 idlFile.write('// GeoEco is a Python package that provides geospatial ecology tools.\n') 306 idlFile.write('// Many of these tools are exposed as COM classes. Each class has a\n') 307 idlFile.write('// ProgID beginning with "GeoEco." and exposes a dual interface.\n') 308 idlFile.write('// Late-binding clients such as script engines can invoke the classes\n') 309 idlFile.write('// through the IDispatch interface, while early-binding clients such\n') 310 idlFile.write('// as C# can import the GeoEco Type Library and invoke the classes\n') 311 idlFile.write('// through the more-efficient vtable interface.\n') 312 idlFile.write('//\n') 313 idlFile.write('// This IDL file defines all of the interfaces and classes exported by\n') 314 idlFile.write('// the GeoEco type library.\n') 315 idlFile.write('\n') 316 idlFile.write('import "oaidl.idl";\n') 317 idlFile.write('import "ocidl.idl";\n') 318 idlFile.write('\n') 319 320 # Obtain a list of all of the classes flagged for exposure through COM 321 # IDispatch. Validate the classes' metadata. Also validate that each 322 # class has a unique name across the entire set of classes, regardless 323 # of which module it appears in. This means developers cannot 324 # disambiguate classes with the same names using the Python module 325 # hierarchy. The benefit of this restriction is that we don't have to 326 # generate multiple type libraries, or a single type library that 327 # prepends the full list of module names to the class name. 328 329 print(u'Validating classes flagged for exposure by IDispatch:') 330 331 import pythoncom 332 import GeoEco.COM 333 334 classDict = {} 335 guidDict = {} 336 337 iDispatchClasses = GetIDispatchClassesInModule(u'GeoEco', sys.modules[u'GeoEco'].__path__[0]) 338 for cls in iDispatchClasses: 339 GeoEco.COM.ValidateClassMetadata(cls) 340 classMetadata = cls.__doc__.Obj 341 342 if classDict.has_key(classMetadata.Name): 343 sys.exit(u'Two classes flagged for exposure by IDispatch have the same class name: %s.%s and %s.%s. To be exposed by IDispatch, each class must have a unique name, regardless of what module it appears in. Please change the name of one of these classes.' % (classMetadata.Module.Name, classMetadata.Name, classDict[classMetadata.Name].Module.Name, classDict[classMetadata.Name].Name)) 344 classDict[classMetadata.Name] = classMetadata 345 346 if guidDict.has_key(classMetadata.COMIID): 347 sys.exit(u'Two classes flagged for exposure by IDispatch are using the same GUID %s: %s.%s is using it for COMIID and %s.%s is using it for %s. To be exposed by IDispatch, each class must have a unique GUID for COMIID and COMCLSID. Here is a new unique GUID you can use: %s' % (classMetadata.COMIID, classMetadata.Module.Name, classMetadata.Name, guidDict[classMetadata.COMIID][1].Module.Name, guidDict[classMetadata.COMIID][1].Name, guidDict[classMetadata.COMIID][0], repr(unicode(pythoncom.CreateGuid())))) 348 guidDict[classMetadata.COMIID] = (u'COMIID', classMetadata) 349 350 if guidDict.has_key(classMetadata.COMCLSID): 351 sys.exit(u'Two classes flagged for exposure by IDispatch are using the same GUID %s: %s.%s is using it for COMCLSID and %s.%s is using it for %s. To be exposed by IDispatch, each class must have a unique GUID for COMIID and COMCLSID. Here is a new unique GUID you can use: %s' % (classMetadata.COMIID, classMetadata.Module.Name, classMetadata.Name, guidDict[classMetadata.COMIID][1].Module.Name, guidDict[classMetadata.COMIID][1].Name, guidDict[classMetadata.COMIID][0], repr(unicode(pythoncom.CreateGuid())))) 352 guidDict[classMetadata.COMIID] = (u'COMCLSID', classMetadata) 353 354 print(' %s.%s as ProgID %s' % (cls.__doc__.Obj.Module.Name, cls.__doc__.Obj.Name, cls.__doc__.Obj.COMVersionIndependentProgID)) 355 356 # Write the interface definitions to the IDL file. 357 358 print(u'Writing interface definitions to %s.' % idlFilePath) 359 for cls in iDispatchClasses: 360 idlFile.write(GeoEco.COM.GetIDLInterfaceDefinitionFromMetadata(cls.__doc__.Obj)) 361 idlFile.write('\n') 362 363 # Write type library header to the IDL file. 364 365 idlFile.write('[\n') 366 idlFile.write(' uuid(%s),\n' % GeoEco.COM.TypeLibraryGUID[1:-1]) 367 idlFile.write(' version(%i.%i),\n' % (GeoEco.COM.TypeLibraryVersion[0], GeoEco.COM.TypeLibraryVersion[1])) 368 idlFile.write(' helpstring("GeoEco %i.%i Type Library")\n' % (GeoEco.COM.TypeLibraryVersion[0], GeoEco.COM.TypeLibraryVersion[1])) 369 idlFile.write(']\n') 370 idlFile.write('library GeoEco\n') 371 idlFile.write('{\n') 372 idlFile.write(' importlib("stdole32.tlb");\n') 373 idlFile.write(' importlib("stdole2.tlb");\n') 374 375 # Write the coclass definitions to the IDL file. 376 377 for cls in iDispatchClasses: 378 idlFile.write('\n') 379 idlFile.write(' [\n') 380 idlFile.write(' uuid(%s),\n' % cls.__doc__.Obj.COMCLSID[1:-1]) 381 idlFile.write(' helpstring("%s Class")\n' % cls.__doc__.Obj.Name) 382 idlFile.write(' ]\n') 383 idlFile.write(' coclass %s\n' % cls.__doc__.Obj.Name) 384 idlFile.write(' {\n') 385 idlFile.write(' [default] interface I%s;\n' % cls.__doc__.Obj.Name) 386 idlFile.write(' };\n') 387 388 # Close the IDL file. 389 390 idlFile.write('};\n') 391 idlFile.close() 392 393 # Execute the MIDL compiler on the IDL file to produce the TLB file. 394 395 tlbFilePath = os.path.splitext(idlFilePath)[0] + u'.tlb' 396 397 args = [u'midl.exe', u'/out', os.path.dirname(idlFilePath), u'/tlb', tlbFilePath, u'/win32', idlFilePath] 398 print('Invoking %s' % ' '.join(args)) 399 try: 400 p = subprocess.Popen(args) 401 except WindowsError, e: 402 if e.errno == 2: 403 print(e.__class__.__name__ + u': ' + unicode(e)) 404 sys.exit(u'The most common cause for failure here is forgetting to register the Microsoft Visual Studio environment variables. This is usually best accomplished by running "C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\Tools\\vsvars32.bat" prior to executing setup.py.') 405 else: 406 raise 407 retcode = p.wait() 408 if retcode != 0: 409 sys.exit(u'midl.exe failed and returned exit code %i.' % retcode) 410 for ext in [u'_i.c', u'_p.c', u'.h']: 411 if os.path.exists(os.path.splitext(idlFilePath)[0] + ext): 412 os.remove(os.path.splitext(idlFilePath)[0] + ext) 413 if os.path.exists(os.path.join(os.path.dirname(idlFilePath), u'dlldata.c')): 414 os.remove(os.path.join(os.path.dirname(idlFilePath), u'dlldata.c')) 415 416 packageData[u'GeoEco'].append(os.path.join(u'COM', u'*.*')) 417 246 418 # If running on Windows, generate the postinstall script. 247 419 … … 251 423 print(u'* Generating the Windows postinstall script') 252 424 print(u'********************************************************************************') 253 print(u'') 425 print(u'') 426 427 # Generate the list of classes that need COM registration. 428 429 classesForCOMRegistration = '[' + ', '.join(map(lambda cls: '[' + repr(str(cls.__doc__.Obj.Module.Name)) + ', ' + repr(str(cls.__doc__.Obj.Name)) + ']', iDispatchClasses)) + ']' 430 431 # Write the install script. 254 432 255 433 postInstallFilePath = os.path.join(srcDir, u'GeoEcoPostInstall.py') … … 270 448 import GeoEco 271 449 geoEcoRoot = os.path.dirname(sys.modules['GeoEco'].__file__) 450 451 ############################################################################### 452 # INPUT DATA 453 ############################################################################### 454 455 classesForCOMRegistration = """ + classesForCOMRegistration + """ 272 456 273 457 ############################################################################### … … 308 492 import win32process 309 493 except: 310 sys.exit('ERROR: Python for Windows Extensions (pywin32) is not installed. GeoEco requires this Python package. Please uninstall GeoEco, download the packagefrom http://sourceforge.net/projects/pywin32, install it, and install GeoEco again.')494 sys.exit('ERROR: Python for Windows Extensions (pywin32) is not installed. GeoEco requires this Python package. Please uninstall GeoEco, download pywin32 for your version of Python from http://sourceforge.net/projects/pywin32, install it, and install GeoEco again.') 311 495 312 496 # Ensure the ArcGIS is installed by reading the InstallDir from the registry. … … 366 550 return True 367 551 552 def RegisterClassesAsCOMIDispatchServers(): 553 554 # Import pywin32 modules that we need. 555 556 try: 557 import pythoncom 558 import win32com.server.register 559 except: 560 sys.exit('ERROR: Python for Windows Extensions (pywin32) is not installed. GeoEco requires this Python package. Please uninstall GeoEco, download pywin32 for your version of Python from http://sourceforge.net/projects/pywin32, install it, and install GeoEco again.') 561 562 # Register the classes. 563 564 success = True 565 import GeoEco.COM 566 for [moduleName, className] in classesForCOMRegistration: 567 if not GeoEco.COM.RegisterIDispatchServerUsingClassMetadata(moduleName, className): 568 success = False 569 570 # Register the type library. 571 572 tlbFile = os.path.join(os.path.dirname(sys.modules['GeoEco.COM'].__file__), 'COM', 'GeoEco.tlb') 573 try: 574 tli = pythoncom.LoadTypeLib(tlbFile) 575 except Exception, e: 576 print('WARNING: Failed to load the GeoEco COM type library. Since the library could not be loaded, it will not be registered with COM, and you will not be able to call GeoEco objects from early-bound programming languages such as C#. You can try registration again by uninstalling and reinstalling GeoEco. The pythoncom.LoadTypeLib(\\'%s\\') function reported: %s: %s' % (tlbFile, e.__class__.__name__, str(e))) 577 success = False 578 579 if success: 580 try: 581 pythoncom.RegisterTypeLib(tli, tlbFile) 582 except Exception, e: 583 print('WARNING: Failed to register the GeoEco COM type library. You will not be able to call GeoEco objects from early-bound programming languages such as C#. You can try registration again by uninstalling and reinstalling GeoEco. The pythoncom.RegisterTypeLib(tli, \\'%s\\') function reported: %s: %s' % (tlbFile, e.__class__.__name__, str(e))) 584 success = False 585 586 return success 587 588 def UnregisterClassesAsCOMIDispatchServers(): 589 590 # Import pywin32 modules that we need. 591 592 try: 593 import pythoncom 594 import win32com.server.register 595 except: 596 return 597 598 # Unregister the classes. 599 600 import GeoEco.COM 601 for [moduleName, className] in classesForCOMRegistration: 602 GeoEco.COM.UnregisterIDispatchServerUsingClassMetadata(moduleName, className) 603 604 # Unregister the type library: 605 606 try: 607 pythoncom.UnRegisterTypeLib('""" + GeoEco.COM.TypeLibraryGUID + '\', ' + str(GeoEco.COM.TypeLibraryVersion[0]) + ', ' + str(GeoEco.COM.TypeLibraryVersion[1]) + ', ' + str(GeoEco.COM.TypeLibraryLCID) + """, pythoncom.SYS_WIN32) 608 except: 609 pass 610 368 611 ############################################################################### 369 612 # MAIN SCRIPT … … 374 617 if len(sys.argv) >= 2 and sys.argv[1].lower() == '-install': 375 618 arcGISToolboxInstalled = RegisterToolboxWithArcCatalog('register') 376 377 if arcGISToolboxInstalled: 619 allCOMClassesRegistered = RegisterClassesAsCOMIDispatchServers() 620 621 if arcGISToolboxInstalled and allCOMClassesRegistered: 378 622 print('All installation tasks completed successfully.') 379 623 else: … … 386 630 elif len(sys.argv) >= 2 and sys.argv[1].lower() == '-remove': 387 631 RegisterToolboxWithArcCatalog('unregister') 632 UnregisterClassesAsCOMIDispatchServers() 388 633 389 634 # If argv[1] is absent or unrecognized, report an error. … … 423 668 print(u'Removing directory %s...' % os.path.join(setupDir, u'build')) 424 669 shutil.rmtree(os.path.join(setupDir, u'build'), False) 670 print(u'') 671 print(u'***** BUILD SUCCESSFUL *****') 425 672 426 673 if __name__ == u'__main__': MGET/Trunk/PythonPackage/src/GeoEco/ArcGIS.py
r20 r25 12 12 import GeoEco.Logging 13 13 from GeoEco.Metadata import * 14 15 16 # Public attributes, functions and classes exported by this module 17 18 Geoprocessor = None 19 20 def InitializeGeoprocessor(): 21 _InitializeGeoprocessor() 22 23 def GetRealGeoprocessor(): 24 return _RealGeoprocessor 25 26 def SetRealGeoprocessor(geoprocessor): 27 if not isinstance(geoprocessor, object): 28 raise TypeError, _(u'The geoprocessor argument must be an instance of the ArcGIS geoprocessor object.') 29 try: 30 globals()[u'_RealGeoprocessor'] = geoprocessor 31 globals()[u'Geoprocessor'] = _ArcGISObjectWrapper(geoprocessor, u'Geoprocessor') 32 except: 33 globals()[u'_RealGeoprocessor'] = None 34 globals()[u'Geoprocessor'] = None 35 14 from GeoEco.Types import * 15 16 17 # Public classes and functions exported by this module 18 19 class GeoprocessorManager(object): 20 __doc__ = DynamicDocString() 21 22 _Geoprocessor = None 23 _WrappedGeoprocessor = None 24 _ArcGISMajorVersion = None 25 _ArcGISMinorVersion = None 26 _ArcGISServicePack = None 27 28 @classmethod 29 def GetGeoprocessor(cls): 30 return GeoprocessorManager._Geoprocessor 31 32 @classmethod 33 def SetGeoprocessor(cls, geoprocessor): 34 cls.__doc__.Obj.ValidatePropertyAssignment() 35 try: 36 GeoprocessorManager._Geoprocessor = geoprocessor 37 GeoprocessorManager._WrappedGeoprocessor = _ArcGISObjectWrapper(geoprocessor, u'Geoprocessor') 38 except: 39 GeoprocessorManager._Geoprocessor = None 40 GeoprocessorManager._WrappedGeoprocessor = None 41 if GeoprocessorManager._Geoprocessor is not None: 42 GeoEco.Logging.Logger.Debug(_(u'GeoEco will now use ArcGIS geoprocessor object 0x%08X.'), id(geoprocessor)) 43 44 Geoprocessor = property(GetGeoprocessor, SetGeoprocessor, doc=DynamicDocString()) 45 46 @classmethod 47 def GetWrappedGeoprocessor(cls): 48 return GeoprocessorManager._WrappedGeoprocessor 49 50 WrappedGeoprocessor = property(GetWrappedGeoprocessor, doc=DynamicDocString()) 51 52 @classmethod 53 def GetArcGISMajorVersion(cls): 54 if GeoprocessorManager._ArcGISMajorVersion is None: 55 cls._GetArcGISVersionNumbers() 56 return GeoprocessorManager._ArcGISMajorVersion 57 58 ArcGISMajorVersion = property(GetArcGISMajorVersion, doc=DynamicDocString()) 59 60 @classmethod 61 def GetArcGISMinorVersion(cls): 62 if GeoprocessorManager._ArcGISMajorVersion is None: 63 cls._GetArcGISVersionNumbers() 64 return GeoprocessorManager._ArcGISMinorVersion 65 66 ArcGISMinorVersion = property(GetArcGISMinorVersion, doc=DynamicDocString()) 67 68 @classmethod 69 def GetArcGISServicePack(cls): 70 if GeoprocessorManager._ArcGISMajorVersion is None: 71 cls._GetArcGISVersionNumbers() 72 return GeoprocessorManager._ArcGISServicePack 73 74 ArcGISServicePack = property(GetArcGISServicePack, doc=DynamicDocString()) 75 76 @classmethod 77 def InitializeGeoprocessor(cls): 78 cls.InitializeGeoprocessorForDependency() 79 80 @classmethod 81 def InitializeGeoprocessorForDependency(cls, dependency=None): 82 cls.__doc__.Obj.ValidateMethodInvocation() 83 84 # Return immediately the geoprocessor has already been initialized. 85 86 if cls.GetGeoprocessor() is not None: 87 GeoEco.Logging.Logger.Debug(_(u'GeoEco.ArcGIS.GeoprocessorManager.InitializeGeoprocessorForDependency was called but the geoprocessor was already initialized. The request to initialize it again will be ignored.')) 88 return 89 90 GeoEco.Logging.Logger.Debug(_(u'Initializing the ArcGIS geoprocessor object...')) 91 92 # First try to import the arcgisscripting package, which was 93 # introduced in ArcGIS 9.2. 94 95 arcgissscriptingImported = True 96 try: 97 import arcgisscripting 98 except Exception, e: 99 GeoEco.Logging.Logger.Debug(_(u'The arcgisscripting Python package could not be imported (Python raised %s: %s). ArcGIS 9.2 or later is not installed on this machine.'), e.__class__.__name__, unicode(e)) 100 arcgissscriptingImported = False 101 102 # If we succesfully imported the arcgisscripting package, use it to 103 # create the geoprocessor object. 104 105 realGeoprocessor = None 106 107 if arcgissscriptingImported: 108 GeoEco.Logging.Logger.Debug(_(u'Imported the arcgisscripting Python package. ArcGIS 9.2 or later must be installed on this machine.')) 109 error = None 110 try: 111 realGeoprocessor = arcgisscripting.create() 112 except Exception, e: 113 error = (u'%s: %s' % e.__class__.__name__, unicode(e)).strip() 114 if realGeoprocessor is None: 115 message = _(u'This function requires ESRI ArcGIS. The function successfully imported the Python arcgisscripting package, suggesting that ArcGIS 9.2 or later is installed. But the arcgisscripting.create() function') 116 if error is None: 117 message = _(u'%s did not return the geoprocessor object (it returned None without raising an exception). Please verify that ArcGIS is properly installed.') % message 118 else: 119 message = _(u'%s raised an exception. Please verify that ArcGIS is properly installed. The exception was: %s') % (message, error) 120 raise SoftwareNotInstalledError(message, dependency) 121 GeoEco.Logging.Logger.Debug(_(u'Obtained ArcGIS geoprocessor object 0x%08X from arcgisscripting.create().'), id(realGeoprocessor)) 122 123 # If we failed to import the arcgisscripting package, try the old 124 # technique of creating the IDispatch COM object. 125 126 else: 127 128 # The IDispatch technique only works on Windows. Fail if this is 129 # not Windows. 130 131 if platform.system().lower() != u'windows': 132 raise SoftwareNotInstalledError(_(u'This function requires ESRI ArcGIS, which does not appear to be installed. If ArcGIS is not supported on your operating system, you must run this function on an operating system that does support it.'), dependency) 133 134 # Import the Python COM libraries. 135 136 try: 137 import pythoncom 138 except Exception, e: 139 raise SoftwareNotInstalledError(_(u'This function requires ESRI ArcGIS. ArcGIS 9.2 or a later version does not appear to be installed, because the Python arcgisscripting package could not be imported. A prior version might be installed, but in order for GeoEco to communicate with it, you must install the "Python for Windows extensions" Python package for the running version of Python (%s.%s). This package does not appear to be installed. It may be available at http://sourceforge.net/projects/pywin32. Debugging information: the Python statement "__import__(\'pythoncom\')" raised %s: %s') % (unicode(platform.python_version_tuple()[0]), unicode(platform.python_version_tuple()[1]), e.__class__.__name__, unicode(e)), dependency) 140 141 try: 142 import win32com.client 143 except Exception, e: 144 raise SoftwareNotInstalledError(_(u'This function requires ESRI ArcGIS. ArcGIS 9.2 or a later version does not appear to be installed, because the Python arcgisscripting package could not be imported. A prior version might be installed, but in order for GeoEco to communicate with it, you must install the "Python for Windows extensions" Python package for the running version of Python (%s.%s). This package does not appear to be installed. It may be available at http://sourceforge.net/projects/pywin32. Debugging information: the Python statement "__import__(\'win32com.client\')" raised %s: %s') % (unicode(platform.python_version_tuple()[0]), unicode(platform.python_version_tuple()[1]), e.__class__.__name__, unicode(e)), dependency) 145 146 # Create the IDispatch object. 147 148 progID = 'esriGeoprocessing.GPDispatch' 149 150 try: 151 realGeoprocessor = win32com.client.Dispatch(progID) 152 except pythoncom.com_error, (hr, msg, exc, arg): 153 raise SoftwareNotInstalledError(_(u'This function requires ESRI ArcGIS, which does not appear to be installed. This function was unable to import the arcgisscripting Python module, indicating that ArcGIS 9.2 or later is not installed. It was also unable to create the %s COM object, indicating that ArcGIS 9.0 or 9.1 is not installed. Debugging information: win32com.client.Dispatch(\'%s\') raised the exception: %s') % (progID, _FormatCOMError(hr, msg, exc, arg)), dependency) 154 except Exception, e: 155 raise SoftwareNotInstalledError(_(u'This function requires ESRI ArcGIS, which does not appear to be installed. This function was unable to import the arcgisscripting Python module, indicating that ArcGIS 9.2 or later is not installed. It was also unable to create the %s COM object, indicating that ArcGIS 9.0 or 9.1 is not installed. Debugging information: win32com.client.Dispatch(\'%s\') raised the exception: %s: %s') % (progID, e.__class__.__name__, unicode(e)), dependency) 156 GeoEco.Logging.Logger.Debug(_(u'Obtained ArcGIS geoprocessor object 0x%08X by creating COM object %s.'), id(realGeoprocessor), progID) 157 158 # We successfully created the geoprocessor object. 159 160 cls.SetGeoprocessor(realGeoprocessor) 161 162 @classmethod 163 def _GetArcGISVersionNumbers(cls): 164 165 # If we're running on Windows, get the ArcGIS version number from 166 # the Windows registry. 167 168 if platform.system().lower() == u'windows': 169 GeoEco.Logging.Logger.Debug(_(u'Retrieving the ArcGIS version numbers from the Windows Registry.')) 170 171 # First import the win32api module. 172 173 d = GeoEco.Dependencies.PythonPackage(importName='win32api', displayName=_(u'Python for Windows extensions'), alternateURL=u'http://sourceforge.net/projects/pywin32') 174 d.Initialize(); 175 import win32api 176 177 d = GeoEco.Dependencies.PythonPackage(importName='win32con', displayName=_(u'Python for Windows extensions'), alternateURL=u'http://sourceforge.net/projects/pywin32') 178 d.Initialize(); 179 import win32con 180 181 # Read the registry values that contain the version numbers. 182 183 try: 184 hkey = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\ESRI\\ArcInfo\\Desktop\\8.0') 185 try: 186 (realVersionValue, realVersionType) = win32api.RegQueryValueEx(hkey, 'RealVersion') 187 if not isinstance(realVersionValue, basestring) or not re.match('^[0-9]+\.[0-9]+$', realVersionValue.strip()): 188 raise ValueError(_(u'The RealVersion value of the HKEY_LOCAL_MACHINE\\SOFTWARE\\ESRI\\ArcInfo\\Desktop\\8.0 registry key is not a REG_SZ, or it is not formatted properly.')) 189 GeoprocessorManager._ArcGISMajorVersion = int(realVersionValue.strip().split('.')[0]) 190 GeoprocessorManager._ArcGISMinorVersion = int(realVersionValue.strip().split('.')[1]) 191 spNumberValue = None 192 try: 193 (spNumberValue, spNumberType) = win32api.RegQueryValueEx(hkey, 'SPNumber') 194 except: 195 pass 196 if spNumberValue is not None: 197 if not isinstance(spNumberValue, basestring) or len(spNumberValue.strip()) > 0 and not re.match('^[0-9]+$', spNumberValue.strip()): 198 raise ValueError(_(u'The SPNumber value of the HKEY_LOCAL_MACHINE\\SOFTWARE\\ESRI\\ArcInfo\\Desktop\\8.0 registry key is not a REG_SZ, or it is not formatted properly.')) 199 if len(spNumberValue.strip()) > 0: 200 GeoprocessorManager._ArcGISServicePack = int(spNumberValue.strip()) 201 else: 202 GeoprocessorManager._ArcGISServicePack = 0 203 finally: 204 try: 205 win32api.RegCloseKey(hkey) 206 except: 207 pass 208 except Exception, e: 209 GeoprocessorManager._ArcGISMajorVersion = None 210 GeoprocessorManager._ArcGISMinorVersion = None 211 GeoprocessorManager._ArcGISServicePack = None 212 GeoEco.Logging.Logger.Debug(_(u'Failed to retrieve the ArcGIS version numbers from the Windows Registry. ArcGIS must not be installed. Python reported %s: %s'), e.__class__.__name__, unicode(e)) 213 214 # If we're on a non-Windows platform, all we can try to do is import the 215 # arcgisscripting package. If successful, we know that ArcGIS 9.2 or 216 # later is installed. 217 218 else: 219 GeoEco.Logging.Logger.Debug(_(u'Importing the arcgisscripting Python package to determine if ArcGIS is installed on this machine...')) 220 arcgissscriptingImported = True 221 try: 222 import arcgisscripting 223 GeoprocessorManager._ArcGISMajorVersion = 9 224 GeoprocessorManager._ArcGISMinorVersion = 2 225 GeoprocessorManager._ArcGISServicePack = 0 226 GeoEco.Logging.Logger.Debug(_(u'Imported the arcgisscripting Python package. ArcGIS 9.2 or later is installed on this machine. We do not presently know how to determine which version is installed, so we will assume it is 9.2.')) 227 except Exception, e: 228 GeoprocessorManager._ArcGISMajorVersion = None 229 GeoprocessorManager._ArcGISMinorVersion = None 230 GeoprocessorManager._ArcGISServicePack = None 231 GeoEco.Logging.Logger.Debug(_(u'The arcgisscripting Python package could not be imported (Python raised %s: %s). ArcGIS is not installed on this machine.'), e.__class__.__name__, unicode(e)) 232 36 233 37 234 class ArcGISVersion(Dependency): … … 83 280 def Initialize(self): 84 281 85 GeoEco.Logging.LogDebug(_(u'Checking software dependency: ArcGIS version %i.%i%s or later.') % (self.MinimumMajorVersion, self.MinimumMinorVersion, self.MinimumServicePackString)) 86 87 # If we have not created the geoprocessor object, do it first. This will 88 # raise an exception if ArcGIS is not installed on the machine. 89 90 if globals()[u'Geoprocessor'] is None: 91 _InitializeGeoprocessor(self) 282 GeoEco.Logging.Logger.Debug(_(u'Checking software dependency: ArcGIS version %i.%i%s or later.') % (self.MinimumMajorVersion, self.MinimumMinorVersion, self.MinimumServicePackString)) 283 284 # If the geoprocessor object is not initialized yet, do it now. This 285 # will raise an exception if ArcGIS is not installed on the machine. 286 287 if GeoprocessorManager.GetWrappedGeoprocessor() is None: 288 GeoprocessorManager.InitializeGeoprocessorForDependency(self) 289 290 # If we got to here, then some version of ArcGIS is installed. Check the 291 # ArcGIS version numbers 292 293 if GeoprocessorManager.GetArcGISMajorVersion() is None or GeoprocessorManager.GetArcGISMinorVersion() is None or GeoprocessorManager.GetArcGISServicePack() is None: 294 raise SoftwareNotInstalledError(_(u'This function requires ArcGIS %i.%i%s or a later version. Some verison of ArcGIS appears to be installed on this machine but this function was unable to retrieve the version numbers. (On Windows machines, the version numbers are in the RealVersion and SPNumber values of the HKEY_LOCAL_MACHINE\\SOFTWARE\\ESRI\\ArcInfo\\Desktop\\8.0 Registry key). Please verify that ArcGIS is property installed.') % (self.MinimumMajorVersion, self.MinimumMinorVersion, self.MinimumServicePackString), self) 295 296 if GeoprocessorManager.GetArcGISServicePack() > 0: 297 servicePackString = _(u' Service Pack %i') % GeoprocessorManager.GetArcGISServicePack() 92 298 else: 93 GeoEco.Logging.LogDebug(_(u'The ArcGIS geoprocessor was already initialized.')) 94 95 # If we got to here, then some version of ArcGIS is installed. If we 96 # have not retrieved the version numbers yet, do it now. 97 98 if globals()[u'_ArcGISMajorVersion'] is None: 99 100 # If we're running on Windows, get the ArcGIS version number from 101 # the Windows registry. 102 103 if platform.system().lower() == u'windows': 104 GeoEco.Logging.LogDebug(_(u'Retrieving the ArcGIS version numbers from the Windows Registry.')) 105 106 # First import the win32api module. 107 108 d = GeoEco.Dependencies.PythonPackage(importName='win32api', displayName=_(u'Python for Windows extensions'), alternateURL=u'http://sourceforge.net/projects/pywin32') 109 d.Initialize(); 110 import win32api 111 112 d = GeoEco.Dependencies.PythonPackage(importName='win32con', displayName=_(u'Python for Windows extensions'), alternateURL=u'http://sourceforge.net/projects/pywin32') 113 d.Initialize(); 114 import win32con 115 116 # Read the registry values that contain the version numbers. 117 118 try: 119 hkey = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\ESRI\\ArcInfo\\Desktop\\8.0') 120 try: 121 (realVersionValue, realVersionType) = win32api.RegQueryValueEx(hkey, 'RealVersion') 122 if not isinstance(realVersionValue, basestring) or not re.match('^[0-9]+\.[0-9]+$', realVersionValue.strip()): 123 raise ValueError(_(u'The RealVersion value of the HKEY_LOCAL_MACHINE\\SOFTWARE\\ESRI\\ArcInfo\\Desktop\\8.0 registry key is not a REG_SZ, or it is not formatted properly.')) 124 globals()[u'_ArcGISMajorVersion'] = int(realVersionValue.strip().split('.')[0]) 125 globals()[u'_ArcGISMinorVersion'] = int(realVersionValue.strip().split('.')[1]) 126 spNumberValue = None 127 try: 128 (spNumberValue, spNumberType) = win32api.RegQueryValueEx(hkey, 'SPNumber') 129 except: 130 pass 131 if spNumberValue is not None: 132 if not isinstance(spNumberValue, basestring) or len(spNumberValue.strip()) > 0 and not re.match('^[0-9]+$', spNumberValue.strip()): 133 raise ValueError(_(u'The SPNumber value of the HKEY_LOCAL_MACHINE\\SOFTWARE\\ESRI\\ArcInfo\\Desktop\\8.0 registry key is not a REG_SZ, or it is not formatted properly.')) 134 if len(spNumberValue.strip()) > 0: 135 globals()[u'_ArcGISServicePack'] = int(spNumberValue.strip()) 136 else: 137 globals()[u'_ArcGISServicePack'] = 0 138 finally: 139 try: 140 win32api.RegCloseKey(hkey) 141 except: 142 pass 143 except Exception, e: 144 globals()[u'_ArcGISMajorVersion'] = None 145 globals()[u'_ArcGISMinorVersion'] = None 146 globals()[u'_ArcGISServicePack'] = None 147 raise SoftwareNotInstalledError(_(u'This tool requires ArcGIS %i.%i%s or a later version. Some verison of ArcGIS appears to be installed on this machine but this tool was unable to retrieve the version numbers from the Windows Registry (the RealVersion and SPNumber values of the HKEY_LOCAL_MACHINE\\SOFTWARE\\ESRI\\ArcInfo\\Desktop\\8.0 key). Please verify that ArcGIS is property installed. Detailed error information: one of the win32api registry functions raised %s: %s.') % (self.MinimumMajorVersion, self.MinimumMinorVersion, self.MinimumServicePackString, e.__class__.__name__, unicode(e)), self) 148 149 # If we're on some other platform, issue a warning because we do not 150 # know how to obtain the version numbers. 151 152 else: 153 self._LogWarning(_(u'This tool requires ArcGIS %i.%i%s or a later version, but it does not know how to retrieve the ArcGIS version numbers when running on non-Windows platforms. The tool will continue executing even though it cannot verify the ArcGIS version. If you do not have a sufficient version installed you may experience unexpected results.') % (self.MinimumMajorVersion, self.MinimumMinorVersion, self.MinimumServicePackString)) 154 155 # If we got the version numbers, check them. (If we did not get them but 156 # we still got to this point, it means we are running on a platform that 157 # we don't know how to get the version numbers from, and we're willing 158 # to go forward anyway with possible unexpected results.) 159 160 if globals()[u'_ArcGISMajorVersion'] is not None: 161 if globals()[u'_ArcGISServicePack'] > 0: 162 servicePackString = _(u' Service Pack %i') % globals()[u'_ArcGISServicePack'] 163 else: 164 servicePackString = u'' 165 GeoEco.Logging.LogDebug(_(u'ArcGIS %i.%i%s is installed.') % (globals()[u'_ArcGISMajorVersion'], globals()[u'_ArcGISMinorVersion'], servicePackString)) 166 if self.MinimumMajorVersion > globals()[u'_ArcGISMajorVersion'] or self.MinimumMajorVersion == globals()[u'_ArcGISMajorVersion'] and self.MinimumMinorVersion > globals()[u'_ArcGISMinorVersion'] or self.MinimumMajorVersion == globals()[u'_ArcGISMajorVersion'] and self.MinimumMinorVersion == globals()[u'_ArcGISMinorVersion'] and self.MinimumServicePack > globals()[u'_ArcGISServicePack']: 167 raise SoftwareNotInstalledError(_(u'This tool requires ArcGIS %i.%i%s or a later version, but verison %s.%s%s is installed. Please upgrade your ArcGIS installation to a compatible version.') % (self.MinimumMajorVersion, self.MinimumMinorVersion, self.MinimumServicePackString, globals()[u'_ArcGISMajorVersion'], globals()[u'_ArcGISMinorVersion'], servicePackString), self) 168 169 170 def ValidateToolMetadata(moduleName, className, methodName): 299 servicePackString = u'' 300 GeoEco.Logging.Logger.Debug(_(u'ArcGIS %i.%i%s is installed.'), GeoprocessorManager.GetArcGISMajorVersion(), GeoprocessorManager.GetArcGISMinorVersion(), servicePackString) 301 302 if self.MinimumMajorVersion > GeoprocessorManager.GetArcGISMajorVersion() or self.MinimumMajorVersion == GeoprocessorManager.GetArcGISMajorVersion() and self.MinimumMinorVersion > GeoprocessorManager.GetArcGISMinorVersion() or self.MinimumMajorVersion == GeoprocessorManager.GetArcGISMajorVersion() and self.MinimumMinorVersion == GeoprocessorManager.GetArcGISMinorVersion() and self.MinimumServicePack > GeoprocessorManager.GetArcGISServicePack(): 303 raise SoftwareNotInstalledError(_(u'This function requires ArcGIS %i.%i%s or a later version, but verison %s.%s%s is installed. Please upgrade your ArcGIS installation to a compatible version.') % (self.MinimumMajorVersion, self.MinimumMinorVersion, self.MinimumServicePackString, GeoprocessorManager.GetArcGISMajorVersion(), GeoprocessorManager.GetArcGISMinorVersion(), servicePackString), self) 304 305 306 def ValidateMethodMetadataForExposureAsArcGISTool(moduleName, className, methodName): 171 307 172 308 # Validate the class and method metadata. 173 309 174 assert sys.modules.has_key(moduleName), u'Module %s must be imported before ValidateToolMetadata is invoked on that module.' % moduleName 175 import GeoEco.Tools 176 assert sys.modules[moduleName].__dict__.has_key(className) and issubclass(sys.modules[moduleName].__dict__[className], GeoEco.Tool.Tool), u'Module %s must contain a class named %s, and the class must derive from GeoEco.Tool.Tool.' % (moduleName, className) 310 assert sys.modules.has_key(moduleName), u'Module %s must be imported before ValidateMethodMetadataForExposureAsArcGISTool is invoked on that module.' % moduleName 311 assert sys.modules[moduleName].__dict__.has_key(className) and issubclass(sys.modules[moduleName].__dict__[className], object), u'Module %s must contain a class named %s, and the class must derive from object.' % (moduleName, className) 177 312 cls = sys.modules[moduleName].__dict__[className] 178 313 assert isinstance(cls.__doc__, DynamicDocString) and isinstance(cls.__doc__.Obj, ClassMetadata), u'The __doc__ attribute of class %s must be an instance of DynamicDocString, and that Obj property of that instance must be an instance of ClassMetadata.' % className … … 211 346 212 347 213 def Execute ToolFromCommandLine(moduleName, className, methodName, loggingConfigFile=None):348 def ExecuteMethodFromCommandLineAsArcGISTool(moduleName, className, methodName, loggingConfigFile=None): 214 349 215 350 # Initialize the logging system. 216 351 217 352 import GeoEco.Logging 218 GeoEco.Logging. InitializeLogging(loggingConfigFile)353 GeoEco.Logging.Logger.Initialize(loggingConfigFile) 219 354 try: 220 GeoEco.Logging. ActivateArcGISLogging()221 222 # Validate the tool's metadata. This was already done when the GeoEco355 GeoEco.Logging.Logger.ActivateArcGISLogging() 356 357 # Validate the methods's metadata. This was already done when the GeoEco 223 358 # package was built, but we do it again here for safety. 224 359 225 360 __import__(moduleName, globals(), locals()) 226 Validate ToolMetadata(moduleName, className, methodName)361 ValidateMethodMetadataForExposureAsArcGISTool(moduleName, className, methodName) 227 362 228 363 # Determine whether we were invoked from an ArcGIS GUI application, in 229 364 # which case we can use the geoprocessor's GetParameterAsText API to 230 # retrieve the tool's parameters. If we were not invoked from an ArcGIS365 # retrieve the method's parameters. If we were not invoked from an ArcGIS 231 366 # GUI, then this API won't work, and we have to get the parameters from 232 367 # sys.argv. GetParameterAsText is better because it doesn't strip out … … 245 380 methodMetadata = getattr(cls, methodName).__doc__.Obj 246 381 expectedParamCount = len(methodMetadata.Arguments) + len(methodMetadata.Results) - 1 # Subtract 1 because the "self" or "cls" parameter is not exposed in ArcGIS 247 geoprocessor = globals()[u'Geoprocessor']382 geoprocessor = GeoprocessorManager.GetWrappedGeoprocessor() 248 383 if geoprocessor.ParameterCount == expectedParamCount: 249 384 useSysArgv = False … … 290 425 for i in range(len(methodMetadata.Results)): 291 426 if locals()[u'ret%s' % i] is not None: 292 globals()[u'Geoprocessor'].SetParameterAsText(len(methodMetadata.Arguments) - 1 + i, unicode(locals()[u'ret%s' % i]))427 GeoprocessorManager.GetWrappedGeoprocessor().SetParameterAsText(len(methodMetadata.Arguments) - 1 + i, unicode(locals()[u'ret%s' % i])) 293 428 else: 294 globals()[u'Geoprocessor'].SetParameterAsText(len(methodMetadata.Arguments) - 1 + i, u'')429 GeoprocessorManager.GetWrappedGeoprocessor().SetParameterAsText(len(methodMetadata.Arguments) - 1 + i, u'') 295 430 296 431 # If we caught an exception, log it as an error if the logger level is set … … 300 435 try: 301 436 if logging.getLogger(u'GeoEco').getEffectiveLevel() <= logging.DEBUG: 302 GeoEco.Logging.Log Error(u'%s: %s', e.__class__.__name__, unicode(e), exc_info=e)437 GeoEco.Logging.Logger.Error(u'%s: %s', e.__class__.__name__, unicode(e), exc_info=e) 303 438 else: 304 GeoEco.Logging.Log Error(u'%s: %s', e.__class__.__name__, unicode(e))439 GeoEco.Logging.Logger.Error(u'%s: %s', e.__class__.__name__, unicode(e)) 305 440 except: 306 441 pass … … 310 445 311 446 sys.exit(0) 312 313 314 # Private attributes, functions and classes that implement the public interface.315 316 _RealGeoprocessor = None # The geoprocessor instance obtained from ArcGIS, not wrapped by a _ArcGISObjectWrapper instance.317 _ArcGISMajorVersion = None # Major version number of ArcGIS that is installed on this machine318 _ArcGISMinorVersion = None # Minor version number of ArcGIS that is installed on this machine319 _ArcGISServicePack = None # Service pack number of ArcGIS that is installed on this machine320 321 322 def _InitializeGeoprocessor(dependency=None):323 assert globals()[u'Geoprocessor'] is None and globals()[u'_RealGeoprocessor'] is None or globals()[u'Geoprocessor'] is not None and globals()[u'_RealGeoprocessor'] is not None324 assert isinstance(dependency, (types.NoneType, Dependency))325 326 # Return immediately the geoprocessor has already been initialized.327 328 if globals()[u'Geoprocessor'] is not None:329 return330 331 # First try to import the arcgisscripting package, which was332 # introduced in ArcGIS 9.2.333 334 arcgissscriptingImported = True335 try:336 import arcgisscripting337 except Exception, e:338 arcgissscriptingImported = False339 340 # If we succesfully imported the arcgisscripting package, use it to341 # create the geoprocessor object.342 343 realGeoprocessor = None344 345 if arcgissscriptingImported:346 error = None347 try:348 realGeoprocessor = arcgisscripting.create()349 except Exception, e:350 error = (u'%s: %s' % e.__class__.__name__, unicode(e)).strip()351 if realGeoprocessor is None:352 message = _(u'This tool requires ESRI ArcGIS. The tool successfully imported the Python arcgisscripting package, suggesting that ArcGIS 9.2 or later is installed. But the arcgisscripting.create() function')353 if error is None:354 message = _(u'%s did not return the geoprocessor object (it returned None without raising an exception). Please verify that ArcGIS is properly installed.') % message355 else:356 message = _(u'%s raised an exception. Please verify that ArcGIS is properly installed. The exception was: %s') % (message, error)357 raise SoftwareNotInstalledError(message, dependency)358 359 # If we failed to import the arcgisscripting package, try the old360 # technique of creating the IDispatch COM object.361 362 else:363 364 # The IDispatch technique only works on Windows. Fail if this is365 # not Windows.366 367 if platform.system().lower() != u'windows':368 raise SoftwareNotInstalledError(_(u'This tool requires ESRI ArcGIS, which does not appear to be installed. If ArcGIS is not supported on your operating system, you must run this tool on an operating system that does support it.'), dependency)369 370 # Import the Python COM libraries.371 372 try:373 import pythoncom374 except Exception, e:375 raise SoftwareNotInstalledError(_(u'This tool requires ESRI ArcGIS. ArcGIS 9.2 or a later version does not appear to be installed, because the Python arcgisscripting package could not be imported. A prior version might be installed, but in order for GeoEco to communicate with it, you must install the "Python for Windows extensions" Python package for the running version of Python (%s.%s). This package does not appear to be installed. It may be available at http://sourceforge.net/projects/pywin32. Debugging information: the Python statement "__import__(\'pythoncom\')" raised %s: %s') % (unicode(platform.python_version_tuple()[0]), unicode(platform.python_version_tuple()[1]), e.__class__.__name__, unicode(e)), dependency)376 377 try:378 import win32com.client379 except Exception, e:380 raise SoftwareNotInstalledError(_(u'This tool requires ESRI ArcGIS. ArcGIS 9.2 or a later version does not appear to be installed, because the Python arcgisscripting package could not be imported. A prior version might be installed, but in order for GeoEco to communicate with it, you must install the "Python for Windows extensions" Python package for the running version of Python (%s.%s). This package does not appear to be installed. It may be available at http://sourceforge.net/projects/pywin32. Debugging information: the Python statement "__import__(\'win32com.client\')" raised %s: %s') % (unicode(platform.python_version_tuple()[0]), unicode(platform.python_version_tuple()[1]), e.__class__.__name__, unicode(e)), dependency)381 382 # Create the IDispatch object.383 384 progID = 'esriGeoprocessing.GPDispatch'385 386 try:387 realGeoprocessor = win32com.client.Dispatch(progID)388 except pythoncom.com_error, (hr, msg, exc, arg):389 raise SoftwareNotInstalledError(_(u'This tool requires ESRI ArcGIS, which does not appear to be installed. This tool was unable to import the arcgisscripting Python module, indicating that ArcGIS 9.2 or later is not installed. It was also unable to create the %s COM object, indicating that ArcGIS 9.0 or 9.1 is not installed. Debugging information: win32com.client.Dispatch(\'%s\') raised the exception: %s') % (progID, _FormatCOMError(hr, msg, exc, arg)), dependency)390 except Exception, e:391 raise SoftwareNotInstalledError(_(u'This tool requires ESRI ArcGIS, which does not appear to be installed. This tool was unable to import the arcgisscripting Python module, indicating that ArcGIS 9.2 or later is not installed. It was also unable to create the %s COM object, indicating that ArcGIS 9.0 or 9.1 is not installed. Debugging information: win32com.client.Dispatch(\'%s\') raised the exception: %s: %s') % (progID, e.__class__.__name__, unicode(e)), dependency)392 393 # We successfully created the geoprocessor object.394 395 SetRealGeoprocessor(realGeoprocessor)396 447 397 448 … … 531 582 except com_error, (hr, msg, exc, arg): 532 583 self._LogReturnedGeoprocessingMessages() # Most likely there are none, but try it anyway. 533 raise ArcGISError(_(u'Failed to get the value of the %s attribute of ArcGIS %s object 0x%08X. This may result from a problem with your inputs or it may indicate a programming mistake in this tool or ArcGIS itself. Please check your inputs and try again. Also review any preceding error messages and the detailed error information that appears at the end of this message. If you suspect a programming mistake in this tool or ArcGIS, please contact the author of this toolfor assistance. Detailed error information: The following exception was raised when the property retrieved: %s') % (name, self._Name, id(self._Object), _FormatCOMError(hr, msg, exc, arg)), sys.exc_info()[1])584 raise ArcGISError(_(u'Failed to get the value of the %s attribute of ArcGIS %s object 0x%08X. This may result from a problem with your inputs or it may indicate a programming mistake in this function or ArcGIS itself. Please check your inputs and try again. Also review any preceding error messages and the detailed error information that appears at the end of this message. If you suspect a programming mistake in this function or ArcGIS, please contact the author of this function for assistance. Detailed error information: The following exception was raised when the property retrieved: %s') % (name, self._Name, id(self._Object), _FormatCOMError(hr, msg, exc, arg)), sys.exc_info()[1]) 534 585 535 586 # If we did not import pythoncom, set the value and allow the outer … … 549 600 except Exception, e: 550 601 self._LogReturnedGeoprocessingMessages() # Most likely there are none, but try it anyway. 551 raise ArcGISError(_(u'Failed to get the value of the %s attribute of ArcGIS %s object 0x%08X. This may result from a problem with your inputs or it may indicate a programming mistake in this tool or ArcGIS itself. Please check your inputs and try again. Also review any preceding error messages and the detailed error information that appears at the end of this message. If you suspect a programming mistake in this tool or ArcGIS, please contact the author of this toolfor assistance. Detailed error information: The following exception was raised when the property retrieved: %s: %s') % (name, self._Name, id(self._Object), e.__class__.__name__, unicode(e)), e)602 raise ArcGISError(_(u'Failed to get the value of the %s attribute of ArcGIS %s object 0x%08X. This may result from a problem with your inputs or it may indicate a programming mistake in this function or ArcGIS itself. Please check your inputs and try again. Also review any preceding error messages and the detailed error information that appears at the end of this message. If you suspect a programming mistake in this function or ArcGIS, please contact the author of this function for assistance. Detailed error information: The following exception was raised when the property retrieved: %s: %s') % (name, self._Name, id(self._Object), e.__class__.__name__, unicode(e)), e) 552 603 553 604 # If it is a method, create a wrapper, add it to our dictionary of … … 625 676 else: 626 677 valueStr = repr(value) 627 raise ArcGISError(_(u'Failed to set the %s property of ArcGIS %s object 0x%08X to %s. This may result from a problem with your inputs or it may indicate a programming mistake in this tool or ArcGIS itself. Please check your inputs and try again. Also review any preceding error messages and the detailed error information that appears at the end of this message. If you suspect a programming mistake in this tool or ArcGIS, please contact the author of this toolfor assistance. Detailed error information: The following exception was raised when the property was assigned: %s') % (name, self._Name, id(self._Object), valueStr, _FormatCOMError(hr, msg, exc, arg)), sys.exc_info()[1])678 raise ArcGISError(_(u'Failed to set the %s property of ArcGIS %s object 0x%08X to %s. This may result from a problem with your inputs or it may indicate a programming mistake in this function or ArcGIS itself. Please check your inputs and try again. Also review any preceding error messages and the detailed error information that appears at the end of this message. If you suspect a programming mistake in this function or ArcGIS, please contact the author of this function for assistance. Detailed error information: The following exception was raised when the property was assigned: %s') % (name, self._Name, id(self._Object), valueStr, _FormatCOMError(hr, msg, exc, arg)), sys.exc_info()[1]) 628 679 629 680 # If we did not import pythoncom, set the value and allow the outer … … 647 698 else: 648 699 valueStr = repr(value) 649 raise ArcGISError(_(u'Failed to set the %s property of ArcGIS %s object 0x%08X to %s. This may result from a problem with your inputs or it may indicate a programming mistake in this tool or ArcGIS itself. Please check your inputs and try again. Also review any preceding error messages and the detailed error information that appears at the end of this message. If you suspect a programming mistake in this tool or ArcGIS, please contact the author of this toolfor assistance. Detailed error information: The following exception was raised when the property was assigned: %s: %s') % (name, self._Name, id(self._Object), valueStr, e.__class__.__name__, unicode(e)), e)700 raise ArcGISError(_(u'Failed to set the %s property of ArcGIS %s object 0x%08X to %s. This may result from a problem with your inputs or it may indicate a programming mistake in this function or ArcGIS itself. Please check your inputs and try again. Also review any preceding error messages and the detailed error information that appears at the end of this message. If you suspect a programming mistake in this function or ArcGIS, please contact the author of this function for assistance. Detailed error information: The following exception was raised when the property was assigned: %s: %s') % (name, self._Name, id(self._Object), valueStr, e.__class__.__name__, unicode(e)), e) 650 701 651 702 # Log the set value. … … 699 750 except com_error, (hr, msg, exc, arg): 700 751 self._LogReturnedGeoprocessingMessages() 701 raise ArcGISError(_(u'An ArcGIS geoprocessing function failed. This usually results from a problem with your inputs. Please check them and try again. Also review any preceding error messages and the detailed error information that appears at the end of this message. If you suspect the failure is due to a programming mistake in this tool or ArcGIS, please contact the author of this toolfor assistance. Detailed error information: ArcGIS %s object 0x%08X: Invocation of %s%s raised %s') % (self._Name, id(self._Object), method.__name__, inspect.formatargvalues(_args, _varargs, _varkw, _locals), _FormatCOMError(hr, msg, exc, arg)), sys.exc_info()[1])752 raise ArcGISError(_(u'An ArcGIS geoprocessing function failed. This usually results from a problem with your inputs. Please check them and try again. Also review any preceding error messages and the detailed error information that appears at the end of this message. If you suspect the failure is due to a programming mistake in this function or ArcGIS, please contact the author of this function for assistance. Detailed error information: ArcGIS %s object 0x%08X: Invocation of %s%s raised %s') % (self._Name, id(self._Object), method.__name__, inspect.formatargvalues(_args, _varargs, _varkw, _locals), _FormatCOMError(hr, msg, exc, arg)), sys.exc_info()[1]) 702 753 703 754 # If we did not import pythoncom, invoke the method and allow the … … 717 768 except Exception, e: 718 769 self._LogReturnedGeoprocessingMessages() 719 raise ArcGISError(_(u'An ArcGIS geoprocessing function failed. This usually results from a problem with your inputs. Please check them and try again. Also review any preceding error messages and the detailed error information that appears at the end of this message. If you suspect the failure is due to a programming mistake in this tool or ArcGIS, please contact the author of this toolfor assistance. Detailed error information: ArcGIS %s object 0x%08X: Invocation of %s%s raised %s: %s') % (self._Name, id(self._Object), method.__name__, inspect.formatargvalues(_args, _varargs, _varkw, _locals), e.__class__.__name__, unicode(e)), e)770 raise ArcGISError(_(u'An ArcGIS geoprocessing function failed. This usually results from a problem with your inputs. Please check them and try again. Also review any preceding error messages and the detailed error information that appears at the end of this message. If you suspect the failure is due to a programming mistake in this function or ArcGIS, please contact the author of this function for assistance. Detailed error information: ArcGIS %s object 0x%08X: Invocation of %s%s raised %s: %s') % (self._Name, id(self._Object), method.__name__, inspect.formatargvalues(_args, _varargs, _varkw, _locals), e.__class__.__name__, unicode(e)), e) 720 771 721 772 # The method executed successfully. Log any geoprocessing messages it … … 753 804 i = 0 754 805 try: 755 realGeoprocessor = Ge tRealGeoprocessor()806 realGeoprocessor = GeoprocessorManager.GetGeoprocessor() 756 807 while i < realGeoprocessor.MessageCount: 757 808 sev = realGeoprocessor.GetSeverity(i) … … 841 892 u'fidset' : None, 842 893 u'PropertySet' : None} 894 895 896 ############################################################################### 897 # Metadata: module 898 ############################################################################### 899 900 AddModuleMetadata(shortDescription=_(u'Provides utility functions for interacting with the ESRI ArcGIS software package.')) 901 902 ############################################################################### 903 # Metadata: GeoprocessorManager class 904 ############################################################################### 905 906 AddClassMetadata(GeoprocessorManager, 907 shortDescription=_(u'Manages the instance of the ArcGIS geoprocessor object used whenever any GeoEco function needs to invoke ArcGIS tools.'), 908 isExposedByIDispatch=True, 909 comIID=u'{3DAAF9BD-2C7F-4A0B-8AB1-8975103F3E78}', 910 comCLSID=u'{6E4B25C1-0E1D-496B-A661-AC75ADCB24C8}') 911 912 # Public properties 913 914 AddPropertyMetadata(GeoprocessorManager.Geoprocessor, 915 typeMetadata=AnyPythonInstance(canBeNone=True), 916 shortDescription=_(u'The ArcGIS geoprocessor object used whenever any GeoEco function needs to invoke ArcGIS tools.'), 917 longDescription=_( 918 u"""This property is a singleton; all Python modules running in the same 919 instance of the Python interpreter share the same value for this property. This 920 property remains empty until it is explicitly set, or the InitializeGeoprocessor 921 method is explicitly invoked, or a GeoEco function that has a dependency on 922 ArcGIS is invoked (in which case it will invoke InitializeGeoprocessor). 923 924 If you want to invoke GeoEco functions from your own ArcGIS geoprocessing script 925 and you have already obtained a geoprocessor object, you should set this 926 property to that object before invoking any other GeoEco functions. Failing to 927 do so will cause GeoEco to allocate its own geoprocessor object, which can yield 928 unpredictable results. (As far as I can tell, the ArcGIS tools still work 929 correctly, but log messages do not end up in the ArcGIS GUIs.) 930 931 If your geoprocessing script has not yet obtained the geoprocessor object, you 932 may allow the GeoEco functions to obtain one when they first need it and then 933 retrieve it by getting the value of this property. 934 935 If you want to invoke GeoEco functions from something that is not a 936 "geoprocessing script" (a program that does not invoke any ArcGIS 937 geoprocessing tools directly), then you should ignore this property and 938 allow the GeoEco functions to obtain and use their own geoprocessor object. 939 940 See the documentation for InitializeGeoprocessor for more information about this 941 property."""), 942 devTeamNotes=_( 943 u"""Generally, GeoEco functions should *not* use this property; they should use 944 WrappedGeoprocessor instead. That property implements a wrapper around the 945 geoprocessor that logs debug messages every time the geoprocessor is invoked."""), 946 isExposedByIDispatch=True) 947 948 AddPropertyMetadata(GeoprocessorManager.WrappedGeoprocessor, 949 typeMetadata=AnyPythonInstance(canBeNone=True), 950 shortDescription=_(u'The Geoprocessor property, wrapped by a class that logs messages whenever the geoprocessor is accessed.'), 951 longDescription=_( 952 u"""This property is a singleton; all Python modules running in the same 953 instance of the Python interpreter share the same value for this property. It is 954 initialized whenever the Geoprocessor property is initialized; see the 955 documentation for that property for more information. 956 957 This property is actually a wrapper class around the ArcGIS geoprocessor object. 958 The wrapper exports the same interface as the wrapped object but logs a debug 959 message every time a method is invoked or a property is accessed. By default, 960 these debug messages are discarded by the GeoEco logging infrastructure. You can 961 enable them by initializing the Logger class with a custom configuration file 962 or by editing the default configuration file. See the Logger class documentation 963 for more information. 964 965 All GeoEco functions use WrappedGeoprocessor to access the geoprocessor, rather 966 than the Geoprocessor property, so that debug messages are reported whenever any 967 function accesses the geoprocessor. External callers are welcome to use 968 WrappedGeoprocessor as well, but they should consider using Geoprocessor 969 instead, to completely eliminate the chance that a bug in the wrapper would 970 affect their code."""), 971 devTeamNotes=_(u'Generally, GeoEco functions should use this property rather than the Geoprocessor property.'), 972 isExposedByIDispatch=True) 973 974 AddPropertyMetadata(GeoprocessorManager.ArcGISMajorVersion, 975 typeMetadata=PythonInteger(canBeNone=True), 976 shortDescription=_(u'The major version number for ArcGIS, if it is installed on the machine.'), 977 longDescription=_(u'This property is empty if ArcGIS is not installed on the machine.'), 978 isExposedByIDispatch=True) 979 980 AddPropertyMetadata(GeoprocessorManager.ArcGISMinorVersion, 981 typeMetadata=PythonInteger(canBeNone=True), 982 shortDescription=_(u'The minor version number for ArcGIS, if it is installed on the machine.'), 983 longDescription=_(u'This property is empty if ArcGIS is not installed on the machine.'), 984 isExposedByIDispatch=True) 985 986 AddPropertyMetadata(GeoprocessorManager.ArcGISServicePack, 987 typeMetadata=PythonInteger(canBeNone=True), 988 shortDescription=_(u'The service pack number for ArcGIS, if it is installed on the machine.'), 989 longDescription=_(u'This property is empty if ArcGIS is not installed on the machine.'), 990 isExposedByIDispatch=True) 991 992 # Public method: GetGeoprocessor 993 994 AddMethodMetadata(GeoprocessorManager.GetGeoprocessor, 995 shortDescription=_(u'Returns the value of the Geoprocessor property.')) 996 997 AddArgumentMetadata(GeoprocessorManager.GetGeoprocessor, u'cls', 998 typeMetadata=PythonClassOrClassInstance(cls=GeoprocessorManager), 999 description=_(u'%s class or an instance of it.') % GeoprocessorManager.__name__) 1000 1001 AddResultMetadata(GeoprocessorManager.GetGeoprocessor, u'geoprocessor', 1002 typeMetadata=AnyPythonInstance(canBeNone=True), 1003 description=_(u'The value of the Geoprocessor property.')) 1004 1005 # Public method: SetGeoprocessor 1006 1007 AddMethodMetadata(GeoprocessorManager.SetGeoprocessor, 1008 shortDescription=_(u'Sets the value of the Geoprocessor property.')) 1009 1010 AddArgumentMetadata(GeoprocessorManager.SetGeoprocessor, u'cls', 1011 typeMetadata=PythonClassOrClassInstance(cls=GeoprocessorManager), 1012 description=_(u'%s class or an instance of it.') % GeoprocessorManager.__name__) 1013 1014 AddArgumentMetadata(GeoprocessorManager.SetGeoprocessor, u'geoprocessor', 1015 typeMetadata=AnyPythonInstance(), 1016 description=_(u'The ArcGIS geoprocessor object obtained from COM or the arcgisscripting Python module. See the documentation for the Geoprocessor property for more information.')) 1017 1018 # Public method: GetWrappedGeoprocessor 1019 1020 AddMethodMetadata(GeoprocessorManager.GetWrappedGeoprocessor, 1021 shortDescription=_(u'Returns the value of the WrappedGeoprocessor property.')) 1022 1023 AddArgumentMetadata(GeoprocessorManager.GetWrappedGeoprocessor, u'cls', 1024 typeMetadata=PythonClassOrClassInstance(cls=GeoprocessorManager), 1025 description=_(u'%s class or an instance of it.') % GeoprocessorManager.__name__) 1026 1027 AddResultMetadata(GeoprocessorManager.GetWrappedGeoprocessor, u'geoprocessor', 1028 typeMetadata=AnyPythonInstance(canBeNone=True), 1029 description=_(u'The value of the WrappedGeoprocessor property.')) 1030 1031 # Public method: GetArcGISMajorVersion 1032 1033 AddMethodMetadata(GeoprocessorManager.GetArcGISMajorVersion, 1034 shortDescription=_(u'Returns the value of the ArcGISMajorVersion property.')) 1035 1036 AddArgumentMetadata(GeoprocessorManager.GetArcGISMajorVersion, u'cls', 1037 typeMetadata=PythonClassOrClassInstance(cls=GeoprocessorManager), 1038 description=_(u'%s class or an instance of it.') % GeoprocessorManager.__name__) 1039 1040 AddResultMetadata(GeoprocessorManager.GetArcGISMajorVersion, u'majorVersion', 1041 typeMetadata=PythonInteger(canBeNone=True), 1042 description=_(u'The value of the ArcGISMajorVersion property.')) 1043 1044 # Public method: GetArcGISMinorVersion 1045 1046 AddMethodMetadata(GeoprocessorManager.GetArcGISMinorVersion, 1047 shortDescription=_(u'Returns the value of the ArcGISMinorVersion property.')) 1048 1049 AddArgumentMetadata(GeoprocessorManager.GetArcGISMinorVersion, u'cls', 1050 typeMetadata=PythonClassOrClassInstance(cls=GeoprocessorManager), 1051 description=_(u'%s class or an instance of it.') % GeoprocessorManager.__name__) 1052 1053 AddResultMetadata(GeoprocessorManager.GetArcGISMinorVersion, u'minorVersion', 1054 typeMetadata=PythonInteger(canBeNone=True), 1055 description=_(u'The value of the ArcGISMinorVersion property.')) 1056 1057 # Public method: GetArcGISServicePack 1058 1059 AddMethodMetadata(GeoprocessorManager.GetArcGISServicePack, 1060 shortDescription=_(u'Returns the value of the ArcGISServicePack property.')) 1061 1062 AddArgumentMetadata(GeoprocessorManager.GetArcGISServicePack, u'cls', 1063 typeMetadata=PythonClassOrClassInstance(cls=GeoprocessorManager), 1064 description=_(u'%s class or an instance of it.') % GeoprocessorManager.__name__) 1065 1066 AddResultMetadata(GeoprocessorManager.GetArcGISServicePack, u'servicePack', 1067 typeMetadata=PythonInteger(canBeNone=True), 1068 description=_(u'The value of the ArcGISMinorVersion property.')) 1069 1070 # Public method: InitializeGeoprocessor 1071 1072 AddMethodMetadata(GeoprocessorManager.InitializeGeoprocessor, 1073 shortDescription=_(u'Initializes the Geoprocessor property with a new ArcGIS geoprocessor object.'), 1074 longDescription=_( 1075 u"""Generally, this method should only be invoked by GeoEco classes. There is 1076 no need for external callers to invoke this function. They should allow GeoEco 1077 classes to invoke it internally, or obtain their own goeprocessor object from 1078 ArcGIS and then set the Geoprocessor property. 1079 1080 If the Geoprocessor property is not empty, this method returns without doing 1081 anything. If it is empty, this method attempts to obtain a geoprocessor object 1082 using the following procedure: 1083 1084 * Import the arcgisscripting Python package and invoke the create method. This 1085 will succeed if ArcGIS 9.2 or later is installed on the machine. If this 1086 succeeds, the returned object is an unknown type. (Note: because I have not 1087 tried ArcGIS 9.2 yet, I don't know what kind of object is returned. If it is 1088 not an IDispatch interface, then it cannot be returned to COM callers. If you 1089 are calling InitializeGeoprocessor using COM, I am not sure what will happen. 1090 I will investigate this as soon as I can install ArcGIS 9.2.) 1091 1092 * If the step above fails, create the "esriGeoprocessing.GPDispatch" COM object 1093 using the Dispatch function provided by the win32com.client Python package. 1094 If this succeeds, the returned object is the COM IDispatch interface for the 1095 geoprocessor object."""), 1096 isExposedByIDispatch=True) 1097 1098 AddArgumentMetadata(GeoprocessorManager.InitializeGeoprocessor, u'cls', 1099 typeMetadata=PythonClassOrClassInstance(cls=GeoprocessorManager), 1100 description=_(u'%s class or an instance of it.') % GeoprocessorManager.__name__) 1101 1102 # Public method: InitializeGeoprocessorForDependency 1103 1104 AddMethodMetadata(GeoprocessorManager.InitializeGeoprocessorForDependency, 1105 shortDescription=_(u'Initializes the Geoprocessor property with a new ArcGIS geoprocessor object on behalf of the specified dependency declared by a GeoEco class method.'), 1106 longDescription=_(u'This method should only be invoked directly by the GeoEco.ArcGIS.ArcGISVersion class.')) 1107 1108 AddArgumentMetadata(GeoprocessorManager.InitializeGeoprocessorForDependency, u'cls', 1109 typeMetadata=PythonClassOrClassInstance(cls=GeoprocessorManager), 1110 description=_(u'%s class or an instance of it.') % GeoprocessorManager.__name__) 1111 1112 AddArgumentMetadata(GeoprocessorManager.InitializeGeoprocessorForDependency, u'dependency', 1113 typeMetadata=PythonClassInstance(cls=GeoEco.Metadata.Dependency, canBeNone=True), 1114 description=_(u'An instance of the %s class, or None if the invocation is not occurring on behalf of a dependency.') % GeoEco.Metadata.Dependency.__name__) MGET/Trunk/PythonPackage/src/GeoEco/Configuration/Logging.txt
r18 r25 23 23 # impossible to track them down. For this reason, ALWAYS make a backup 24 24 # copy of your file and change JUST A LITTLE AT A TIME so that 25 # mistakes are easier to trac dk down.25 # mistakes are easier to track down. 26 26 27 # The handlers specify the types of destinations of log messages: 27 # The handlers specify the possible destinations for log messages. Python 28 # provides more than the default ones you see here: 28 29 29 30 [handlers] … … 54 55 55 56 [loggers] 56 keys=root,GeoEco,ArcGIS 57 keys=root,GeoEco,ArcGIS,COM 57 58 58 59 # Log GeoEco informational, warning and error messages to the console. 59 60 # and to ArcGIS. To log debug messages as well, change "level=INFO" 60 61 # to "level=DEBUG". But rather than editing the default GeoEco logging 61 # configuration file, consider making a copy 62 # configuration file, consider making a copy and explicitly initializing the 63 # logging system with your own file. 64 # 65 # Note: During the initial GeoEco development cycle, we are setting level=DEBUG 66 # instead of level=INFO. 62 67 63 68 [logger_GeoEco] 64 level= INFO69 level=DEBUG 65 70 handlers=Console,ArcGIS 66 71 propagate=0 … … 68 73 69 74 # Only log warnings and errors from GeoEco.ArcGIS. Change "level=WARNING" 70 # to "level=DEBUG" to see a complete trace of interactions between GeoEco 71 # and the ArcGIS geoprocessor. 75 # to "level=INFO" to see the messages reported by ArcGIS any time GeoEco invokes 76 # an ArcGIS geoprocessing tool. Change it to "level=DEBUG" to see a complete 77 # low-level trace of all interactions between GeoEco and the ArcGIS 78 # geoprocessor (a message will be generated every time GeoEco accesses a 79 # property or invokes a method of the geoprocessor). 80 # 81 # Note: During the initial GeoEco development cycle, we are setting level=DEBUG 82 # instead of level=WARNING. 72 83 73 84 [logger_ArcGIS] 74 level= INFO85 level=DEBUG 75 86 handlers=Console,ArcGIS 76 87 propagate=0 77 88 qualname=GeoEco.ArcGIS 89 90 # Only log warnings and errors from GeoEco.COM. Change "level=WARNING" 91 # to "level=DEBUG" to see a complete low-level trace of calls to properties and 92 # methods of GeoEco classes made through COM. This is useful for debugging 93 # obscure COM problems but not much else. 94 # 95 # WARNING: *DO NOT* add ArcGIS to the list of handlers; you will create an 96 # infinite loop! 97 # 98 # Note: During the initial GeoEco development cycle, we are setting level=DEBUG 99 # instead of level=WARNING. 100 101 [logger_COM] 102 level=DEBUG 103 handlers=Console 104 propagate=0 105 qualname=GeoEco.COM 78 106 79 107 # Log warnings and errors from any non-GeoEco component to the console. MGET/Trunk/PythonPackage/src/GeoEco/Dependencies.py
r16 r25 51 51 if self.MinimumServicePack > 0: 52 52 osName = _(u'%s Service Pack %i') % (osName, self.MinimumServicePack) 53 raise UnsupportedPlatformError(_(u'This toolrequires Microsoft Windows %s, or a later version of Windows.') % osName, self)53 raise UnsupportedPlatformError(_(u'This function requires Microsoft Windows %s, or a later version of Windows.') % osName, self) 54 54 55 55 … … 66 66 patchlevel = self.__ParseVersionNumber(v[2]) 67 67 if self.MinimumVersion[0] > major or self.MinimumVersion[0] == major and self.MinimumVersion[1] > minor or self.MinimumVersion[0] == major and self.MinimumVersion[1] == minor and self.MinimumVersion[2] > patchlevel: 68 raise SoftwareNotInstalledError(_(u'This toolrequires Python version %i.%i.%i (or newer). Version %s is currently running. Please ensure the required version (or newer) is installed. Also ensure that the GeoEco package is installed under that Python installation (if you reinstall Python, you have to reinstall GeoEco). Finally, ensure the operating system is configured to invoke the required version of Python when it interprets Python scripts, rather than an older version of Python. On Windows, you must configure a "file association" that associates the newer version of Python with .py files.') % (self.MinimumVersion[0], self.MinimumVersion[1], self.MinimumVersion[2], platform.python_version()), self)68 raise SoftwareNotInstalledError(_(u'This function requires Python version %i.%i.%i (or newer). Version %s is currently running. Please ensure the required version (or newer) is installed. Also ensure that the GeoEco package is installed under that Python installation (if you reinstall Python, you have to reinstall GeoEco). Finally, ensure the operating system is configured to invoke the required version of Python when it interprets Python scripts, rather than an older version of Python. On Windows, you must configure a "file association" that associates the newer version of Python with .py files.') % (self.MinimumVersion[0], self.MinimumVersion[1], self.MinimumVersion[2], platform.python_version()), self) 69 69 70 70 @classmethod … … 97 97 except Exception, e: 98 98 if self.DisplayName is None: 99 message = _(u'This toolrequires the "%s" Python package. Please verify that it is properly installed for the running version of Python (%s.%s).') % (self.ImportName, unicode(platform.python_version_tuple()[0]), unicode(platform.python_version_tuple()[1]))99 message = _(u'This function requires the "%s" Python package. Please verify that it is properly installed for the running version of Python (%s.%s).') % (self.ImportName, unicode(platform.python_version_tuple()[0]), unicode(platform.python_version_tuple()[1])) 100 100 else: 101 message = _(u'This toolrequires the "%s" Python package. Please verify that it is properly installed for the running version of Python (%s.%s).') % (self.DisplayName, unicode(platform.python_version_tuple()[0]), unicode(platform.python_version_tuple()[1]))101 message = _(u'This function requires the "%s" Python package. Please verify that it is properly installed for the running version of Python (%s.%s).') % (self.DisplayName, unicode(platform.python_version_tuple()[0]), unicode(platform.python_version_tuple()[1])) 102 102 if self.CheeseShopName is not None and self.AlternateURL is None: 103 103 message = _(u'%s The package may be available at http://www.python.org/pypi/%s.') % (message, self.CheeseShopName) MGET/Trunk/PythonPackage/src/GeoEco/Exceptions.py
r16 r25 19 19 20 20 def __unicode__(self): 21 return _(u'Execution failed because this toolis running on an unsupported operating system or processor architecture. %s') % self.Message21 return _(u'Execution failed because this function is running on an unsupported operating system or processor architecture. %s') % self.Message 22 22 23 23 def AsCOMException(): MGET/Trunk/PythonPackage/src/GeoEco/Logging.py
r16 r25 7 7 import GeoEco 8 8 import GeoEco.ArcGIS 9 from GeoEco.Metadata import * 9 10 from GeoEco.Internationalization import _ 10 11 11 12 12 # Public functions exported by this module 13 14 def LogDebug(format, *args, **kwargs): 15 try: 16 logging.getLogger(u'GeoEco').debug(format, *args, **kwargs) 17 except: 18 pass 19 20 def LogInfo(format, *args, **kwargs): 21 try: 22 logging.getLogger(u'GeoEco').info(format, *args, **kwargs) 23 except: 24 pass 25 26 def LogWarning(format, *args, **kwargs): 27 try: 28 logging.getLogger(u'GeoEco').warning(format, *args, **kwargs) 29 except: 30 pass 31 32 def LogError(format, *args, **kwargs): 33 try: 34 logging.getLogger(u'GeoEco').error(format, *args, **kwargs) 35 except: 36 pass 37 38 def InitializeLogging(loggingConfigFile=None): 39 40 if not isinstance(loggingConfigFile, (types.NoneType, types.UnicodeType)): 41 raise TypeError, _(u'loggingConfigFile, if provided, must be a Unicode string') 42 43 # Hack: this module (GeoEco.Logging) defines a class _ArcGISLoggingHandler 44 # which derives from logging.Handler. We want the user to be able to 45 # reference this handler in a logging configuration file. But the logging.config 46 # module offers no way to import this module into its namespace, which 47 # prevents it from being able to instantiate our class. So we must manually 48 # import ourself into the logging namespace (! not logging.config !). 49 50 if not sys.modules[u'logging'].__dict__.has_key(u'GeoEco'): 51 sys.modules[u'logging'].__dict__[u'GeoEco'] = sys.modules[u'GeoEco'] 52 if not sys.modules[u'logging'].__dict__.has_key(u'GeoEco.Logging'): 53 sys.modules[u'logging'].__dict__[u'GeoEco.Logging'] = sys.modules[u'GeoEco.Logging'] 54 55 # If the caller provided a file, try to initialize the logging system 56 # from it. 57 58 callersFileWarning = None 59 if loggingConfigFile is not None: 60 callersFileWarning = _InitializeLoggingFromFile(loggingConfigFile) 61 62 # If the caller did not provide a file, or the logging system could not 63 # be initialized from it, try the default logging config file. 64 65 defaultFileWarning = None 66 defaultLoggingConfigFile = os.path.join(GeoEco.ConfigurationDir, u'Logging.txt') 67 if loggingConfigFile is None or callersFileWarning is not None: 68 defaultFileWarning = _InitializeLoggingFromFile(defaultLoggingConfigFile) 69 70 # If we failed to initialize from either the caller's file or the 71 # default file, initialize using a hard-coded configuration. 72 73 manualInitializationWarning = None 13 # Public classes exposed by this module 14 15 class Logger(object): 16 __doc__ = GeoEco.Metadata.DynamicDocString() 74 17 75 if (loggingConfigFile is None or callersFileWarning is not None) and defaultFileWarning is not None: 76 try: 77 stdout_handler = logging.StreamHandler(strm=sys.stdout) 78 stdout_handler.level = logging.INFO 79 logging.getLogger(u'').addHandler(stdout_handler) 80 logging.getLogger(u'').setLevel(logging.INFO) 18 @classmethod 19 def Debug(cls, format, *args): 20 try: 21 logging.getLogger(u'GeoEco').debug(format, *args) 22 except: 23 pass 24 25 @classmethod 26 def Info(cls, format, *args): 27 try: 28 logging.getLogger(u'GeoEco').info(format, *args) 29 except: 30 pass 31 32 @classmethod 33 def Warning(cls, format, *args): 34 try: 35 logging.getLogger(u'GeoEco').warning(format, *args) 36 except: 37 pass 38 39 @classmethod 40 def Error(cls, format, *args): 41 try: 42 logging.getLogger(u'GeoEco').error(format, *args) 43 except: 44 pass 45 46 @classmethod 47 def Initialize(cls, loggingConfigFile=None, activateArcGISLogging=False): 48 49 if not isinstance(loggingConfigFile, (types.NoneType, types.UnicodeType)): 50 raise TypeError, _(u'loggingConfigFile, if provided, must be a Unicode string') 51 52 if not isinstance(activateArcGISLogging, (types.NoneType, types.BooleanType)): 53 raise TypeError, _(u'activateArcGISLogging, if provided, must be a boolean') 54 55 # Hack: this module (GeoEco.Logging) defines a class _ArcGISLoggingHandler 56 # which derives from logging.Handler. We want the user to be able to 57 # reference this handler in a logging configuration file. But the logging.config 58 # module offers no way to import this module into its namespace, which 59 # prevents it from being able to instantiate our class. So we must manually 60 # import ourself into the logging namespace (! not logging.config !). 61 62 if not sys.modules[u'logging'].__dict__.has_key(u'GeoEco'): 63 sys.modules[u'logging'].__dict__[u'GeoEco'] = sys.modules[u'GeoEco'] 64 if not sys.modules[u'logging'].__dict__.has_key(u'GeoEco.Logging'): 65 sys.modules[u'logging'].__dict__[u'GeoEco.Logging'] = sys.modules[u'GeoEco.Logging'] 66 67 # If the caller provided a file, try to initialize the logging system 68 # from it. 69 70 callersFileWarning = None 71 if loggingConfigFile is not None: 72 callersFileWarning = cls._InitializeLoggingFromFile(loggingConfigFile) 73 74 # If the caller did not provide a file, or the logging system could not 75 # be initialized from it, try the default logging config file. 76 77 defaultFileWarning = None 78 defaultLoggingConfigFile = os.path.join(GeoEco.ConfigurationDir, u'Logging.txt') 79 if loggingConfigFile is None or callersFileWarning is not None: 80 defaultFileWarning = cls._InitializeLoggingFromFile(defaultLoggingConfigFile) 81 82 # If we failed to initialize from either the caller's file or the 83 # default file, initialize using a hard-coded configuration. 84 85 manualInitializationWarning = None 86 87 if (loggingConfigFile is None or callersFileWarning is not None) and defaultFileWarning is not None: 88 try: 89 stdout_handler = logging.StreamHandler(strm=sys.stdout) 90 stdout_handler.level = logging.INFO 91 logging.getLogger(u'').addHandler(stdout_handler) 92 logging.getLogger(u'').setLevel(logging.INFO) 93 except Exception, e: 94 manualInitializationWarning = _(u'Failed to initialize the logging system from hard-coded settings. One of the logging functions reported the error: ') + unicode(e) 95 96 # Log warning messages, if any, and a success message. We have to delay of 97 # all this until now, because until this point, the logging system may not 98 # have been initialized. If we were able to initialize it, we want any 99 # warning messages to be logged using the best possible settings. 100 101 if (loggingConfigFile is None or callersFileWarning is not None) and defaultFileWarning is not None and manualInitializationWarning is not None: 102 if callersFileWarning is not None: 103 print(callersFileWarning) 104 print(defaultFileWarning) 105 print(manualInitializationWarning) 106 print(_(u'The logging system could not be initialized. Log messages will not be reported.')) 107 elif loggingConfigFile is not None and callersFileWarning is None: 108 cls.Info(_(u'Logging system initialized from config file "%s".'), loggingConfigFile) 109 elif defaultFileWarning is None: 110 if callersFileWarning is not None: 111 cls.Warning(callersFileWarning) 112 cls.Info(_(u'Logging system initialized from config file "%s".'), defaultLoggingConfigFile) 113 elif manualInitializationWarning is None: 114 if callersFileWarning is not None: 115 cls.Warning(callersFileWarning) 116 if defaultFileWarning is not None: 117 cls.Warning(defaultFileWarning) 118 cls.Info(_(u'Log messages will only be sent to the console output (stdout).')) 119 else: 120 raise AssertionError, u'This line of code should never be executed.' 121 122 # Active ArcGIS logging if requested. 123 124 if activateArcGISLogging: 125 cls.ActivateArcGISLogging() 126 127 @classmethod 128 def ActivateArcGISLogging(cls): 129 _ArcGISLoggingHandler.Activate() 130 131 @classmethod 132 def _InitializeLoggingFromFile(cls, loggingConfigFile=None): 133 assert isinstance(loggingConfigFile, types.UnicodeType), u'loggingConfigFile must be a Unicode string' 134 135 # Try to open the file for reading, so we know it is accessible. 136 137 try: 138 f = file(loggingConfigFile, u'r') 81 139 except Exception, e: 82 manualInitializationWarning = _(u'Failed to initialize the logging system from hard-coded settings. One of the logging functions reported the error: ') + unicode(e) 83 84 # Log warning messages, if any, and a success message. We have to delay of 85 # all this until now, because until this point, the logging system may not 86 # have been initialized. If we were able to initialize it, we want any 87 # warning messages to be logged using the best possible settings. 88 89 if (loggingConfigFile is None or callersFileWarning is not None) and defaultFileWarning is not None and manualInitializationWarning is not None: 90 if callersFileWarning is not None: 91 print(callersFileWarning) 92 print(defaultFileWarning) 93 print(manualInitializationWarning) 94 print(_(u'The logging system could not be initialized. Log messages will not be reported.')) 95 elif loggingConfigFile is not None and callersFileWarning is None: 96 LogInfo(_(u'Logging system initialized from config file "%s".'), loggingConfigFile) 97 elif defaultFileWarning is None: 98 if callersFileWarning is not None: 99 LogWarning(callersFileWarning) 100 LogInfo(_(u'Logging system initialized from config file "%s".'), defaultLoggingConfigFile) 101 elif manualInitializationWarning is None: 102 if callersFileWarning is not None: 103 LogWarning(callersFileWarning) 104 if defaultFileWarning is not None: 105 LogWarning(defaultFileWarning) 106 LogInfo(_(u'Log messages will only be sent to the console output (stdout).')) 107 else: 108 raise AssertionError, u'This line of code should never be executed.' 109 110 def ActivateArcGISLogging(): 111 _ArcGISLoggingHandler.Activate() 140 return(_(u'Failed to initialize logging from the config file "%s". The file could not be opened. The operating system reported the error: %s') % (loggingConfigFile, unicode(e).strip())) 141 try: 142 f.close() 143 except: 144 pass 145 146 # If that was successful, try to initialize logging. 147 # 148 # If the logging config file is improperly formatted, the logging 149 # initialization function can fail in two ways. First, it may raise an 150 # exception. In this case, catch it as usual and return a failure 151 # message. 152 # 153 # In the second failure mode, it simply prints an exception trace to 154 # stderr, but does not raise an exception or return a value indicating 155 # failure. This would be ok, except that it can leave the logging system 156 # in an inconsistent state: subsequent calls to logging functions such 157 # as logging.debug() will fail. Again, these failed calls swallow 158 # exceptions, just printing their traces to stderr. 159 # 160 # Because we don't want stderr to be spammed when logging fails to 161 # initialize, we detect the failure in the logging configuration 162 # function by capturing stderr, and return a failure message. 163 164 cap = _StderrCapturer() 165 cap.Start() 166 try: 167 try: 168 # First handle a bug in logging.config.fileConfig that causes the 169 # logging Handler class to raise an exception at shutdown. This bug 170 # was reported in Aug 2006 and exists in Python 2.4.4 but is 171 # supposedly fixed in Python 2.5. 172 173 if globals().has_key(u'_TempHandler') and globals()[u'_TempHandler'] is not None: 174 logging.getLogger(u'GeoEco').removeHandler(globals()[u'_TempHandler']) 175 globals()[u'_TempHandler'].close() 176 del globals()[u'_TempHandler'] 177 178 # Now read the config file. 179 180 logging.config.fileConfig(loggingConfigFile) 181 182 except Exception, e: 183 return _(u'Failed to initialize logging from the config file "%s". Please verify that the contents of the config file are valid. Search the Python documentation for "logging configuration file format". In Python 2.4, the article is titled "6.29.10.2 Configuration file format". Python\'s log configuration file parser (logging.config.fileConfig) reported the error: %s') % (loggingConfigFile, unicode(e).strip()) 184 finally: 185 result = cap.Stop() 186 187 if result is not None and len(result.strip()) > 0: 188 result_lines = result.strip().split(u'\n') 189 i = 1 190 while i < len(result_lines) and (len(result_lines[i]) == 0 or result_lines[i][0] == u' '): 191 i = i + 1 192 message = u'' 193 for j in range(i, len(result_lines)): 194 message = message + result_lines[j] + u'\n' 195 message = message.strip() 196 return _(u'Failed to initialize logging from the config file "%s". Please verify that the contents of the config file are valid. Search the Python documentation for "logging configuration file format". In Python 2.4, the article is titled "6.29.10.2 Configuration file format". Python\'s log configuration file parser (logging.config.fileConfig) reported the error: %s') % (loggingConfigFile, message) 197 198 # Return successfully. 199 200 return None 201 112 202 113 203 # Private classes and functions global to this module … … 137 227 message = self.format(record) 138 228 if record.levelno >= logging.ERROR: 139 GeoEco.ArcGIS.Ge tRealGeoprocessor().AddError(message)229 GeoEco.ArcGIS.GeoprocessorManager.GetGeoprocessor().AddError(message) 140 230 elif record.levelno >= logging.WARNING: 141 GeoEco.ArcGIS.Ge tRealGeoprocessor().AddWarning(message)231 GeoEco.ArcGIS.GeoprocessorManager.GetGeoprocessor().AddWarning(message) 142 232 else: 143 GeoEco.ArcGIS.Ge tRealGeoprocessor().AddMessage(message)233 GeoEco.ArcGIS.GeoprocessorManager.GetGeoprocessor().AddMessage(message) 144 234 except: 145 235 self.handleError(record) … … 152 242 def Activate(cls): 153 243 if cls._PreactivationQueue is not None: 154 if GeoEco.ArcGIS.Ge tRealGeoprocessor() is None:155 GeoEco.ArcGIS. InitializeGeoprocessor()244 if GeoEco.ArcGIS.GeoprocessorManager.GetGeoprocessor() is None: 245 GeoEco.ArcGIS.GeoprocessorManager.InitializeGeoprocessor() 156 246 while len(cls._PreactivationQueue) > 0: 157 247 record = cls._PreactivationQueue.pop(0) … … 163 253 _PreactivationQueue = [] 164 254 165 def _InitializeLoggingFromFile(loggingConfigFile=None): 166 167 assert isinstance(loggingConfigFile, types.UnicodeType), u'loggingConfigFile must be a Unicode string' 168 169 # Try to open the file for reading, so we know it is accessible. 170 171 try: 172 f = file(loggingConfigFile, u'r') 173 except Exception, e: 174 return(_(u'Failed to initialize logging from the config file "%s". The file could not be opened. The operating system reported the error: %s') % (loggingConfigFile, unicode(e).strip())) 175 try: 176 f.close() 177 except: 178 pass 179 180 # If that was successful, try to initialize logging. 181 # 182 # If the logging config file is improperly formatted, the logging 183 # initialization function can fail in two ways. First, it may raise an 184 # exception. In this case, catch it as usual and return a failure 185 # message. 186 # 187 # In the second failure mode, it simply prints an exception trace to 188 # stderr, but does not raise an exception or return a value indicating 189 # failure. This would be ok, except that it can leave the logging system 190 # in an inconsistent state: subsequent calls to logging functions such 191 # as logging.debug() will fail. Again, these failed calls swallow 192 # exceptions, just printing their traces to stderr. 193 # 194 # Because we don't want stderr to be spammed when logging fails to 195 # initialize, we detect the failure in the logging configuration 196 # function by capturing stderr, and return a failure message. 197 198 cap = StderrCapturer() 199 cap.Start() 200 try: 201 try: 202 # First handle a bug in logging.config.fileConfig that causes the 203 # logging Handler class to raise an exception at shutdown. This bug 204 # was reported in Aug 2006 and exists in Python 2.4.4 but is 205 # supposedly fixed in Python 2.5. 206 207 if globals().has_key(u'_TempHandler') and globals()[u'_TempHandler'] is not None: 208 logging.getLogger(u'GeoEco').removeHandler(globals()[u'_TempHandler']) 209 globals()[u'_TempHandler'].close() 210 del globals()[u'_TempHandler'] 211 212 # Now read the config file. 213 214 logging.config.fileConfig(loggingConfigFile) 215 216 except Exception, e: 217 return _(u'Failed to initialize logging from the config file "%s". Please verify that the contents of the config file are valid. Search the Python documentation for "logging configuration file format". In Python 2.4, the article is titled "6.29.10.2 Configuration file format". Python\'s log configuration file parser (logging.config.fileConfig) reported the error: %s') % (loggingConfigFile, unicode(e).strip()) 218 finally: 219 result = cap.Stop() 220 221 if result is not None and len(result.strip()) > 0: 222 result_lines = result.strip().split(u'\n') 223 i = 1 224 while i < len(result_lines) and (len(result_lines[i]) == 0 or result_lines[i][0] == u' '): 225 i = i + 1 226 message = u'' 227 for j in range(i, len(result_lines)): 228 message = message + result_lines[j] + u'\n' 229 message = message.strip() 230 return _(u'Failed to initialize logging from the config file "%s". Please verify that the contents of the config file are valid. Search the Python documentation for "logging configuration file format". In Python 2.4, the article is titled "6.29.10.2 Configuration file format". Python\'s log configuration file parser (logging.config.fileConfig) reported the error: %s') % (loggingConfigFile, message) 231 232 # Return successfully. 233 234 return None 235 236 class StderrCapturer(object): 255 256 class _StderrCapturer(object): 237 257 238 258 def __init__(self): … … 260 280 else: 261 281 return None 282 262 283 263 284 # Initialize, but do not activate, the ArcGIS logging handler. Until the handler … … 278 299 except: 279 300 pass 301 302 303 ############################################################################### 304 # Metadata: module 305 ############################################################################### 306 307 AddModuleMetadata(shortDescription=_(u'Implements the Logger class, which other GeoEco classes use to report activity to the user.')) 308 309 ############################################################################### 310 # Metadata: Logger class 311 ############################################################################### 312 313 AddClassMetadata(Logger, 314 shortDescription=_(u'Provides methods for reporting messages to the user.'), 315 isExposedByIDispatch=True, 316 comIID=u'{0DA39145-CDE6-48F2-AFD9-8EA6623A3121}', 317 comCLSID=u'{EE5ED6B5-55E7-4D65-B627-EF062B8332C4}') 318 319 # Public method: Debug 320 321 AddMethodMetadata(Logger.Debug, 322 shortDescription=_(u'Reports a debugging message to the user.'), 323 longDescription=_( 324 u"""Like the C printf function or the Python % operator, this method generates a 325 message string by merging in the optional arguments into the format string. 326 327 Debugging messages describe processing details that are usually not interesting 328 unless the user is diagnosing a problem. The default configuration of the 329 logging system causes debugging messages to be discarded."""), 330 isExposedByIDispatch=True) 331 332 AddArgumentMetadata(Logger.Debug, u'cls', 333 typeMetadata=PythonClassOrClassInstance(cls=Logger), 334 description=_(u'%s class or an instance of it.') % Logger.__name__) 335 336 AddArgumentMetadata(Logger.Debug, u'format', 337 typeMetadata=PythonUnicodeString(), 338 description=_( 339 u"""A printf-style format string. While Unicode strings are encouraged, this 340 method will also accept an 8-bit string for this parameter. For a complete 341 specification of the format of this string, look up "% formatting" in the Python 342 documentation.""")) 343 344 AddArgumentMetadata(Logger.Debug, u'args', 345 typeMetadata=PythonTuple(elementType=AnyPythonInstance(canBeNone=True)), 346 description=_(u'Values to insert into the format string.')) 347 348 # Public method: Info 349 350 AddMethodMetadata(Logger.Info, 351 shortDescription=_(u'Reports an informational message to the user.'), 352 longDescription=_( 353 u"""Like the C printf function or the Python % operator, this method generates a 354 message string by merging in the optional arguments into the format string. 355 356 Informational messages describe major processing steps that may be interesting to 357 the user but do not require the user to take any action. For example, a method 358 that performs three major processing tasks might report an informational message 359 after each step is finished. Do not report too many informational messages or 360 you may overwhelm the user. Report processing details as debug messages."""), 361 isExposedByIDispatch=True) 362 363 AddArgumentMetadata(Logger.Info, u'cls', 364 typeMetadata=PythonClassOrClassInstance(cls=Logger), 365 description=_(u'%s class or an instance of it.') % Logger.__name__) 366 367 AddArgumentMetadata(Logger.Info, u'format', 368 typeMetadata=PythonUnicodeString(), 369 description=_( 370 u"""A printf-style format string. While Unicode strings are encouraged, this 371 method will also accept an 8-bit string for this parameter. For a complete 372 specification of the format of this string, look up "% formatting" in the Python 373 documentation.""")) 374 375 AddArgumentMetadata(Logger.Info, u'args', 376 typeMetadata=PythonTuple(elementType=AnyPythonInstance(canBeNone=True)), 377 description=_(u'Values to insert into the format string.')) 378 379 # Public method: Warning 380 381 AddMethodMetadata(Logger.Warning, 382 shortDescription=_(u'Reports a warning message to the user.'), 383 longDescription=_( 384 u"""Like the C printf function or the Python % operator, this method generates a 385 message string by merging in the optional arguments into the format string. 386 387 Warning messages describe important events that should be brought to the user's 388 attention but do not necessarily indicate that processing will fail."""), 389 isExposedByIDispatch=True) 390 391 AddArgumentMetadata(Logger.Warning, u'cls', 392 typeMetadata=PythonClassOrClassInstance(cls=Logger), 393 description=_(u'%s class or an instance of it.') % Logger.__name__) 394 395 AddArgumentMetadata(Logger.Warning, u'format', 396 typeMetadata=PythonUnicodeString(), 397 description=_( 398 u"""A printf-style format string. While Unicode strings are encouraged, this 399 method will also accept an 8-bit string for this parameter. For a complete 400 specification of the format of this string, look up "% formatting" in the Python 401 documentation.""")) 402 403 AddArgumentMetadata(Logger.Warning, u'args', 404 typeMetadata=PythonTuple(elementType=AnyPythonInstance(canBeNone=True)), 405 description=_(u'Values to insert into the format string.')) 406 407 # Public method: Error 408 409 AddMethodMetadata(Logger.Error, 410 shortDescription=_(u'Reports an error message to the user.'), 411 longDescription=_( 412 u"""Like the C printf function or the Python % operator, this method generates a 413 message string by merging in the optional arguments into the format string. 414 415 Error messages describe failures that halt processing and require the user to 416 fix a problem and restart processing."""), 417 isExposedByIDispatch=True) 418 419 AddArgumentMetadata(Logger.Error, u'cls', 420 typeMetadata=PythonClassOrClassInstance(cls=Logger), 421 description=_(u'%s class or an instance of it.') % Logger.__name__) 422 423 AddArgumentMetadata(Logger.Error, u'format', 424 typeMetadata=PythonUnicodeString(), 425 description=_( 426 u"""A printf-style format string. While Unicode strings are encouraged, this 427 method will also accept an 8-bit string for this parameter. For a complete 428 specification of the format of this string, look up "% formatting" in the Python 429 documentation.""")) 430 431 AddArgumentMetadata(Logger.Error, u'args', 432 typeMetadata=PythonTuple(elementType=AnyPythonInstance(canBeNone=True)), 433 description=_(u'Values to insert into the format string.')) 434 435 # Public method: Initialize 436 437 AddMethodMetadata(Logger.Initialize, 438 shortDescription=_(u'Initializes the logging system.'), 439 longDescription=_( 440 u"""Like the C printf function or the Python % operator, this method generates a 441 message string by merging in the optional arguments into the format string. 442 443 Error messages describe failures that halt processing and require the user to 444 fix a problem and restart processing."""), 445 isExposedByIDispatch=True) 446 447 AddArgumentMetadata(Logger.Initialize, u'cls', 448 typeMetadata=PythonClassOrClassInstance(cls=Logger), 449 description=_(u'%s class or an instance of it.') % Logger.__name__) 450 451 AddArgumentMetadata(Logger.Initialize, u'loggingConfigFile', 452 typeMetadata=PythonUnicodeString(canBeNone=True), 453 description=_( 454 u"""Path to the logging configuration file. If not provided, the default logging 455 configuration file will be used. The default file, Logging.txt, is located in 456 the Configuration subdirectory of the GeoEco Python package subdirectory.""")) 457 458 AddArgumentMetadata(Logger.Initialize, u'activateArcGISLogging', 459 typeMetadata=PythonBoolean(canBeNone=True), 460 description=_( 461 u"""If true, logging messages will be delivered to the ArcGIS geoprocessing 462 system and appear in the ArcGIS user interface. If false, they will be reported 463 to other logging destinations but will be queued in memory for ArcGIS until the 464 ActivateArcGISLogging method is called. To limit memory consumption in the event 465 that the method is never called, the queue retains only the most recent 1000 466 messages. If you are calling Initialize but not running as part of an ArcGIS 467 geoprocessing *do not* pass true for this parameter. Passing true will decrease 468 performance by initializing the ArcGIS geoprocessor when it might not be 469 necessary to do so. (The memory used by the queue is negligible.)""")) MGET/Trunk/PythonPackage/src/GeoEco/Metadata.py
r24 r25 310 310 __doc__ = DynamicDocString() 311 311 312 def __init__(self, name, moduleMetadata=None, shortDescription=None, longDescription=None, devTeamNotes=None ):312 def __init__(self, name, moduleMetadata=None, shortDescription=None, longDescription=None, devTeamNotes=None, isExposedByIDispatch=False, comIID=None, comCLSID=None, comVersionIndependentProgID=None, comVersionDependentProgID=None): 313 313 314 314 # If the caller did not provide a ModuleMetadata instance for the module … … 325 325 assert moduleMetadata.Object.__dict__.has_key(name) and inspect.isclass(moduleMetadata.Object.__dict__[name]), u'Module %s must contain a class named %s.' % (moduleMetadata.Name, name) 326 326 self._Module = moduleMetadata 327 self.IsExposedByIDispatch = isExposedByIDispatch 328 self.COMIID = comIID 329 self.COMCLSID = comCLSID 330 self.COMVersionIndependentProgID = comVersionIndependentProgID 331 self.COMVersionDependentProgID = comVersionDependentProgID 327 332 328 333 def _GetModule(self): … … 330 335 331 336 Module = property(_GetModule, doc=DynamicDocString()) 337 338 def _GetIsExposedByIDispatch(self): 339 return self._IsExposedByIDispatch 340 341 def _SetIsExposedByIDispatch(self, value): 342 assert isinstance(value, types.BooleanType), u'IsExposedByIDispatch must be a %s.' % types.BooleanType.__name__ 343 self._IsExposedByIDispatch = value 344 345 IsExposedByIDispatch = property(_GetIsExposedByIDispatch, _SetIsExposedByIDispatch, doc=DynamicDocString()) 346 347 def _GetCOMIID(self): 348 return self._COMIID 349 350 def _SetCOMIID(self, value): 351 assert isinstance(value, (types.UnicodeType, types.NoneType)), u'COMIID must be a %s, or None.' % types.UnicodeType.__name__ 352 if value is not None: 353 assert re.match(u'^\{[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\}$', value), u'COMIID must be a GUID, in string format (e.g. u\'{CB2E1BC5-D6A5-11D2-852D-204C4F4F5020}\').' 354 self._COMIID = value 355 356 COMIID = property(_GetCOMIID, _SetCOMIID, doc=DynamicDocString()) 357 358 def _GetCOMCLSID(self): 359 return self._COMCLSID 360 361 def _SetCOMCLSID(self, value): 362 assert isinstance(value, (types.UnicodeType, types.NoneType)), u'COMCLSID must be a %s, or None.' % types.UnicodeType.__name__ 363 if value is not None: 364 assert re.match(u'^\{[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\}$', value), u'COMCLSID must be a GUID, in string format (e.g. u\'{CB2E1BC5-D6A5-11D2-852D-204C4F4F5020}\').' 365 self._COMCLSID = value 366 367 COMCLSID = property(_GetCOMCLSID, _SetCOMCLSID, doc=DynamicDocString()) 368 369 def _GetCOMVersionIndependentProgID(self): 370 return self._COMVersionIndependentProgID 371 372 def _SetCOMVersionIndependentProgID(self, value): 373 assert isinstance(value, (types.UnicodeType, types.NoneType)), u'COMVersionIndependentProgID must be a %s, or None.' % types.UnicodeType.__name__ 374 if value is None: 375 self._COMVersionIndependentProgID = u'GeoEco.' + unicode(self.Name) 376 else: 377 self._COMVersionIndependentProgID = value 378 379 COMVersionIndependentProgID = property(_GetCOMVersionIndependentProgID, _SetCOMVersionIndependentProgID, doc=DynamicDocString()) 380 381 def _GetCOMVersionDependentProgID(self): 382 return self._COMVersionDependentProgID 383 384 def _SetCOMVersionDependentProgID(self, value): 385 assert isinstance(value, (types.UnicodeType, types.NoneType)), u'COMVersionDependentProgID must be a %s, or None.' % types.UnicodeType.__name__ 386 if value is None: 387 self._COMVersionDependentProgID = u'GeoEco.' + unicode(self.Name) + u'.1' 388 else: 389 self._COMVersionDependentProgID = value 390 391 COMVersionDependentProgID = property(_GetCOMVersionDependentProgID, _SetCOMVersionDependentProgID, doc=DynamicDocString()) 332 392 333 393 def _GetObject(self): … … 496 556 assert issubclass(cls, object), u'ValidatePropertyAssignment should only be called from the "fset" method of a property. By definition, only "new-style" classes (those that derive from object) can have properties.' 497 557 498 # Validate that the method is the fset method for a property of that 499 # class. 500 558 # Now we need to identify the class's property object that uses the 559 # calling method as the "fset" method. Once we have that property object 560 # we can use the property's metadata to validate the assigned value. 561 # 562 # First, determine if the calling method is an instance method or a 563 # classmethod. 564 565 methodType = None 566 mro = inspect.getmro(cls) 567 for mroClass in mro: 568 if mroClass.__dict__.has_key(method.__name__): 569 if isinstance(mroClass.__dict__[method.__name__], classmethod): 570 methodType = classmethod 571 else: 572 methodType = types.MethodType 573 break 574 assert methodType is not None, u'Programming error in GeoEco.Metadata.ClassMetadata.ValidatePropertyAssignment: methodType is None. Please contact the authors of GeoEco for assistance.' 575 501 576 propName = None 502 577 prop = None 503 props = inspect.getmembers(cls, inspect.isdatadescriptor) 504 for (name, p) in props: 505 if p.fset.func_code == method.im_func.func_code: 506 propName = name 507 prop = p 508 break 578 579 # If the calling method is an instance method, look for the property 580 # that has its fset property set to the method object itself. 581 582 if methodType == types.MethodType: 583 props = inspect.getmembers(cls, inspect.isdatadescriptor) 584 for (name, p) in props: 585 if hasattr(p, 'fset') and isinstance(p.fset, types.MethodType) and p.fset == method: 586 propName = name 587 prop = p 588 break 589 590 # If the calling method is a classmethod, we have to look up the 591 # classmethod for which the calling method is the implementation. We 592 # cannot get this from p.fset.im_func or anything like that. Any time I 593 # try to dereference fset when it is a classmethod, Python just exits. 594 595 else: 596 597 # First find the classmethod for which the calling method is the 598 # implementation. 599 600 classmethodForMethod = None 601 for mroClass in mro: 602 for key in mroClass.__dict__.keys(): 603 if isinstance(mroClass.__dict__[key], classmethod) and getattr(mroClass, key) == method: 604 classmethodForMethod = mroClass.__dict__[key] 605 break 606 if classmethodForMethod is not None: 607 break 608 609 # Now look up the property that has its fset property set to the 610 # classmethod object. 611 612 if classmethodForMethod is not None: 613 props = inspect.getmembers(cls, inspect.isdatadescriptor) 614 for (name, p) in props: 615 if hasattr(p, 'fset') and isinstance(p.fset, classmethod) and p.fset == classmethodForMethod: 616 propName = name 617 prop = p 618 break 619 509 620 assert propName is not None and prop is not None, u'ValidatePropertyAssignment should only be called from the "fset" method of a property. None of the properties in class %s use method %s for their "fset" method. Please do not call ValidatePropertyAssignment from %s.' % (cls.__name__, method.__name__, method.__name__) 510 621 … … 564 675 def AppendXMLNodes(self, node, document): 565 676 super(ClassMetadata, self).AppendXMLNodes(node, document) 677 self.AppendPropertyXMLNode(self, u'IsExposedByIDispatch', node, document) 678 self.AppendPropertyXMLNode(self, u'COMIID', node, document) 679 self.AppendPropertyXMLNode(self, u'COMCLSID', node, document) 680 self.AppendPropertyXMLNode(self, u'COMVersionIndependentProgID', node, document) 681 self.AppendPropertyXMLNode(self, u'COMVersionDependentProgID', node, document) 566 682 propertiesNode = node.appendChild(document.createElement(u'Properties')) 567 683 for (name, prop) in inspect.getmembers(self.Object, inspect.isdatadescriptor): … … 680 796 self.AppendPropertyXMLNode(self, u'IsExposedByPython', node, document) 681 797 self.AppendPropertyXMLNode(self, u'IsExposedByIDispatch', node, document) 798 self.AppendPropertyXMLNode(self, u'IsReadOnly', node, document) 682 799 683 800 … … 883 1000 self._Method = methodMetadata 884 1001 (args, varargs, varkw, defaults) = inspect.getargspec(methodMetadata.Object) 885 argFound = varargs is not None and name == varargs or varkw is not None and name == varkw1002 argFound = (varargs is not None and name == varargs or varkw is not None and name == varkw) 886 1003 if not argFound: 887 1004 for arg in args: … … 996 1113 def _GetHasDefault(self): 997 1114 (args, varargs, varkw, defaults) = inspect.getargspec(self.Method.Object) 1115 if self.Name == varargs or self.Name == varkw: 1116 return False 998 1117 for i in range(len(args)): 999 1118 if args[i] == self.Name: … … 1007 1126 def _GetDefault(self): 1008 1127 (args, varargs, varkw, defaults) = inspect.getargspec(self.Method.Object) 1128 if self.Name == varargs or self.Name == varkw: 1129 return None 1009 1130 for i in range(len(args)): 1010 1131 if args[i] == self.Name: … … 1124 1245 class TypeMetadata(object): 1125 1246 1126 def __init__(self, pythonType, canBeNone=False, arcGISType=None, arcGISAssembly=None, canBeArcGISInputParameter=False, canBeArcGISOutputParameter=False):1247 def __init__(self, pythonType, canBeNone=False, comIDLType=None, canBeIDispatchParameter=False, arcGISType=None, arcGISAssembly=None, canBeArcGISInputParameter=False, canBeArcGISOutputParameter=False): 1127 1248 assert isinstance(pythonType, (types.TypeType, types.ClassType)) and not issubclass(pythonType, types.NoneType), u'pythonType must be a type or old-style class, and it may not be types.NoneType or derived from it.' 1128 1249 assert isinstance(canBeNone, types.BooleanType), u'canBeNone must be a boolean.' 1250 assert isinstance(comIDLType, (types.NoneType, types.UnicodeType)), u'comIDLType must be a unicode string, or None.' 1251 assert isinstance(canBeIDispatchParameter, types.BooleanType), u'canBeIDispatchParameter must be a boolean.' 1129 1252 assert arcGISType is None and arcGISAssembly is None or isinstance(arcGISType, types.UnicodeType) and isinstance(arcGISAssembly, types.UnicodeType), u'arcGISType and arcGISAssembly must both be Unicode strings or both be None.' 1130 1253 assert isinstance(canBeArcGISInputParameter, types.BooleanType), u'canBeArcGISInputParameter must be a boolean.' … … 1132 1255 self._PythonType = pythonType 1133 1256 self._CanBeNone = canBeNone 1257 self._COMIDLType = comIDLType 1258 self._CanBeIDispatchParameter = canBeIDispatchParameter 1134 1259 self._ArcGISType = arcGISType 1135 1260 self._ArcGISAssembly = arcGISAssembly … … 1146 1271 1147 1272 CanBeNone = property(_GetCanBeNone, doc=DynamicDocString()) 1273 1274 def _GetCOMIDLType(self): 1275 return self._COMIDLType 1276 1277 COMIDLType = property(_GetCOMIDLType, doc=DynamicDocString()) 1278 1279 def _GetCanBeIDispatchParameter(self): 1280 return self._CanBeIDispatchParameter 1281 1282 CanBeIDispatchParameter = property(_GetCanBeIDispatchParameter, doc=DynamicDocString()) 1148 1283 1149 1284 def _GetArcGISType(self): … … 1178 1313 node.appendChild(document.createElement(u'PythonType')).appendChild(document.createTextNode(self.PythonType.__name__)) 1179 1314 Metadata.AppendPropertyXMLNode(self, u'CanBeNone', node, document) 1315 Metadata.AppendPropertyXMLNode(self, u'COMIDLType', node, document) 1316 Metadata.AppendPropertyXMLNode(self, u'CanBeIDispatchParameter', node, document) 1180 1317 Metadata.AppendPropertyXMLNode(self, u'ArcGISType', node, document) 1181 1318 Metadata.AppendPropertyXMLNode(self, u'ArcGISAssembly', node, document) … … 1192 1329 elif not isinstance(value, self.PythonType): 1193 1330 raise TypeError(_(u'The value provided for the %s is invalid because it is a %s, an invalid type. Please provide a value of type %s.') % (variableName, type(value).__name__, self.PythonType.__name__)) 1331 1332 def COMIDLRepresentationOfValue(self, value): 1333 return None 1194 1334 1195 1335 def ParseValueFromArcGISInputParameterString(self, paramString, paramDisplayName, paramIndex): … … 1330 1470 1331 1471 1332 def AddClassMetadata(cls, shortDescription, longDescription=None, devTeamNotes=None, module=None ):1472 def AddClassMetadata(cls, shortDescription, longDescription=None, devTeamNotes=None, module=None, isExposedByIDispatch=False, comIID=None, comCLSID=None, comVersionIndependentProgID=None, comVersionDependentProgID=None): 1333 1473 module = _GetModuleObject(module) 1334 1474 assert isinstance(module.__doc__, DynamicDocString) and isinstance(module.__doc__.Obj, ModuleMetadata), u'The __doc__ attribute of module %s must be an instance of GeoEco.Metadata.DynamicDocString, and __doc__.Obj must be an instance of GeoEco.Metadata.ModuleMetadata. Use the GeoEco.Metadata.AddModuleMetadata function to add the module\'s metadata before calling GeoEco.Metadata.AddClassMetadata.' % module.__name__ 1335 1475 cls = _GetClassObject(cls, module) 1336 assert isinstance(cls.__doc__, DynamicDocString), u'The __doc__ attribute of class %s defined in module %s must be an instance of GeoEco.Metadata.DynamicDocString. You should place the line\n\n __doc__ = GeoEco.Metadata.DynamicDocString()\n\nin your class definition.' % s(cls.__name__, module.__name__)1476 assert isinstance(cls.__doc__, DynamicDocString), u'The __doc__ attribute of class %s defined in module %s must be an instance of GeoEco.Metadata.DynamicDocString. You should place the line\n\n __doc__ = GeoEco.Metadata.DynamicDocString()\n\nin your class definition.' % (cls.__name__, module.__name__) 1337 1477 assert cls.__doc__.Obj is None, u'%s.__doc__.Obj must be None. Do not call AddClassMetadata on a class that already has metadata.' % cls.__name__ 1338 cls.__doc__.Obj = ClassMetadata(unicode(cls.__name__), module.__doc__.Obj, shortDescription, longDescription, devTeamNotes )1478 cls.__doc__.Obj = ClassMetadata(unicode(cls.__name__), module.__doc__.Obj, shortDescription, longDescription, devTeamNotes, isExposedByIDispatch, comIID, comCLSID, comVersionIndependentProgID, comVersionDependentProgID) 1339 1479 1340 1480 … … 1364 1504 propName = attr 1365 1505 assert cls is not None, u'If prop is a property object and cls is None, module %s must contain the class to which prop belongs.' % module.__name__ 1366 assert isinstance(cls.__doc__, DynamicDocString), u'The __doc__ attribute of class %s defined in module %s must be an instance of GeoEco.Metadata.DynamicDocString. You should place the line\n\n __doc__ = GeoEco.Metadata.DynamicDocString()\n\nin your class definition.' % s(cls.__name__, module.__name__)1506 assert isinstance(cls.__doc__, DynamicDocString), u'The __doc__ attribute of class %s defined in module %s must be an instance of GeoEco.Metadata.DynamicDocString. You should place the line\n\n __doc__ = GeoEco.Metadata.DynamicDocString()\n\nin your class definition.' % (cls.__name__, module.__name__) 1367 1507 assert isinstance(cls.__doc__.Obj, ClassMetadata), u'%s.__doc__.Obj must be an instance of GeoEco.Metadata.ClassMetadata. Before calling GeoEco.Metadata.AddPropertyMetadata, use GeoEco.Metadata.AddClassMetadata to add ClassMetadata to class %s.' % (cls.__name__, cls.__name__) 1368 1508 assert isinstance(prop.__doc__, DynamicDocString), u'%s.%s.__doc__ must be an instance of GeoEco.Metadata.DynamicDocString. When defining the property, set the doc parameter to a new instance of DynamicDocString, like this:\n\n %s = property(..., doc=DynamicDocString())' % (cls.__name__, propName, propName) … … 1667 1807 shortDescription=_(u'%s instance for the module that contains this class.') % ModuleMetadata.__name__) 1668 1808 1809 AddPropertyMetadata(ClassMetadata.IsExposedByIDispatch, 1810 typeMetadata=PythonBoolean(), 1811 shortDescription=_(u'True if this class is exposed using the Microsoft COM IDispatch interface on Windows operating systems.'), 1812 longDescription=_(u'Components that expose an IDispatch interface are sometimes called COM Automation components or ActiveX components. Exposing the IDispatch interface allows the component to be invoked from virtually any programming language.')) 1813 1814 AddPropertyMetadata(ClassMetadata.COMIID, 1815 typeMetadata=PythonUnicodeString(), 1816 shortDescription=_(u'Microsoft COM IID (interface ID) for the COM interface exposed by this class, in GUID string format (e.g. u\'{CB2E1BC5-D6A5-11D2-852D-204C4F4F5020}\').'), 1817 longDescription=_(u'The IID is the globally-unique identifier for the COM interface that represents this class under the COM infrastructure. Windows programs invoke properties and methods of this class through COM using this indentifier.'), 1818 devTeamNotes=_( 1819 u"""This property is only relevant if IsExposedByIDispatch is True. If you set 1820 IsExposedByIDispatch to True, you must supply a value for COMIID. You may 1821 obtain a random, globally-unique value like this:: 1822 1823 >>> import pythoncom 1824 >>> unicode(pythoncom.CreateGuid()) 1825 u'{890E7DF8-FC16-43BD-BF14-B08890F6CC0C}' 1826 """)) 1827 1828 AddPropertyMetadata(ClassMetadata.COMCLSID, 1829 typeMetadata=PythonUnicodeString(), 1830 shortDescription=_(u'Microsoft COM CLSID (class ID) for this class, in GUID string format (e.g. u\'{CB2E1BC5-D6A5-11D2-852D-204C4F4F5020}\').'), 1831 longDescription=_(u'The CLSID is the globally-unique identifier for this class under the COM infrastructure. Windows programs create instances of this class through COM using this indentifier.'), 1832 devTeamNotes=_( 1833 u"""This property is only relevant if IsExposedByIDispatch is True. If you set 1834 IsExposedByIDispatch to True, you must supply a value for COMCLSID. You may 1835 obtain a random, globally-unique value like this:: 1836 1837 >>> import pythoncom 1838 >>> unicode(pythoncom.CreateGuid()) 1839 u'{890E7DF8-FC16-43BD-BF14-B08890F6CC0C}' 1840 """)) 1841 1842 AddPropertyMetadata(ClassMetadata.COMVersionIndependentProgID, 1843 typeMetadata=PythonUnicodeString(), 1844 shortDescription=_(u'Microsoft COM "version-independent ProgID" for this class.'), 1845 longDescription=_( 1846 u"""A ProgID is human-readable identifier for a class under the COM 1847 infrastructure, such as "'GeoEco.Tools.HelloWorld". Windows programs can 1848 create instances of this class through COM using the ProgID raster than the 1849 CLSID. Many programmers prefer to use the ProgID rather than the CLSID."""), 1850 devTeamNotes=_( 1851 u"""The ProgID provides one level of indirection in component name resolution. When 1852 a program creates a component instance using the ProgID, COM looks up the CLSID 1853 from the ProgID and instantiates the component using the CLSID. This allows the 1854 component developer to change the component's CLSID while leaving the ProgID 1855 unchanged. The calling programs will automatically create the new component 1856 without any code changes. 1857 1858 A further level of indirection is allowed by the provision of both version- 1859 independent and version-dependent ProgIDs. Traditionally, a component provides 1860 a single version-independent ProgID, such as "GeoEco.Tools.HelloWorld" and 1861 one or more version-dependent ProgIDs, such as 1862 "GeoEco.Tools.HelloWorld.HelloWorld.1", "GeoEco.Tools.HelloWorld.HelloWorld.2" 1863 and "GeoEco.Tools.HelloWorld.HelloWorld.3". The version-independent ProgID 1864 resolves to the latest version-dependent ProgID, 1865 "GeoEco.Tools.HelloWorld.HelloWorld.3" in this case. Programs instantiate the 1866 version-independent ID if they always want the latest version of the component, 1867 or a version-dependent ID if they want a specific version. Multiple versions of 1868 the component may be installed simultaneously, if the component supports it. 1869 1870 GeoEco does not support multiple simultaneous installations. A program that 1871 instantiates a GeoEco class by ProgID may use either of two strategies: 1872 1873 * Use the version-independent ProgID. This will guarantee that the program will 1874 obtain an instance no matter what version of GeoEco is installed, but the 1875 program must handle any behavior changes between component versions. 1876 1877 * Use the version-dependent ProgIDs. This will guarantee that the program will 1878 only obtain an instance of a specific version. The program will not need to 1879 deal with behavior differences between versions, but instantiation will fail 1880 if the requested version is not installed. 1881 1882 To facilitate these strategies, the following approach is recommended for 1883 developers of GeoEco classes that will be exposed through COM. 1884 1885 * Do not specify a COMVersionIndependentProgID for your ClassMetadata. By 1886 default, your class's version-independent ProgID will be "GeoEco." plus the 1887 class name, e.g. "GeoEco.HelloWorld". This scheme means that your class's name 1888 must be unique across all GeoEco classes exposed by COM, regardless of what 1889 modules they are defined in. You cannot use submodules and subpackages to 1890 disambiguate classes with the same name. (This restriction is cumbersome 1891 but it allows the ProgIDs to remain consistent with the type information 1892 exposed to early-bound callers by the GeoEco type library. Please contact the 1893 author of GeoEco's COM infrastructure for a full explanation.) 1894 1895 * For the first version of your class, do not specify a COMVersionDependentProgID. 1896 By default, your class's version dependent ProgID will by the module name plus 1897 the class name plus ".1", e.g. "GeoEco.HelloWorld.1". 1898 1899 * If your component ever changes its behavior "significantly" between GeoEco 1900 versions, specify a new version-dependent ProgID that is "one number higher" 1901 than the previous one, e.g. "GeoEco.HelloWorld.2" for the second version. It 1902 is up to you what "significantly" means. One possible definition of a 1903 "signficant" change is one that would cause a double-digit percentage of your 1904 callers to fail or receive bad results if they blindly invoked the new version. 1905 (Callers that invoke using the version-independent ProgID will still break, 1906 but they incurred that risk when they chose to bind to that ProgID, rather 1907 than the version-dependent one.) 1908 """)) 1909 1910 AddPropertyMetadata(ClassMetadata.COMVersionDependentProgID, 1911 typeMetadata=PythonUnicodeString(), 1912 shortDescription=_(u'Microsoft COM "version-dependent ProgID" for this class.'), 1913 longDescription=ClassMetadata.COMVersionIndependentProgID.__doc__.Obj.LongDescription, 1914 devTeamNotes=ClassMetadata.COMVersionIndependentProgID.__doc__.Obj.DevTeamNotes) 1915 1669 1916 # Public method: ValidatePropertyAssignment 1670 1917 MGET/Trunk/PythonPackage/src/GeoEco/Tools/HelloWorld.py
r24 r25 4 4 from GeoEco.Logging import * 5 5 from GeoEco.Metadata import * 6 from GeoEco.Tool import *7 6 from GeoEco.Types import * 8 7 9 class HelloWorld( Tool):8 class HelloWorld(object): 10 9 __doc__ = DynamicDocString() 11 10 11 _public_methods_ = ['GreetPerson'] 12 12 13 @classmethod 13 14 def GreetPerson(cls, person=_(u'World')): 14 15 cls.__doc__.Obj.ValidateMethodInvocation() 15 16 greeting = _(u'Hello %s!') % person.strip() 16 Log Info(greeting)17 Logger.Info(greeting) 17 18 return greeting 18 19 … … 25 26 greeting = _(u'Hello %s!') % people[0] 26 27 else: 27 Log Error(_(u'You must specify at least one person to greet.'))28 Log Info(greeting)28 Logger.Error(_(u'You must specify at least one person to greet.')) 29 Logger.Info(greeting) 29 30 return greeting 30 31 31 32 @classmethod 32 33 def TestParameterTypes(cls, oneBoolean=True, listOfBooleans=[False,True,False], oneFloat=1.0, listOfFloats=[2.0, 3.0, 4.0], oneInt=5, listOfInts=[5,6,7], oneString=u'Foo', listOfStrings=[u'Blah',u'Blah',u'Blah']): 33 Log Info(u'oneBoolean = ' + unicode(repr(oneBoolean)))34 Log Info(u'listOfBooleans = ' + unicode(repr(listOfBooleans)))35 Log Info(u'oneFloat = ' + unicode(repr(oneFloat)))36 Log Info(u'listOfFloats = ' + unicode(repr(listOfFloats)))37 Log Info(u'oneInt = ' + unicode(repr(oneInt)))38 Log Info(u'listOfInts = ' + unicode(repr(listOfInts)))39 Log Info(u'oneString = ' + unicode(repr(oneString)))40 Log Info(u'listOfStrings = ' + unicode(repr(listOfStrings)))34 Logger.Info(u'oneBoolean = ' + unicode(repr(oneBoolean))) 35 Logger.Info(u'listOfBooleans = ' + unicode(repr(listOfBooleans))) 36 Logger.Info(u'oneFloat = ' + unicode(repr(oneFloat))) 37 Logger.Info(u'listOfFloats = ' + unicode(repr(listOfFloats))) 38 Logger.Info(u'oneInt = ' + unicode(repr(oneInt))) 39 Logger.Info(u'listOfInts = ' + unicode(repr(listOfInts))) 40 Logger.Info(u'oneString = ' + unicode(repr(oneString))) 41 Logger.Info(u'listOfStrings = ' + unicode(repr(listOfStrings))) 41 42 return oneBoolean, oneFloat, oneInt, oneString 42 43 … … 46 47 ############################################################################### 47 48 48 AddModuleMetadata(shortDescription=_(u'Contains the HelloWorld class, which illustrates how to build a GeoEco tool.'))49 AddModuleMetadata(shortDescription=_(u'Contains the HelloWorld class, which illustrates how to build a GeoEco class exposed to external callers.')) 49 50 50 51 ############################################################################### … … 53 54 54 55 AddClassMetadata(HelloWorld, 55 shortDescription=_(u'llustrates how to build a GeoEco toolusing the classic "hello world" paradigm.'),56 shortDescription=_(u'llustrates how to build a GeoEco class exposed to external callers using the classic "hello world" paradigm.'), 56 57 longDescription= 57 58 _(u"""At the beginning of their classic text on the C programming language, Brian … … 61 62 authors have introduced new programming languages. In the spririt of this 62 63 tradition, I have provided a HelloWorld class to illustrate, as succinctly as 63 possible, the features of the GeoEco Python class framework and build script.""")) 64 possible, the features of the GeoEco Python class framework and build script."""), 65 isExposedByIDispatch=True, 66 comIID=u'{CEEE9091-E817-4F39-9A90-20E43FDB8AC8}', 67 comCLSID=u'{B2ED9CEF-D035-4011-A5A6-DA4BC14CBF71}') 64 68 65 69 # Public method: GreetPerson … … 67 71 AddMethodMetadata(HelloWorld.GreetPerson, 68 72 shortDescription=_(u'Greets a specified person.'), 73 isExposedByIDispatch=True, 69 74 isExposedAsArcGISTool=True, 70 75 arcGISDisplayName=_(u'Greet Person'), 71 76 arcGISToolCategory=_(u'Examples')) 72 77 73 HelloWorld.GreetPerson.im_func.__doc__.Obj.Dependencies.append(ArcGISVersion(minimumMajorVersion=9, minimumMinorVersion=1))78 #HelloWorld.GreetPerson.im_func.__doc__.Obj.Dependencies.append(ArcGISVersion(minimumMajorVersion=9, minimumMinorVersion=1)) 74 79 75 80 AddArgumentMetadata(HelloWorld.GreetPerson, u'cls', … … 78 83 79 84 AddArgumentMetadata(HelloWorld.GreetPerson, u'person', 80 typeMetadata=PythonUnicodeString( ),85 typeMetadata=PythonUnicodeString(canBeNone=True), 81 86 description=_(u'Person to greet.'), 82 87 arcGISDisplayName=_(u'Person to Greet')) MGET/Trunk/PythonPackage/src/GeoEco/Types.py
r24 r25 8 8 9 9 10 # Core Python types from which everything else should derive: 10 # Specialized types from which few things derive 11 12 13 class AnyPythonInstance(TypeMetadata): 14 15 def __init__(self, canBeNone=False): 16 super(AnyPythonInstance, self).__init__(pythonType=types.ObjectType, canBeNone=canBeNone, comIDLType=u'VARIANT', canBeIDispatchParameter=True) 11 17 12 18 … … 32 38 33 39 40 # Simple Python types from which many other types derive: 41 42 34 43 class PythonBoolean(TypeMetadata): 35 44 36 45 def __init__(self, canBeNone=False): 37 super(PythonBoolean, self).__init__(pythonType=types.BooleanType, canBeNone=canBeNone, arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPBooleanTypeClass', arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing', canBeArcGISInputParameter=True, canBeArcGISOutputParameter=True)46 super(PythonBoolean, self).__init__(pythonType=types.BooleanType, canBeNone=canBeNone, comIDLType=u'VARIANT_BOOL', canBeIDispatchParameter=True, arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPBooleanTypeClass', arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing', canBeArcGISInputParameter=True, canBeArcGISOutputParameter=True) 38 47 39 48 def AppendXMLNodesForValue(self, value, node, document): … … 42 51 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' 43 52 node.appendChild(document.createElement(u'boolean')).appendChild(document.createTextNode(unicode(value).lower())) 53 54 def COMIDLRepresentationOfValue(self, value): 55 assert isinstance(value, types.BooleanType), u'value must be a boolean' 56 if value: 57 return 'VARIANT_TRUE' 58 return 'VARIANT_FALSE' 44 59 45 60 def ParseValueFromArcGISInputParameterString(self, paramString, paramDisplayName, paramIndex): … … 55 70 56 71 def __init__(self, canBeNone=False): 57 super(PythonFloat, self).__init__(pythonType=types.FloatType, canBeNone=canBeNone, arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPDoubleTypeClass', arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing', canBeArcGISInputParameter=True, canBeArcGISOutputParameter=True)72 super(PythonFloat, self).__init__(pythonType=types.FloatType, canBeNone=canBeNone, comIDLType=u'double', canBeIDispatchParameter=True, arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPDoubleTypeClass', arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing', canBeArcGISInputParameter=True, canBeArcGISOutputParameter=True) 58 73 59 74 def AppendXMLNodesForValue(self, value, node, document): … … 62 77 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' 63 78 node.appendChild(document.createElement(u'double')).appendChild(document.createTextNode(unicode(value))) 79 80 def COMIDLRepresentationOfValue(self, value): 81 assert isinstance(value, types.FloatType), u'value must be a float' 82 return str(value) 64 83 65 84 def ParseValueFromArcGISInputParameterString(self, paramString, paramDisplayName, paramIndex): … … 75 94 76 95 def __init__(self, canBeNone=False): 77 super(PythonInteger, self).__init__(pythonType=types.IntType, canBeNone=canBeNone, arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPLongTypeClass', arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing', canBeArcGISInputParameter=True, canBeArcGISOutputParameter=True)96 super(PythonInteger, self).__init__(pythonType=types.IntType, canBeNone=canBeNone, comIDLType=u'long', canBeIDispatchParameter=True, arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPLongTypeClass', arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing', canBeArcGISInputParameter=True, canBeArcGISOutputParameter=True) 78 97 79 98 def AppendXMLNodesForValue(self, value, node, document): … … 82 101 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' 83 102 node.appendChild(document.createElement(u'int')).appendChild(document.createTextNode(unicode(value))) 103 104 def COMIDLRepresentationOfValue(self, value): 105 assert isinstance(value, types.IntType), u'value must be an int' 106 return str(value) 84 107 85 108 def ParseValueFromArcGISInputParameterString(self, paramString, paramDisplayName, paramIndex): … … 95 118 96 119 def __init__(self, canBeNone=False): 97 super(PythonUnicodeString, self).__init__(pythonType=types.UnicodeType, canBeNone=canBeNone, arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPStringTypeClass', arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing', canBeArcGISInputParameter=True, canBeArcGISOutputParameter=True) 120 super(PythonUnicodeString, self).__init__(pythonType=types.UnicodeType, canBeNone=canBeNone, comIDLType=u'BSTR', canBeIDispatchParameter=True, arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPStringTypeClass', arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing', canBeArcGISInputParameter=True, canBeArcGISOutputParameter=True) 121 122 def COMIDLRepresentationOfValue(self, value): 123 assert isinstance(value, types.UnicodeType), u'value must be a Unicode string' 124 return '"' + str(value).replace('"', '\\"') + '"' 98 125 99 126 def AppendXMLNodesForValue(self, value, node, document): … … 104 131 105 132 106 class PythonList(TypeMetadata): 107 108 def __init__(self, elementType, canBeNone=False): 133 # Python sequence types 134 135 136 class PythonSequence(TypeMetadata): 137 138 def __init__(self, elementType, pythonType=types.ObjectType, canBeNone=False, comIDLType=u'SAFEARRAY(VARIANT)', canBeIDispatchParameter=True, arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPMultiValueTypeClass', arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing', canBeArcGISInputParameter=True, canBeArcGISOutputParameter=False): 109 139 assert isinstance(elementType, TypeMetadata), u'elementType must be an instance of TypeMetadata' 110 super(PythonList, self).__init__(pythonType=types.ListType, canBeNone=canBeNone, arcGISType=u'ESRI.ArcGIS.Geoprocessing.GPMultiValueTypeClass', arcGISAssembly=u'ESRI.ArcGIS.Geoprocessing', canBeArcGISInputParameter=(issubclass(elementType.PythonType, basestring) or not hasattr(elementType.PythonType, '__getitem__')), canBeArcGISOutputParameter=False) 140 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.)' 141 super(PythonSequence, self).__init__(pythonType=pythonType, canBeNone=canBeNone, comIDLType=comIDLType, canBeIDispatchParameter=canBeIDispatchParameter, arcGISType=arcGISType, arcGISAssembly=arcGISAssembly, canBeArcGISInputParameter=canBeArcGISInputParameter, canBeArcGISOutputParameter=canBeArcGISOutputParameter) 111 142 self._ElementType = elementType 112 143 … … 117 148 118 149 def AppendXMLNodes(self, node, document): 119 super(Python List, self).AppendXMLNodes(node, document)150 super(PythonSequence, self).AppendXMLNodes(node, document) 120 151 elementTypeNode = node.appendChild(document.createElement(u'ElementTypeMetadata')) 121 152 self.ElementType.AppendXMLNodes(elementTypeNode, document) … … 130 161 131 162 def ValidateValue(self, value, variableName): 132 super(PythonList, self).ValidateValue(value, variableName) 163 super(PythonSequence, self).ValidateValue(value, variableName) 164 if not hasattr(value, '__len__') or not hasattr(value, '__getitem__') or not hasattr(value, '__setitem__') or not hasattr(value, '__iter__'): 165 raise TypeError(_(u'The value provided for the %s is invalid because it is a %s, which is not a Python sequence type. Please provide sequence type, such as %s, %s or %s.') % (variableName, type(value).__name__, types.ListType.__name__, types.TupleType.__name__, types.DictType.__name__)) 133 166 for i in range(len(value)): 134 167 self.ElementType.ValidateValue(value[i], _(u'element %i of the %s (where 0 is the first element)')) 135 168 136 169 def ParseValueFromArcGISInputParameterString(self, paramString, paramDisplayName, paramIndex): 137 paramString = super(Python List, self).ParseValueFromArcGISInputParameterString(paramString, paramDisplayName, paramIndex)170 paramString = super(PythonSequence, self).ParseValueFromArcGISInputParameterString(paramString, paramDisplayName, paramIndex) 138 171 139 172 # The input string is a list of values formatted as follows: … … 161 194 while i < len(paramString): 162 195 163 #GeoEco.Logging.Log Debug('----------------------------')164 #GeoEco.Logging.Log Debug(u'i = %i, c = %s, state = %i, paramStart = %i, paramCharCount= %i' % (i, paramString[i], state, paramStart, paramCharCount))196 #GeoEco.Logging.Logger.Debug('----------------------------') 197 #GeoEco.Logging.Logger.Debug(u'i = %i, c = %s, state = %i, paramStart = %i, paramCharCount= %i' % (i, paramString[i], state, paramStart, paramCharCount)) 165 198 166 199 if state == FIRST_CHARACTER: … … 213 246 raise RuntimeError(_(u'Failed to parse a list of values from the string provided for the %s parameter (parameter number %i) due to a programming error in the parser: the parser was found to be in unknown state %i. Please contact the author of this tool for assistance.') % (paramDisplayName, paramIndex, state)) 214 247 215 #GeoEco.Logging.Log Debug('state = %i, paramStart = %i, paramCharCount= %i' % (state, paramStart, paramCharCount))248 #GeoEco.Logging.Logger.Debug('state = %i, paramStart = %i, paramCharCount= %i' % (state, paramStart, paramCharCount)) 216 249 217 250 i += 1 … … 249 282 250 283 return values 284 285 286 class PythonList(PythonSequence): 287 288 def __init__(self, elementType, canBeNone=False): 289 super(PythonList, self).__init__(elementType=elementType, pythonType=types.ListType, canBeNone=canBeNone) 290 291 292 class PythonTuple(PythonSequence): 293 294 def __init__(self, elementType, canBeNone=False): 295 super(PythonTuple, self).__init__(elementType=elementType, pythonType=types.TupleType, canBeNone=canBeNone) 296 297 def ParseValueFromArcGISInputParameterString(self, paramString, paramDisplayName, paramIndex): 298 resultList = super(PythonTuple, self).ParseValueFromArcGISInputParameterString(paramString, paramDisplayName, paramIndex) 299 return tuple(resultList) MGET/Trunk/VisualStudioSolutions/CreateArcGISToolbox/Program.cs
r19 r25 46 46 #region Fields deserialized from Metadata.xml 47 47 48 public bool IsExposedByIDispatch; 49 public string COMIID; 50 public string COMCLSID; 51 public string COMVersionIndependentProgID; 52 public string COMVersionDependentProgID; 48 53 public PropertyMetadata[] Properties; 49 54 public MethodMetadata[] Methods; … … 57 62 58 63 [XmlElement(typeof(TypeMetadata)), 64 XmlElement(typeof(AnyPythonInstance)), 59 65 XmlElement(typeof(PythonClassInstance)), 60 66 XmlElement(typeof(PythonClassOrClassInstance)), … … 63 69 XmlElement(typeof(PythonInteger)), 64 70 XmlElement(typeof(PythonUnicodeString)), 65 XmlElement(typeof(PythonList))] 71 XmlElement(typeof(PythonSequence)), 72 XmlElement(typeof(PythonList)), 73 XmlElement(typeof(PythonTuple))] 66 74 public TypeMetadata TypeMetadata; 67 75 public bool IsExposedByPython; 68 76 public bool IsExposedByIDispatch; 77 public bool IsReadOnly; 69 78 70 79 #endregion … … 95 104 public string Name; 96 105 [XmlElement(typeof(TypeMetadata)), 106 XmlElement(typeof(AnyPythonInstance)), 97 107 XmlElement(typeof(PythonClassInstance)), 98 108 XmlElement(typeof(PythonClassOrClassInstance)), … … 101 111 XmlElement(typeof(PythonInteger)), 102 112 XmlElement(typeof(PythonUnicodeString)), 103 XmlElement(typeof(PythonList))] 113 XmlElement(typeof(PythonSequence)), 114 XmlElement(typeof(PythonList)), 115 XmlElement(typeof(PythonTuple))] 104 116 public TypeMetadata TypeMetadata; 105 117 [XmlAnyElement(Name = "Description")] … … 127 139 public string Name; 128 140 [XmlElement(typeof(TypeMetadata)), 141 XmlElement(typeof(AnyPythonInstance)), 129 142 XmlElement(typeof(PythonClassInstance)), 130 143 XmlElement(typeof(PythonClassOrClassInstance)), … … 133 146 XmlElement(typeof(PythonInteger)), 134 147 XmlElement(typeof(PythonUnicodeString)), 135 XmlElement(typeof(PythonList))] 148 XmlElement(typeof(PythonSequence)), 149 XmlElement(typeof(PythonList)), 150 XmlElement(typeof(PythonTuple))] 136 151 public TypeMetadata TypeMetadata; 137 152 [XmlAnyElement(Name = "Description")] … … 150 165 public string PythonType; 151 166 public bool CanBeNone; 167 public string COMIDLType; 168 public bool CanBeIDispatchParameter; 169 public string ArcGISType; 170 public string ArcGISAssembly; 152 171 public bool CanBeArcGISInputParameter; 153 172 public bool CanBeArcGISOutputParameter; 154 public string ArcGISType;155 public string ArcGISAssembly;156 173 157 174 #endregion … … 214 231 } 215 232 216 public class PythonClassOrClassInstance : TypeMetadata233 public class AnyPythonInstance : TypeMetadata 217 234 { 218 235 #region Overridden TypeMetadata members … … 228 245 } 229 246 247 public class PythonClassOrClassInstance : TypeMetadata 248 { 249 #region Overridden TypeMetadata members 250 251 public override System.Type DotNetType { get { throw new NotSupportedException(); } } 252 public override string NameForSerializedXmlValue { get { throw new NotSupportedException(); } } 253 public override object DeserializeValueFromXmlElement(XmlElement element) { throw new NotSupportedException(); } 254 public override IGPDataType GetIGPDataTypeInstance() { throw new NotSupportedException(); } 255 public override IGPValue GetIGPValueInstance(object value) { throw new NotSupportedException(); } 256 public override IGPValue GetIGPValueInstanceForDerivedOutput(Result result) { throw new NotSupportedException(); } 257 258 #endregion 259 } 260 230 261 public class PythonBoolean : TypeMetadata 231 262 { … … 275 306 } 276 307 277 public class Python List: TypeMetadata308 public class PythonSequence : TypeMetadata 278 309 { 279 310 #region Fields deserialized from Metadata.xml 280 311 281 312 [XmlElement("ElementTypeMetadata", typeof(TypeMetadata)), 313 XmlElement(typeof(AnyPythonInstance)), 282 314 XmlElement(typeof(PythonClassInstance)), 283 315 XmlElement(typeof(PythonClassOrClassInstance)), … … 286 318 XmlElement(typeof(PythonInteger)), 287 319 XmlElement(typeof(PythonUnicodeString)), 288 XmlElement(typeof(PythonList))] 320 XmlElement(typeof(PythonSequence)), 321 XmlElement(typeof(PythonList)), 322 XmlElement(typeof(PythonTuple))] 289 323 public TypeMetadata ElementTypeMetadata; 290 324 … … 342 376 #endregion 343 377 } 378 379 public class PythonList : PythonSequence { } 380 381 public class PythonTuple : PythonSequence { } 344 382 345 383 class Program
