root/MGET/Trunk/PythonPackage/src/GeoEco/Dependencies.py

Revision 480, 29.3 kB (checked in by jjr8, 1 month ago)

Merged [465-479] from Jason branch into the Trunk. This will be released as MGET 0.8 alpha 2.

Line 
1 # Dependencies.py - Provides classes that allow other classes in the GeoEco
2 # Python package to declare dependencies on software and hardware.
3 #
4 # Copyright (C) 2007 Jason J. Roberts
5 #
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License (available in the file LICENSE.TXT)
15 # for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20
21 import codecs
22 import os
23 import platform
24 import types
25 import StringIO
26 import sys
27
28 from GeoEco.DynamicDocString import DynamicDocString
29 from GeoEco.Exceptions import GeoEcoError
30 from GeoEco.Internationalization import _
31
32
33 # Exceptions raised when a software or hardware dependency is checked and fails.
34
35
36 class UnsupportedPlatformError(GeoEcoError):
37     __doc__ = DynamicDocString()
38
39
40 class SoftwareNotInstalledError(GeoEcoError):
41     __doc__ = DynamicDocString()
42
43
44 # Classes that represent various types of dependencies.
45
46
47 class Dependency(object):
48     __doc__ = DynamicDocString()
49
50     def GetResultCacheKey(self):
51         return None
52
53     def Initialize(self):
54         raise NotImplementedError(u'Derived classes must override this method.')
55
56
57 class WindowsDependency(Dependency):
58     __doc__ = DynamicDocString()
59
60     def __init__(self, minimumMajorVersion, minimumMinorVersion=None, minimumServicePack=None):
61         self.SetVersion(minimumMajorVersion, minimumMinorVersion, minimumServicePack)
62
63     def SetVersion(self, minimumMajorVersion, minimumMinorVersion=None, minimumServicePack=None):
64         assert isinstance(minimumMajorVersion, types.IntType), u'minimumMajorVersion must be an integer.'
65         assert isinstance(minimumMinorVersion, (types.IntType, types.NoneType)), 'minimumMinorVersion must be an integer, or None.'
66         assert isinstance(minimumServicePack, (types.IntType, types.NoneType)), u'minimumServicePack must be an integer, or None.'
67         assert minimumMajorVersion is not None and minimumMinorVersion is None and minimumServicePack is None or minimumMajorVersion is not None and minimumMinorVersion is not None and minimumServicePack is None or minimumMajorVersion is not None and minimumMinorVersion is not None and minimumServicePack is not None, u'If you specify a minimumMinorVersion you must also specify a minimumMajorVersion. If you specify a minimumServicePack you must also specify a minimumMajorVersion and minimumMinorVersion.'
68         assert minimumMinorVersion is None or minimumMinorVersion >= 0, u'If minimumMinorVersion is not None it must be >= 0.'
69         assert minimumServicePack is None or minimumServicePack >= 0, u'If minimumServicePack is not None it must be >= 0.'
70         assert minimumMajorVersion >= 5, u'GeoEco itself cannot run Windows versions prior to Windows 2000, even if your code will. Please adjust the minimumMajorVersion to 5 or greater.'
71
72         if minimumMinorVersion is None:
73             minimumMinorVersion = 0
74         if minimumServicePack is None:
75             minimumServicePack = 0
76
77         self._MinimumMajorVersion = minimumMajorVersion
78         self._MinimumMinorVersion = minimumMinorVersion
79         self._MinimumServicePack = minimumServicePack
80
81     def _GetMinimumMajorVersion(self):
82         return self._MinimumMajorVersion
83    
84     MinimumMajorVersion = property(_GetMinimumMajorVersion, doc=DynamicDocString())
85
86     def _GetMinimumMinorVersion(self):
87         return self._MinimumMinorVersion
88    
89     MinimumMinorVersion = property(_GetMinimumMinorVersion, doc=DynamicDocString())
90
91     def _GetMinimumServicePack(self):
92         return self._MinimumServicePack
93    
94     MinimumServicePack = property(_GetMinimumServicePack, doc=DynamicDocString())
95
96     def GetResultCacheKey(self):
97         return u'WindowsDependency:' + unicode(self._MinimumMajorVersion) + u',' + unicode(self._MinimumMinorVersion) + u',' + unicode(self._MinimumServicePack)
98
99     def Initialize(self):
100         from GeoEco.Logging import Logger
101         Logger.Debug(_(u'Checking platform dependency: %s or later.') % self.GetProductNameFromVersionNumbers(self.MinimumMajorVersion, self.MinimumMinorVersion, self.MinimumServicePack))
102         if sys.platform.lower() == u'win32':
103             (major, minor, servicePack) = self.GetInstalledVersion()
104             if self.MinimumMajorVersion > major or self.MinimumMajorVersion == major and self.MinimumMinorVersion > minor or self.MinimumMajorVersion == major and self.MinimumMinorVersion == minor and self.MinimumServicePack > servicePack:
105                 Logger.RaiseException(UnsupportedPlatformError(_(u'This function can only execute on a computer running %(required)s or a later version. Python reports that %(installed)s is installed. Please upgrade the operating system.') % {u'required' : self.GetProductNameFromVersionNumbers(self.MinimumMajorVersion, self.MinimumMinorVersion, self.MinimumServicePack), u'installed' : self.GetProductNameFromVersionNumbers(major, minor, servicePack)}))
106         else:
107             Logger.RaiseException(UnsupportedPlatformError(_(u'This function can only execute on a computer running the Microsoft Windows operating system. Python reports that this computer is running the \"%s\" operating system.') % platform.system()))
108
109     _MajorVersion = None
110     _MinorVersion = None
111     _ServicePack = None
112
113     @classmethod
114     def GetInstalledVersion(cls):
115         if WindowsDependency._MajorVersion is not None:
116             return (WindowsDependency._MajorVersion, WindowsDependency._MinorVersion, WindowsDependency._ServicePack)
117
118         (WindowsDependency._MajorVersion, WindowsDependency._MinorVersion, build, plat, text) = sys.getwindowsversion()
119         if text is None:
120             WindowsDependency._ServicePack = 0
121         else:
122             try:
123                 WindowsDependency._ServicePack = int(text.strip('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz \t\r\n.'))
124             except:
125                 WindowsDependency._ServicePack = 0
126
127         from GeoEco.Logging import Logger
128         Logger.Debug(_(u'%s is installed.') % cls.GetProductNameFromVersionNumbers(WindowsDependency._MajorVersion, WindowsDependency._MinorVersion, WindowsDependency._ServicePack))
129
130         return (WindowsDependency._MajorVersion, WindowsDependency._MinorVersion, WindowsDependency._ServicePack)
131
132     @classmethod
133     def GetProductNameFromVersionNumbers(cls, majorVersion, minorVersion, servicePack):
134         osName = None
135         if majorVersion == 5:
136             if minorVersion == 0:
137                 osName = _(u'Microsoft Windows 2000')
138             elif minorVersion == 1:
139                 osName = _(u'Microsoft Windows XP')
140             else:
141                 osName = _(u'Microsoft Windows Server 2003')
142         elif majorVersion == 6:
143             if minorVersion == 0:
144                 osName = _(u'Microsoft Windows Vista')
145             elif minorVersion == 1:
146                 osName = _(u'Microsoft Windows "Blackcomb" Server')
147         if osName is None:
148             osName = _(u'Microsoft Windows version %i.%i') % (majorVersion, minorVersion)
149         if servicePack > 0:
150             osName = _(u'%s Service Pack %i') % (osName, servicePack)
151         return osName
152
153            
154 class PythonDependency(Dependency):
155     __doc__ = DynamicDocString()
156
157     def __init__(self, minimumMajorVersion, minimumMinorVersion=None, minimumPatchVersion=None):
158         self.SetVersion(minimumMajorVersion, minimumMinorVersion, minimumPatchVersion)
159
160     def SetVersion(self, minimumMajorVersion, minimumMinorVersion=None, minimumPatchVersion=None):
161         assert isinstance(minimumMajorVersion, types.IntType), u'minimumMajorVersion must be an integer.'
162         assert isinstance(minimumMinorVersion, (types.IntType, types.NoneType)), 'minimumMinorVersion must be an integer, or None.'
163         assert isinstance(minimumPatchVersion, (types.IntType, types.NoneType)), u'minimumPatchVersion must be an integer, or None.'
164         assert minimumMajorVersion is not None and minimumMinorVersion is None and minimumPatchVersion is None or minimumMajorVersion is not None and minimumMinorVersion is not None and minimumPatchVersion is None or minimumMajorVersion is not None and minimumMinorVersion is not None and minimumPatchVersion is not None, u'If you specify a minimumMinorVersion you must also specify a minimumMajorVersion. If you specify a minimumPatchVersion you must also specify a minimumMajorVersion and minimumMinorVersion.'
165         assert minimumMinorVersion is None or minimumMinorVersion >= 0, u'If minimumMinorVersion is not None it must be >= 0.'
166         assert minimumPatchVersion is None or minimumPatchVersion >= 0, u'If minimumPatchVersion is not None it must be >= 0.'
167         assert minimumMajorVersion >= 3 or minimumMajorVersion >= 2 and minimumMinorVersion is not None and minimumMinorVersion >= 4, u'GeoEco itself cannot run on Python versions prior to 2.4, even if your code will. Please adjust minimumMajorVersion.minimumMajorVersion to 2.4 or greater.'
168
169         if minimumMinorVersion is None:
170             minimumMinorVersion = 0
171         if minimumPatchVersion is None:
172             minimumPatchVersion = 0
173
174         self._MinimumMajorVersion = minimumMajorVersion
175         self._MinimumMinorVersion = minimumMinorVersion
176         self._MinimumPatchVersion = minimumPatchVersion
177
178     def _GetMinimumMajorVersion(self):
179         return self._MinimumMajorVersion
180    
181     MinimumMajorVersion = property(_GetMinimumMajorVersion, doc=DynamicDocString())
182
183     def _GetMinimumMinorVersion(self):
184         return self._MinimumMinorVersion
185    
186     MinimumMinorVersion = property(_GetMinimumMinorVersion, doc=DynamicDocString())
187
188     def _GetMinimumPatchVersion(self):
189         return self._MinimumPatchVersion
190    
191     MinimumPatchVersion = property(_GetMinimumPatchVersion, doc=DynamicDocString())
192
193     def GetResultCacheKey(self):
194         return u'PythonDependency:' + unicode(self._MinimumMajorVersion) + u',' + unicode(self._MinimumMinorVersion) + u',' + unicode(self._MinimumPatchVersion)
195
196     def Initialize(self):
197         from GeoEco.Logging import Logger
198         Logger.Debug(_(u'Checking software dependency: Python version %i.%i.%i or later.') % (self.MinimumMajorVersion, self.MinimumMinorVersion, self.MinimumPatchVersion))
199         (major, minor, patch) = self.GetInstalledVersion()
200         if self.MinimumMajorVersion > major or self.MinimumMajorVersion == major and self.MinimumMinorVersion > minor or self.MinimumMajorVersion == major and self.MinimumMinorVersion == minor and self.MinimumPatchVersion > patch:
201             Logger.RaiseException(SoftwareNotInstalledError(_(u'This function requires Python %i.%i.%i or a later version, but version %i.%i.%i is currently running. Please ensure the required version (or newer) is installed. You may download Python from http://www.python.org/. Also ensure that the GeoEco package for that version of Python is installed (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.MinimumMajorVersion, self.MinimumMinorVersion, self.MinimumPatchVersion, major, minor, patch)))
202
203     _MajorVersion = None
204     _MinorVersion = None
205     _PatchVersion = None
206
207     @classmethod
208     def GetInstalledVersion(cls):
209         if PythonDependency._MajorVersion is not None:
210             return (PythonDependency._MajorVersion, PythonDependency._MinorVersion, PythonDependency._PatchVersion)
211
212         v = platform.python_version_tuple()
213         PythonDependency._MajorVersion = cls._ParseVersionNumber(v[0])
214         PythonDependency._MinorVersion = cls._ParseVersionNumber(v[1])
215         PythonDependency._PatchVersion = cls._ParseVersionNumber(v[2])
216
217         from GeoEco.Logging import Logger
218         Logger.Debug(_(u'Python %i.%i.%i is running.') % (PythonDependency._MajorVersion, PythonDependency._MinorVersion, PythonDependency._PatchVersion))
219
220         return (PythonDependency._MajorVersion, PythonDependency._MinorVersion, PythonDependency._PatchVersion)
221
222     @classmethod
223     def _ParseVersionNumber(cls, s):
224         assert isinstance(s, (types.IntType, basestring))
225         if isinstance(s, types.IntType):
226             return s
227         s = s[:len(s) - len(s.lstrip('0123456789'))]
228         if len(s) <= 0:
229             return 0
230         return int(s)
231
232
233 class PythonModuleDependency(Dependency):
234     __doc__ = DynamicDocString()
235
236     def __init__(self, importName, displayName=None, cheeseShopName=None, alternateURL=None, additionalMessage=None, logStdout=False):
237         assert isinstance(importName, types.StringType), u'importName must be a non-Unicode string'
238         assert isinstance(displayName, (types.NoneType, types.UnicodeType)), u'displayName must be a Unicode string, or None'
239         assert isinstance(cheeseShopName, (types.NoneType, types.UnicodeType)), u'displayName must be a Unicode string, or None'
240         assert isinstance(alternateURL, (types.NoneType, types.UnicodeType)), u'displayName must be a Unicode string, or None'
241         assert isinstance(additionalMessage, (types.NoneType, types.UnicodeType)), u'additionalMessage must be a Unicode string, or None'
242         assert isinstance(logStdout, types.BooleanType), u'logStdout must be a boolean'
243
244         self.ImportName = importName
245         self.DisplayName = displayName
246         self.CheeseShopName = cheeseShopName
247         self.AlternateURL = alternateURL
248         self.AdditionalMessage = additionalMessage
249         self.LogStdout = logStdout
250
251     _InstalledModules = {}       
252
253     def GetResultCacheKey(self):
254         return u'PythonModuleDependency:' + self.ImportName
255
256     def Initialize(self):
257         from GeoEco.Logging import Logger
258         Logger.Debug(_(u'Checking software dependency: Python module: %s') % self.ImportName)
259
260         # If we already know that it is installed, return immediately.
261         # (Question: is this necessary now that
262
263         if PythonModuleDependency._InstalledModules.has_key(self.ImportName):
264             return
265
266         # If requested, start capturing stdout so we can log any messages that
267         # are printed when we try to import the module. At the time this code
268         # was written, I only knew of one module (rpy) that printed messages to
269         # stdout during module importation.
270
271         if self.LogStdout:
272             oldStdout = sys.stdout
273             sys.stdout = StringIO.StringIO()
274
275         # Import the module and, if requested, log any messages that are printed
276         # to stdout.
277         
278         try:
279             try:
280                 __import__(self.ImportName)
281             finally:
282                 if self.LogStdout:
283                     messages = []
284                     try:
285                         messages = sys.stdout.getvalue().split('\n')
286                     except:
287                         pass
288                     sys.stdout = oldStdout
289                     try:
290                         for message in messages:
291                             if len(message.strip()) > 0:
292                                 Logger.Debug(_(u'Python %(module)s module: %(message)s') % {u'module' : self.ImportName, u'message' : message.strip()})
293                     except:
294                         pass
295         except Exception, e:
296             if self.DisplayName is None:
297                 message = _(u'This function requires the Python %s module. Please verify that it is properly installed for the running version of Python (%s.%s). If it is Python-version-specific, ensure you installed the version of it for this Python version.') % (self.ImportName, unicode(platform.python_version_tuple()[0]), unicode(platform.python_version_tuple()[1]))
298             else:
299                 message = _(u'This function requires the %s. Please verify that it is properly installed for the running version of Python (%s.%s). If it is Python-version-specific, ensure you installed the version of it for this Python version.') % (self.DisplayName, unicode(platform.python_version_tuple()[0]), unicode(platform.python_version_tuple()[1]))
300             if self.CheeseShopName is not None and self.AlternateURL is None:
301                 message = _(u'%s It may be available at http://www.python.org/pypi/%s.') % (message, self.CheeseShopName)
302             elif self.CheeseShopName is None and self.AlternateURL is not None:
303                 message = _(u'%s It may be available at %s.') % (message, self.AlternateURL)
304             elif self.CheeseShopName is not None and self.AlternateURL is not None:
305                 message = _(u'%s It may be available at http://www.python.org/pypi/%s or %s.') % (message, self.CheeseShopName, self.AlternateURL)
306             if self.AdditionalMessage is not None:
307                 message = _(u'%s %s.') % (message, self.AdditionalMessage)
308             message = _(u'%s Debugging information: the Python statement "__import__(\'%s\')" raised %s: %s"') % (message, self.ImportName, e.__class__.__name__, unicode(e))
309             Logger.RaiseException(SoftwareNotInstalledError(message))
310
311         Logger.Debug(_(u'Imported Python module %s successfully.') % self.ImportName)
312         PythonModuleDependency._InstalledModules[self.ImportName] = True           
313
314
315 class PythonAggregatedModuleDependency(Dependency):
316     __doc__ = DynamicDocString()
317
318     def __init__(self, importName):
319         assert isinstance(importName, types.StringType), u'importName must be a non-Unicode string'
320         self.ImportName = importName
321
322     def GetResultCacheKey(self):
323         return u'PythonAggregatedModuleDependency:' + self.ImportName
324
325     def Initialize(self):
326         from GeoEco.Logging import Logger
327         Logger.Debug(_(u'Checking software dependency: aggregated Python module: %s') % self.ImportName)
328
329         # If the module has already been imported, return immediately.
330
331         if sys.modules.has_key(self.ImportName):
332             return
333
334         # Import the module.
335
336         import GeoEco
337         aggregatedModulesDir = os.path.join(os.path.dirname(sys.modules[u'GeoEco'].__file__), 'AggregatedModules')
338
339         try:
340             try:
341                 __import__(self.ImportName)
342             except Exception, e:
343                 if aggregatedModulesDir in sys.path:
344                     raise
345                 Logger.Debug(_(u'Failed to import Python module %s using the unaltered sys.path. The Python statement "__import__(\'%s\')" raised %s: %s"') % (self.ImportName, self.ImportName, e.__class__.__name__, unicode(e)))
346             else:
347                 Logger.Debug(_(u'Imported Python module %s from directory %s.') % (self.ImportName, os.path.dirname(sys.modules[self.ImportName].__file__)))
348                 return
349             sys.path.append(aggregatedModulesDir)
350             Logger.Debug(_(u'Appended %s to sys.path.') % aggregatedModulesDir)
351             __import__(self.ImportName)
352         except Exception, e:
353             Logger.RaiseException(SoftwareNotInstalledError(_(u'This function requires the Python %s module for the running version of Python (%s.%s). GeoEco includes a copy of this module but was unable to import it. This should never happen. Please contact the GeoEco development team for assistance. Debugging information: the Python statement "__import__(\'%s\')" raised %s: %s"') % (self.ImportName, unicode(platform.python_version_tuple()[0]), unicode(platform.python_version_tuple()[1]), self.ImportName, e.__class__.__name__, unicode(e))))
354         Logger.Debug(_(u'Imported Python module %s from directory %s.') % (self.ImportName, os.path.dirname(sys.modules[self.ImportName].__file__)))
355
356
357 # Helper functions for dealing with certain kinds of dependencies.
358
359
360 _GDALModuleHandle = None
361 _ProjModuleHandle = None
362
363 def ImportGDALModule(name):
364
365     # If the specified GDAL module has already been loaded, just
366     # return it.
367
368     if not name.startswith('GeoEco.AssimilatedModules.'):
369         name = 'GeoEco.AssimilatedModules.' + name
370     if sys.modules.has_key(name):
371         return sys.modules[name]
372
373     from GeoEco.Logging import Logger
374
375     Logger.Debug(_(u'The module %s has not been loaded yet.') % name)
376
377     # Determine the paths to our private copies of the GDAL data and
378     # bin directories.
379
380     import GeoEco
381
382     geoEcoBinDir = os.path.join(os.path.dirname(sys.modules[u'GeoEco'].__file__), 'Bin', sys.platform.lower())
383     gdalDataDir = os.path.join(geoEcoBinDir, 'GDAL', 'data')
384     gdalBinDir = os.path.join(geoEcoBinDir, 'GDAL', 'bin')
385
386     # Set the GDAL_DATA environment variable.
387
388     SetGDALDataEnvVar()
389
390     # Import the module.
391     #
392     # For this to succeed, the module has to be able to load the GDAL
393     # library (e.g. gdal16.dll on Windows). This usual technique for
394     # this involves adding the GDAL bin directory to the PATH
395     # environment variable prior to importing the module. But this
396     # seems to interfere with ArcGIS in some scenarios, at least when
397     # running tests using nosetests. Specifically, I discovered that
398     # when I set the PATH variable, subsequent calls to
399     # gp.CreatePersonalGDB_managment would crash the Python process.
400     # It did not matter what I set PATH to--I could even set it to its
401     # current value--that gp call would always crash when running
402     # under nosetests. To work around this, on Windows only,
403     # explicitly load the GDAL library rather than modifying PATH.
404
405     try:
406         if sys.platform == 'win32':
407             import win32api
408
409             # Load the GDAL DLL, if we have not done it already.
410
411             if globals()['_GDALModuleHandle'] is None:
412
413                 # First call Win32 SetDllDirectory so that when we call
414                 # LoadLibrary, it can find the DLLs that the GDAL DLL
415                 # links to.
416                 
417                 d = PythonModuleDependency(importName='win32api', displayName=_(u'Python for Windows extensions (pywin32)'), alternateURL=u'http://sourceforge.net/projects/pywin32')
418                 d.Initialize()
419                 if not hasattr(win32api, 'GetDllDirectory'):
420                     Logger.RaiseException(SoftwareNotInstalledError(_(u'This function requires the Python for Windows extensions (pywin32) build 211 or later. An earlier build is installed. Please uninstall your current version using Add/Remove Programs in the Control Panel (or Programs and Features, if you\'re running Windows Vista). Then download and install build 211 or later from http://sourceforge.net/projects/pywin32')))
421                 oldDllDirectory = None
422                 try:
423                     oldDllDirectory = win32api.GetDllDirectory()        # If no DLL directory has been set, this will throw an exception, at least with pywin32 build 212.
424                 except:
425                     pass
426                 win32api.SetDllDirectory(gdalBinDir)
427                 if oldDllDirectory is not None:
428                     Logger.Debug(_(u'Set the Win32 DLL directory to "%(new)s". (The old value was "%(old)s".)') % {u'new': gdalBinDir, u'old': oldDllDirectory})
429                 else:
430                     Logger.Debug(_(u'Set the Win32 DLL directory to "%(new)s". (The old value was NULL.)') % {u'new': gdalBinDir})
431
432                 # Now call LoadLibrary.
433
434                 try:
435                     gdalDLLPath = os.path.join(gdalBinDir, 'gdal16.dll')
436                     try:
437                         globals()['_GDALModuleHandle'] = win32api.LoadLibrary(gdalDLLPath)
438                     except Exception, e:
439                         Logger.RaiseException(ImportError(_(u'The %(name)s Python module could not be imported because win32api.LoadLibrary(r\'%(path)s\') raised %(e)s: %(msg)s.') % {u'name': name, u'path': gdalDLLPath, u'e': e.__class__.__name__, u'msg': unicode(e)}))
440                     Logger.Debug(_(u'Explicitly loaded "%s" by calling Win32 LoadLibrary.') % gdalDLLPath)
441
442                 # Reset the DLL directory to what it was before.
443
444                 finally:
445                     try:
446                         win32api.SetDllDirectory(oldDllDirectory)
447                     except Exception, e:
448                         Logger.Warning(_(u'Failed to reset the Win32 DLL directory to the previous value. win32api.SetDllDirectory(r\'%(path)s\') raised %(e)s: %(msg)s.') % {u'path': oldDllDirectory, u'e': e.__class__.__name__, u'msg': unicode(e)})
449                     if oldDllDirectory is not None:
450                         Logger.Debug(_(u'Reset the Win32 DLL directory to "%(old)s".') % {u'old': oldDllDirectory})
451                     else:
452                         Logger.Debug(_(u'Reset the Win32 DLL directory to NULL.'))
453
454             # Load the PROJ.4 DLL, if we have not done it already.
455             # This DLL is required by certain parts of GDAL, such as
456             # the osr.CoordinateTransformation class.
457
458             if globals()['_ProjModuleHandle'] is None:
459                 projDLLPath = os.path.join(geoEcoBinDir, 'proj', 'bin', 'proj.dll')
460                 try:
461                     globals()['_ProjModuleHandle'] = win32api.LoadLibrary(projDLLPath)
462                 except Exception, e:
463                     Logger.RaiseException(ImportError(_(u'The %(name)s Python module could not be imported because win32api.LoadLibrary(r\'%(path)s\') raised %(e)s: %(msg)s.') % {u'name': name, u'path': projDLLPath, u'e': e.__class__.__name__, u'msg': unicode(e)}))
464                 Logger.Debug(_(u'Explicitly loaded "%s" by calling Win32 LoadLibrary.') % projDLLPath)
465                    
466             # Import the module.
467
468             __import__(name)
469             Logger.Debug(_(u'Imported the %s module.') % name)
470
471         else:
472             if os.environ['PATH'].find(gdalBinDir) < 0:
473                 oldPath = os.environ['PATH']
474                 os.environ['PATH'] = gdalBinDir + ';' + os.environ['PATH']
475                 Logger.Debug(_(u'Prepended the directory "%s" to the PATH environment variable.') % gdalBinDir)
476                 __import__(name)
477                 Logger.Debug(_(u'Imported the %s module.') % name)
478                 os.environ['PATH'] = oldPath
479                 Logger.Debug(_(u'Removed the directory "%s" from the PATH environment variable.') % gdalBinDir)
480
481     # Reset the GDAL_DATA environment variable.
482
483     finally:
484         try:
485             ResetGDALDataEnvVar()
486         except:
487             Logger.LogExceptionAsWarning()
488
489     # If this is the osgeo.gdal module, call UseExceptions() so that
490     # GDAL will raise exceptions rather than printing error messages.
491
492     if name == 'GeoEco.AssimilatedModules.osgeo.gdal':
493         sys.modules[name].UseExceptions()
494
495     # Return the loaded module.
496
497     return sys.modules[name]
498
499 _GDALDataEnvVarSetCount = 0
500 _OldGDALDataEnvVar = None
501 _OldProjLibEnvVar = None
502
503 def SetGDALDataEnvVar():
504     if globals()['_GDALDataEnvVarSetCount'] > 0:
505         globals()['_GDALDataEnvVarSetCount'] += 1
506     else:
507         import GeoEco
508         geoEcoBinDir = os.path.join(os.path.dirname(sys.modules[u'GeoEco'].__file__), 'Bin', sys.platform.lower())
509         gdalDataDir = os.path.join(geoEcoBinDir, 'GDAL', 'data')
510         projLibDir = os.path.join(geoEcoBinDir, 'proj', 'nad')
511        
512         globals()['_OldGDALDataEnvVar'] = None
513         if os.environ.has_key('GDAL_DATA'):
514             globals()['_OldGDALDataEnvVar'] = os.environ['GDAL_DATA']
515         os.environ['GDAL_DATA'] = gdalDataDir
516        
517         globals()['_OldProjLibEnvVar'] = None
518         if os.environ.has_key('PROJ_LIB'):
519             globals()['_OldProjLibEnvVar'] = os.environ['PROJ_LIB']
520         os.environ['PROJ_LIB'] = projLibDir
521
522         globals()['_GDALDataEnvVarSetCount'] = 1
523
524 def ResetGDALDataEnvVar():
525     from GeoEco.Logging import Logger
526     if globals()['_GDALDataEnvVarSetCount'] == 0:
527         Logger.RaiseException(RuntimeError(_(u'Programming error in this tool. ResetGDALDataEnvVar called when _GDALDataEnvVarSetCount is 0. Please contact the author of this tool for assistance.')))
528     globals()['_GDALDataEnvVarSetCount'] -= 1
529
530     if globals()['_GDALDataEnvVarSetCount'] == 0:
531         if globals()['_OldGDALDataEnvVar'] is not None:
532             os.environ['GDAL_DATA'] = globals()['_OldGDALDataEnvVar']
533         else:
534             del os.environ['GDAL_DATA']
535
536         if globals()['_OldProjLibEnvVar'] is not None:
537             os.environ['PROJ_LIB'] = globals()['_OldProjLibEnvVar']
538         else:
539             del os.environ['PROJ_LIB']
540
541
542 ###############################################################################
543 # Names exported by this module
544 ###############################################################################
545
546 __all__ = ['UnsupportedPlatformError',
547            'SoftwareNotInstalledError',
548            'Dependency',
549            'WindowsDependency',
550            'PythonDependency',
551            'PythonModuleDependency',
552            'PythonAggregatedModuleDependency',
553            'ImportGDALModule',
554            'SetGDALDataEnvVar',
555            'ResetGDALDataEnvVar']
Note: See TracBrowser for help on using the browser.